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