1 /* 2 * Copyright (C) 2017 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 package android.appsecurity.cts; 17 18 import static org.junit.Assert.assertFalse; 19 import static org.junit.Assert.assertTrue; 20 21 import android.platform.test.annotations.AppModeFull; 22 import android.platform.test.annotations.Presubmit; 23 24 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 25 26 import org.junit.After; 27 import org.junit.Before; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 31 import java.util.HashMap; 32 33 @Presubmit 34 @RunWith(DeviceJUnit4ClassRunner.class) 35 @AppModeFull(reason = "Overlays cannot be instant apps") 36 public class OverlayHostTest extends BaseAppSecurityTest { 37 38 // Test applications 39 private static final String TARGET_OVERLAYABLE_APK = "CtsOverlayTarget.apk"; 40 private static final String TARGET_NO_OVERLAYABLE_APK = "CtsOverlayTargetNoOverlayable.apk"; 41 42 private static final String OVERLAY_ANDROID_APK = "CtsOverlayAndroid.apk"; 43 private static final String OVERLAY_ALL_APK = "CtsOverlayPolicyAll.apk"; 44 private static final String OVERLAY_ALL_HAS_CODE_APK = "CtsOverlayPolicyAllHasCode.apk"; 45 private static final String OVERLAY_ALL_NO_NAME_APK = "CtsOverlayPolicyAllNoName.apk"; 46 private static final String OVERLAY_ALL_NO_NAME_DIFFERENT_CERT_APK = 47 "CtsOverlayPolicyAllNoNameDifferentCert.apk"; 48 private static final String OVERLAY_ALL_PIE_APK = "CtsOverlayPolicyAllPie.apk"; 49 private static final String OVERLAY_PRODUCT_APK = "CtsOverlayPolicyProduct.apk"; 50 private static final String OVERLAY_SYSTEM_APK = "CtsOverlayPolicySystem.apk"; 51 private static final String OVERLAY_VENDOR_APK = "CtsOverlayPolicyVendor.apk"; 52 private static final String OVERLAY_DIFFERENT_SIGNATURE_APK = "CtsOverlayPolicySignatureDifferent.apk"; 53 54 // Test application package names 55 private static final String TARGET_PACKAGE = "com.android.cts.overlay.target"; 56 private static final String OVERLAY_ANDROID_PACKAGE = "com.android.cts.overlay.android"; 57 private static final String OVERLAY_ALL_PACKAGE = "com.android.cts.overlay.all"; 58 private static final String OVERLAY_PRODUCT_PACKAGE = "com.android.cts.overlay.policy.product"; 59 private static final String OVERLAY_SYSTEM_PACKAGE = "com.android.cts.overlay.policy.system"; 60 private static final String OVERLAY_VENDOR_PACKAGE = "com.android.cts.overlay.policy.vendor"; 61 private static final String OVERLAY_DIFFERENT_SIGNATURE_PACKAGE = "com.android.cts.overlay.policy.signature"; 62 63 // Test application test class 64 private static final String TEST_APP_APK = "CtsOverlayApp.apk"; 65 private static final String TEST_APP_PACKAGE = "com.android.cts.overlay.app"; 66 private static final String TEST_APP_CLASS = "com.android.cts.overlay.app.OverlayableTest"; 67 private static final String OVERLAY_TARGET_TEST_APP_CLASS = 68 "com.android.cts.overlay.target.OverlayTargetTest"; 69 70 // Overlay states 71 private static final String STATE_DISABLED = "STATE_DISABLED"; 72 private static final String STATE_ENABLED = "STATE_ENABLED"; 73 private static final String STATE_NO_IDMAP = "STATE_NO_IDMAP"; 74 75 // test arguments 76 private static final String PARAM_START_SERVICE = "start_service"; 77 78 private static final long OVERLAY_WAIT_TIMEOUT = 10000; // 10 seconds 79 80 @Before setUp()81 public void setUp() throws Exception { 82 new InstallMultiple().addFile(TEST_APP_APK).run(); 83 } 84 85 @After tearDown()86 public void tearDown() throws Exception { 87 getDevice().uninstallPackage(TEST_APP_PACKAGE); 88 } 89 getStateForOverlay(String overlayPackage)90 private String getStateForOverlay(String overlayPackage) throws Exception { 91 String result = getDevice().executeShellCommand("cmd overlay dump"); 92 93 String overlayPackageForCurrentUser = overlayPackage + ":" + getDevice().getCurrentUser(); 94 95 int startIndex = result.indexOf(overlayPackageForCurrentUser); 96 if (startIndex < 0) { 97 return null; 98 } 99 100 int endIndex = result.indexOf('}', startIndex); 101 assertTrue(endIndex > startIndex); 102 103 int stateIndex = result.indexOf("mState", startIndex); 104 assertTrue(startIndex < stateIndex && stateIndex < endIndex); 105 106 int colonIndex = result.indexOf(':', stateIndex); 107 assertTrue(stateIndex < colonIndex && colonIndex < endIndex); 108 109 int endLineIndex = result.indexOf('\n', colonIndex); 110 assertTrue(colonIndex < endLineIndex && endLineIndex < endIndex); 111 return result.substring(colonIndex + 2, endLineIndex); 112 } 113 114 private void waitForOverlayState(String overlayPackage, String state) throws Exception { 115 boolean overlayFound = false; 116 long startTime = System.currentTimeMillis(); 117 118 while (!overlayFound && (System.currentTimeMillis() - startTime < OVERLAY_WAIT_TIMEOUT)) { 119 String result = getStateForOverlay(overlayPackage); 120 overlayFound = state.equals(result); 121 } 122 123 assertTrue(overlayFound); 124 } 125 126 private void assertFailToGenerateIdmap(String overlayApk, String overlayPackage) 127 throws Exception { 128 try { 129 getDevice().uninstallPackage(TARGET_PACKAGE); 130 getDevice().uninstallPackage(overlayPackage); 131 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 132 assertFalse(getDevice().getInstalledPackageNames().contains(overlayPackage)); 133 134 new InstallMultiple().addFile(TARGET_OVERLAYABLE_APK).run(); 135 new InstallMultiple().addFile(overlayApk).run(); 136 137 waitForOverlayState(overlayPackage, STATE_NO_IDMAP); 138 getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage); 139 waitForOverlayState(overlayPackage, STATE_NO_IDMAP); 140 } finally { 141 getDevice().uninstallPackage(TARGET_PACKAGE); 142 getDevice().uninstallPackage(overlayPackage); 143 } 144 } 145 146 private void runOverlayDeviceTest(String targetApk, String overlayApk, String overlayPackage, 147 String testMethod) 148 throws Exception { 149 try { 150 getDevice().uninstallPackage(TARGET_PACKAGE); 151 getDevice().uninstallPackage(overlayPackage); 152 assertFalse(getDevice().getInstalledPackageNames().contains(TARGET_PACKAGE)); 153 assertFalse(getDevice().getInstalledPackageNames().contains(overlayPackage)); 154 155 new InstallMultiple().addFile(overlayApk).run(); 156 new InstallMultiple().addFile(targetApk).run(); 157 158 waitForOverlayState(overlayPackage, STATE_DISABLED); 159 getDevice().executeShellCommand("cmd overlay enable --user current " + overlayPackage); 160 waitForOverlayState(overlayPackage, STATE_ENABLED); 161 162 runDeviceTests(TEST_APP_PACKAGE, TEST_APP_CLASS, testMethod, false /* instant */); 163 } finally { 164 getDevice().uninstallPackage(TARGET_PACKAGE); 165 getDevice().uninstallPackage(overlayPackage); 166 } 167 } 168 169 private void runDeviceTests(String packageName, String testClassName, String testMethodName, 170 HashMap<String, String> testArgs) throws Exception { 171 Utils.runDeviceTestsAsCurrentUser(getDevice(), packageName, testClassName, testMethodName, 172 testArgs); 173 } 174 175 /** 176 * Overlays that target android and are not signed with the platform signature must not be 177 * installed successfully. 178 */ 179 @Test 180 public void testCannotInstallTargetAndroidNotPlatformSigned() throws Exception { 181 try { 182 getDevice().uninstallPackage(OVERLAY_ANDROID_PACKAGE); 183 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ANDROID_PACKAGE)); 184 185 // Try to install the overlay, but expect an error. 186 new InstallMultiple().addFile(OVERLAY_ANDROID_APK).runExpectingFailure(); 187 188 // The install should have failed. 189 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ANDROID_PACKAGE)); 190 191 // The package of the installed overlay should not appear in the overlay manager list. 192 assertFalse(getDevice().executeShellCommand("cmd overlay list --user current ") 193 .contains(" " + OVERLAY_ANDROID_PACKAGE + "\n")); 194 } finally { 195 getDevice().uninstallPackage(OVERLAY_ANDROID_PACKAGE); 196 } 197 } 198 199 /** 200 * Overlays that target a pre-Q sdk and that are not signed with the platform signature must not 201 * be installed. 202 **/ 203 @Test 204 public void testCannotInstallPieOverlayNotPlatformSigned() throws Exception { 205 try { 206 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 207 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 208 209 // Try to install the overlay, but expect an error. 210 new InstallMultiple().addFile(OVERLAY_ALL_PIE_APK).runExpectingFailure(); 211 212 // The install should have failed. 213 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 214 215 // The package of the installed overlay should not appear in the overlay manager list. 216 assertFalse(getDevice().executeShellCommand("cmd overlay list") 217 .contains(" " + OVERLAY_ALL_PACKAGE + "\n")); 218 } finally { 219 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 220 } 221 } 222 223 /** 224 * Overlays that target Q or higher, that do not specify an android:targetName, and that are 225 * not signed with the same signature as the target package must not be installed. 226 **/ 227 @Test 228 public void testCannotInstallDifferentSignaturesNoName() throws Exception { 229 try { 230 getDevice().uninstallPackage(TARGET_PACKAGE); 231 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 232 assertFalse(getDevice().getInstalledPackageNames().contains(TARGET_PACKAGE)); 233 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 234 235 // Try to install the overlay, but expect an error. 236 new InstallMultiple().addFile(TARGET_NO_OVERLAYABLE_APK).run(); 237 new InstallMultiple().addFile( 238 OVERLAY_ALL_NO_NAME_DIFFERENT_CERT_APK).runExpectingFailure(); 239 240 // The install should have failed. 241 assertFalse(getDevice().getInstalledPackageNames().contains(OVERLAY_ALL_PACKAGE)); 242 243 // The package of the installed overlay should not appear in the overlay manager list. 244 assertFalse(getDevice().executeShellCommand("cmd overlay list --user current") 245 .contains(" " + OVERLAY_ALL_PACKAGE + "\n")); 246 } finally { 247 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 248 getDevice().uninstallPackage(TARGET_PACKAGE); 249 } 250 } 251 252 /** 253 * Overlays that target Q or higher, that do not specify an android:targetName, and are 254 * installed before the target must not be allowed to successfully generate an idmap if the 255 * overlay is not signed with the same signature as the target package. 256 **/ 257 @Test 258 public void testFailIdmapDifferentSignaturesNoName() throws Exception { 259 assertFailToGenerateIdmap(OVERLAY_ALL_NO_NAME_APK, OVERLAY_ALL_PACKAGE); 260 } 261 262 /** 263 * Overlays that target Q or higher, that do not specify an android:targetName, and are 264 * installed before the target must be allowed to successfully generate an idmap if the 265 * overlay is signed with the same signature as the target package. 266 **/ 267 @Test 268 public void testSameSignatureNoOverlayableSucceeds() throws Exception { 269 String testMethod = "testSameSignatureNoOverlayableSucceeds"; 270 runOverlayDeviceTest(TARGET_NO_OVERLAYABLE_APK, OVERLAY_ALL_NO_NAME_APK, 271 OVERLAY_ALL_PACKAGE, testMethod); 272 } 273 274 /** 275 * Overlays installed on the data partition may only overlay resources defined under the public 276 * and signature policies if the overlay is signed with the same signature as the target. 277 */ 278 @Test 279 public void testOverlayPolicyAll() throws Exception { 280 String testMethod = "testOverlayPolicyAll"; 281 runOverlayDeviceTest(TARGET_OVERLAYABLE_APK, OVERLAY_ALL_APK, OVERLAY_ALL_PACKAGE, 282 testMethod); 283 } 284 285 @Test 286 public void testOverlayCodeNotLoaded() throws Exception { 287 String testMethod = "testOverlayCodeNotLoaded"; 288 runOverlayDeviceTest(TARGET_OVERLAYABLE_APK, OVERLAY_ALL_HAS_CODE_APK, OVERLAY_ALL_PACKAGE, 289 testMethod); 290 } 291 292 @Test 293 public void testOverlayPolicyAllNoNameFails() throws Exception { 294 assertFailToGenerateIdmap(OVERLAY_ALL_NO_NAME_APK, OVERLAY_ALL_PACKAGE); 295 } 296 297 @Test 298 public void testOverlayPolicyProductFails() throws Exception { 299 assertFailToGenerateIdmap(OVERLAY_PRODUCT_APK, OVERLAY_PRODUCT_PACKAGE); 300 } 301 302 @Test 303 public void testOverlayPolicySystemFails() throws Exception { 304 assertFailToGenerateIdmap(OVERLAY_SYSTEM_APK, OVERLAY_SYSTEM_PACKAGE); 305 } 306 307 @Test 308 public void testOverlayPolicyVendorFails() throws Exception { 309 assertFailToGenerateIdmap(OVERLAY_VENDOR_APK, OVERLAY_VENDOR_PACKAGE); 310 } 311 312 @Test 313 public void testOverlayPolicyDifferentSignatureFails() throws Exception { 314 assertFailToGenerateIdmap(OVERLAY_DIFFERENT_SIGNATURE_APK, 315 OVERLAY_DIFFERENT_SIGNATURE_PACKAGE); 316 } 317 318 @Test 319 public void testFrameworkDoesNotDefineOverlayable() throws Exception { 320 String testMethod = "testFrameworkDoesNotDefineOverlayable"; 321 runDeviceTests(TEST_APP_PACKAGE, TEST_APP_CLASS, testMethod, false /* instant */); 322 } 323 324 /** Overlays must not overlay assets. */ 325 @Test 326 public void testCannotOverlayAssets() throws Exception { 327 String testMethod = "testCannotOverlayAssets"; 328 runOverlayDeviceTest(TARGET_OVERLAYABLE_APK, OVERLAY_ALL_APK, OVERLAY_ALL_PACKAGE, 329 testMethod); 330 } 331 332 @Test 333 public void testOverlayEnabled_activityInForeground() throws Exception { 334 final HashMap<String, String> testArgs = new HashMap<>(); 335 testArgs.put(PARAM_START_SERVICE, Boolean.FALSE.toString()); 336 try { 337 new InstallMultiple().addFile(OVERLAY_ALL_APK).run(); 338 new InstallMultiple().addFile(TARGET_OVERLAYABLE_APK).run(); 339 340 runDeviceTests(TARGET_PACKAGE, OVERLAY_TARGET_TEST_APP_CLASS, 341 "overlayEnabled_activityInForeground", testArgs); 342 } finally { 343 getDevice().uninstallPackage(TARGET_PACKAGE); 344 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 345 } 346 } 347 348 @Test 349 public void testOverlayEnabled_activityInBackground_toForeground() throws Exception { 350 final HashMap<String, String> testArgs = new HashMap<>(); 351 testArgs.put(PARAM_START_SERVICE, Boolean.FALSE.toString()); 352 try { 353 new InstallMultiple().addFile(OVERLAY_ALL_APK).run(); 354 new InstallMultiple().addFile(TARGET_OVERLAYABLE_APK).run(); 355 356 runDeviceTests(TARGET_PACKAGE, OVERLAY_TARGET_TEST_APP_CLASS, 357 "overlayEnabled_activityInBackground_toForeground", testArgs); 358 } finally { 359 getDevice().uninstallPackage(TARGET_PACKAGE); 360 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 361 } 362 } 363 364 @Test 365 public void testOverlayEnabled_activityWithServiceInForeground() throws Exception { 366 final HashMap<String, String> testArgs = new HashMap<>(); 367 testArgs.put(PARAM_START_SERVICE, Boolean.TRUE.toString()); 368 try { 369 new InstallMultiple().addFile(OVERLAY_ALL_APK).run(); 370 new InstallMultiple().addFile(TARGET_OVERLAYABLE_APK).run(); 371 372 runDeviceTests(TARGET_PACKAGE, OVERLAY_TARGET_TEST_APP_CLASS, 373 "overlayEnabled_activityInForeground", testArgs); 374 } finally { 375 getDevice().uninstallPackage(TARGET_PACKAGE); 376 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 377 } 378 } 379 380 @Test 381 public void testOverlayEnabled_activityWithServiceInBackground_toForeground() throws Exception { 382 final HashMap<String, String> testArgs = new HashMap<>(); 383 testArgs.put(PARAM_START_SERVICE, Boolean.TRUE.toString()); 384 try { 385 new InstallMultiple().addFile(OVERLAY_ALL_APK).run(); 386 new InstallMultiple().addFile(TARGET_OVERLAYABLE_APK).run(); 387 388 runDeviceTests(TARGET_PACKAGE, OVERLAY_TARGET_TEST_APP_CLASS, 389 "overlayEnabled_activityInBackground_toForeground", testArgs); 390 } finally { 391 getDevice().uninstallPackage(TARGET_PACKAGE); 392 getDevice().uninstallPackage(OVERLAY_ALL_PACKAGE); 393 } 394 } 395 } 396