1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package android.backup.cts;
18 
19 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
20 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
21 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
22 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
23 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
24 
25 import static androidx.test.InstrumentationRegistry.getInstrumentation;
26 
27 import static org.testng.Assert.expectThrows;
28 
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.pm.ApplicationInfo;
32 import android.os.IBinder;
33 import android.platform.test.annotations.AppModeFull;
34 
35 import java.io.IOException;
36 import java.lang.reflect.Method;
37 import java.util.Scanner;
38 
39 @AppModeFull
40 public class AgentBindingTest extends BaseBackupCtsTest {
41     private static final String FULL_BACKUP_PACKAGE_NAME = "android.backup.app";
42     private static final String KEY_VALUE_BACKUP_PACKAGE_NAME = "android.backup.kvapp";
43     private static final ComponentName FULL_BACKUP_AGENT_NAME = ComponentName.createRelative(
44             FULL_BACKUP_PACKAGE_NAME, ".FullBackupBackupAgent");
45     private static final ComponentName KEY_VALUE_BACKUP_AGENT_NAME = ComponentName.createRelative(
46             KEY_VALUE_BACKUP_PACKAGE_NAME, "android.backup.app.KeyValueBackupAgent");
47     private static final int LOCAL_TRANSPORT_CONFORMING_FILE_SIZE = 5 * 1024;
48 
49     private Context mContext;
50 
51     // Save the states before running tests. Restore them after tests finished.
52     private int mFullBackupAgentEnabledState;
53     private int mKeyValueBackupAgentEnabledState;
54 
55     @Override
setUp()56     protected void setUp() throws Exception {
57         super.setUp();
58         mContext = getInstrumentation().getTargetContext();
59         mFullBackupAgentEnabledState = mContext.getPackageManager().getComponentEnabledSetting(
60                 FULL_BACKUP_AGENT_NAME);
61         mKeyValueBackupAgentEnabledState = mContext.getPackageManager().getComponentEnabledSetting(
62                 KEY_VALUE_BACKUP_AGENT_NAME);
63     }
64 
65     @Override
tearDown()66     protected void tearDown() throws Exception {
67         super.tearDown();
68         setComponentEnabledSetting(FULL_BACKUP_AGENT_NAME, mFullBackupAgentEnabledState);
69         setComponentEnabledSetting(KEY_VALUE_BACKUP_AGENT_NAME, mKeyValueBackupAgentEnabledState);
70     }
71 
testUnbindBackupAgent_isNotCallableFromCts()72     public void testUnbindBackupAgent_isNotCallableFromCts() throws Exception {
73         if (!isBackupSupported()) {
74             return;
75         }
76         expectThrows(Exception.class, () -> unbindBackupAgent(mContext.getApplicationInfo()));
77     }
78 
testBindBackupAgent_isNotCallableFromCts()79     public void testBindBackupAgent_isNotCallableFromCts() throws Exception {
80         if (!isBackupSupported()) {
81             return;
82         }
83         expectThrows(Exception.class, () -> bindBackupAgent(mContext.getPackageName(), 0, 0));
84     }
85 
testFullBackupAgentComponentDisabled()86     public void testFullBackupAgentComponentDisabled() throws Exception {
87         if (!isBackupSupported()) {
88             return;
89         }
90         setComponentEnabledSetting(FULL_BACKUP_AGENT_NAME, COMPONENT_ENABLED_STATE_DISABLED);
91         // Make sure there's something to backup
92         createTestFileOfSize(FULL_BACKUP_PACKAGE_NAME, LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
93 
94         runBackupAndAssertAgentError(FULL_BACKUP_PACKAGE_NAME);
95     }
96 
testKeyValueBackupAgentComponentDisabled()97     public void testKeyValueBackupAgentComponentDisabled() throws Exception {
98         if (!isBackupSupported()) {
99             return;
100         }
101         setComponentEnabledSetting(KEY_VALUE_BACKUP_AGENT_NAME, COMPONENT_ENABLED_STATE_DISABLED);
102         // Make sure there's something to backup
103         createTestFileOfSize(KEY_VALUE_BACKUP_PACKAGE_NAME, LOCAL_TRANSPORT_CONFORMING_FILE_SIZE);
104 
105         runBackupAndAssertAgentError(KEY_VALUE_BACKUP_PACKAGE_NAME);
106     }
107 
setComponentEnabledSetting(ComponentName componentName, int enabledState)108     private void setComponentEnabledSetting(ComponentName componentName, int enabledState)
109             throws IOException {
110         final StringBuilder cmd = new StringBuilder("pm ");
111         switch (enabledState) {
112             case COMPONENT_ENABLED_STATE_DEFAULT:
113                 cmd.append("default-state ");
114                 break;
115             case COMPONENT_ENABLED_STATE_ENABLED:
116                 cmd.append("enable ");
117                 break;
118             case COMPONENT_ENABLED_STATE_DISABLED:
119                 cmd.append("disable ");
120                 break;
121             case COMPONENT_ENABLED_STATE_DISABLED_USER:
122                 cmd.append("disable-user ");
123                 break;
124             case COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
125                 cmd.append("disable-until-used ");
126                 break;
127             default:
128                 throw new IllegalArgumentException("Invalid enabled state:" + enabledState);
129         }
130         cmd.append("--user cur ").append(componentName.flattenToString());
131         getBackupUtils().executeShellCommandSync(cmd.toString());
132     }
133 
134     /**
135      * Parses the output of "bmgr backupnow" command and checks an agent error during
136      * backup / restore.
137      */
runBackupAndAssertAgentError(String packageName)138     private void runBackupAndAssertAgentError(String packageName) throws IOException {
139         Scanner in = new Scanner(getBackupUtils().getBackupNowOutput(packageName));
140         boolean found = false;
141         while (in.hasNextLine()) {
142             String line = in.nextLine();
143 
144             if (line.contains(packageName)) {
145                 String result = line.split(":")[1].trim();
146                 if ("Agent error".equals(result)) {
147                     found = true;
148                     break;
149                 }
150             }
151         }
152         in.close();
153         assertTrue("Didn't find \'Agent error\' in the output", found);
154     }
155 
unbindBackupAgent(ApplicationInfo applicationInfo)156     private static void unbindBackupAgent(ApplicationInfo applicationInfo) throws Exception {
157         callActivityManagerMethod(
158                 "unbindBackupAgent",
159                 new Class<?>[] {ApplicationInfo.class},
160                 new Object[] {applicationInfo});
161     }
162 
bindBackupAgent(String packageName, int backupRestoreMode, int userId)163     private static void bindBackupAgent(String packageName, int backupRestoreMode, int userId)
164             throws Exception {
165         callActivityManagerMethod(
166                 "bindBackupAgent",
167                 new Class<?>[] {String.class, int.class, int.class},
168                 new Object[] {packageName, backupRestoreMode, userId});
169     }
170 
callActivityManagerMethod( String methodName, Class<?>[] types, Object[] args)171     private static void callActivityManagerMethod(
172             String methodName, Class<?>[] types, Object[] args) throws Exception {
173         Class<?> activityManagerClass = Class.forName("android.app.IActivityManager");
174         Object activityManager = getActivityManager();
175         Method bindBackupAgentMethod = activityManagerClass.getMethod(methodName, types);
176         bindBackupAgentMethod.invoke(activityManager, args);
177     }
178 
getActivityManager()179     private static Object getActivityManager() throws Exception {
180         Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
181         Class<?> stubClass = Class.forName("android.app.IActivityManager$Stub");
182         Method asInterfaceMethod = stubClass.getMethod("asInterface", IBinder.class);
183         Method getServiceMethod = serviceManagerClass.getMethod("getService", String.class);
184         return asInterfaceMethod.invoke(
185                 null, (IBinder) getServiceMethod.invoke(serviceManagerClass, "activity"));
186     }
187 }
188