1 /* 2 * Copyright (C) 2019 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 com.android.tests.stagedinstall.host; 18 19 import static com.android.cts.shim.lib.ShimPackage.SHIM_APEX_PACKAGE_NAME; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.hamcrest.CoreMatchers.endsWith; 24 import static org.hamcrest.CoreMatchers.equalTo; 25 import static org.hamcrest.CoreMatchers.not; 26 import static org.junit.Assume.assumeFalse; 27 import static org.junit.Assume.assumeThat; 28 import static org.junit.Assume.assumeTrue; 29 30 import android.cts.install.lib.host.InstallUtilsHost; 31 import android.platform.test.annotations.LargeTest; 32 33 import com.android.apex.ApexInfo; 34 import com.android.apex.XmlParser; 35 import com.android.ddmlib.Log; 36 import com.android.tradefed.device.DeviceNotAvailableException; 37 import com.android.tradefed.device.ITestDevice; 38 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 39 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 40 41 42 import org.junit.After; 43 import org.junit.Before; 44 import org.junit.Rule; 45 import org.junit.Test; 46 import org.junit.rules.TestWatcher; 47 import org.junit.runner.Description; 48 import org.junit.runner.RunWith; 49 50 import java.io.File; 51 import java.io.FileInputStream; 52 import java.util.List; 53 import java.util.Set; 54 import java.util.stream.Collectors; 55 56 @RunWith(DeviceJUnit4ClassRunner.class) 57 public class StagedInstallTest extends BaseHostJUnit4Test { 58 59 private static final String TAG = "StagedInstallTest"; 60 61 private static final String PACKAGE_NAME = "com.android.tests.stagedinstall"; 62 63 private static final String BROADCAST_RECEIVER_COMPONENT = PACKAGE_NAME + "/" 64 + PACKAGE_NAME + ".LauncherActivity"; 65 66 private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this); 67 68 private String mDefaultLauncher = null; 69 70 @Rule 71 public final FailedTestLogHook mFailedTestLogHook = new FailedTestLogHook(this); 72 73 /** 74 * Runs the given phase of a test by calling into the device. 75 * Throws an exception if the test phase fails. 76 * <p> 77 * For example, <code>runPhase("testInstallStagedApkCommit");</code> 78 */ runPhase(String phase)79 private void runPhase(String phase) throws Exception { 80 assertThat(runDeviceTests(PACKAGE_NAME, 81 "com.android.tests.stagedinstall.StagedInstallTest", 82 phase)).isTrue(); 83 } 84 85 // We do not assert the success of cleanup phase since it might fail due to flaky reasons. cleanUp()86 private void cleanUp() throws Exception { 87 try { 88 runDeviceTests(PACKAGE_NAME, 89 "com.android.tests.stagedinstall.StagedInstallTest", 90 "cleanUp"); 91 } catch (AssertionError e) { 92 Log.e(TAG, e); 93 } 94 } 95 96 @Before setUp()97 public void setUp() throws Exception { 98 cleanUp(); 99 mHostUtils.uninstallShimApexIfNecessary(); 100 storeDefaultLauncher(); 101 } 102 103 @After tearDown()104 public void tearDown() throws Exception { 105 cleanUp(); 106 mHostUtils.uninstallShimApexIfNecessary(); 107 setDefaultLauncher(mDefaultLauncher); 108 } 109 110 /** 111 * Tests for staged install involving only one apk. 112 */ 113 @Test 114 @LargeTest testInstallStagedApk()115 public void testInstallStagedApk() throws Exception { 116 assumeSystemUser(); 117 118 setDefaultLauncher(BROADCAST_RECEIVER_COMPONENT); 119 runPhase("testInstallStagedApk_Commit"); 120 getDevice().reboot(); 121 runPhase("testInstallStagedApk_VerifyPostReboot"); 122 runPhase("testInstallStagedApk_AbandonSessionIsNoop"); 123 } 124 125 @Test testFailInstallIfNoPermission()126 public void testFailInstallIfNoPermission() throws Exception { 127 runPhase("testFailInstallIfNoPermission"); 128 } 129 130 @Test 131 @LargeTest testAbandonStagedApkBeforeReboot()132 public void testAbandonStagedApkBeforeReboot() throws Exception { 133 runPhase("testAbandonStagedApkBeforeReboot_CommitAndAbandon"); 134 getDevice().reboot(); 135 runPhase("testAbandonStagedApkBeforeReboot_VerifyPostReboot"); 136 } 137 138 @Test 139 @LargeTest testAbandonStagedApkBeforeReady()140 public void testAbandonStagedApkBeforeReady() throws Exception { 141 runPhase("testAbandonStagedApkBeforeReady_CommitAndAbandon"); 142 getDevice().reboot(); 143 runPhase("testAbandonStagedApkBeforeReady_VerifyPostReboot"); 144 } 145 146 @Test testStageAnotherSessionImmediatelyAfterAbandon()147 public void testStageAnotherSessionImmediatelyAfterAbandon() throws Exception { 148 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 149 runPhase("testStageAnotherSessionImmediatelyAfterAbandon"); 150 } 151 152 @Test testStageAnotherSessionImmediatelyAfterAbandonMultiPackage()153 public void testStageAnotherSessionImmediatelyAfterAbandonMultiPackage() throws Exception { 154 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 155 runPhase("testStageAnotherSessionImmediatelyAfterAbandonMultiPackage"); 156 } 157 158 @Test testNoSessionUpdatedBroadcastSentForStagedSessionAbandon()159 public void testNoSessionUpdatedBroadcastSentForStagedSessionAbandon() throws Exception { 160 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 161 runPhase("testNoSessionUpdatedBroadcastSentForStagedSessionAbandon"); 162 } 163 164 @Test 165 @LargeTest testInstallMultipleStagedApks()166 public void testInstallMultipleStagedApks() throws Exception { 167 assumeSystemUser(); 168 169 setDefaultLauncher(BROADCAST_RECEIVER_COMPONENT); 170 runPhase("testInstallMultipleStagedApks_Commit"); 171 getDevice().reboot(); 172 runPhase("testInstallMultipleStagedApks_VerifyPostReboot"); 173 } 174 assumeSystemUser()175 private void assumeSystemUser() throws Exception { 176 String systemUser = "0"; 177 assumeThat("Current user is not system user", 178 getDevice().executeShellCommand("am get-current-user").trim(), equalTo(systemUser)); 179 } 180 181 @Test testGetActiveStagedSessions()182 public void testGetActiveStagedSessions() throws Exception { 183 assumeTrue("Device does not support file-system checkpoint", 184 mHostUtils.isCheckpointSupported()); 185 186 runPhase("testGetActiveStagedSessions"); 187 } 188 189 /** 190 * Verifies that active staged session fulfils conditions stated at 191 * {@link PackageInstaller.SessionInfo#isStagedSessionActive} 192 */ 193 @Test testIsStagedSessionActive()194 public void testIsStagedSessionActive() throws Exception { 195 runPhase("testIsStagedSessionActive"); 196 } 197 198 @Test testGetActiveStagedSessionsNoSessionActive()199 public void testGetActiveStagedSessionsNoSessionActive() throws Exception { 200 runPhase("testGetActiveStagedSessionsNoSessionActive"); 201 } 202 203 @Test testGetActiveStagedSessions_MultiApkSession()204 public void testGetActiveStagedSessions_MultiApkSession() throws Exception { 205 assumeTrue("Device does not support file-system checkpoint", 206 mHostUtils.isCheckpointSupported()); 207 208 runPhase("testGetActiveStagedSessions_MultiApkSession"); 209 } 210 211 @Test testStagedInstallDowngrade_DowngradeNotRequested_Fails()212 public void testStagedInstallDowngrade_DowngradeNotRequested_Fails() throws Exception { 213 runPhase("testStagedInstallDowngrade_DowngradeNotRequested_Fails_Commit"); 214 } 215 216 @Test 217 @LargeTest testStagedInstallDowngrade_DowngradeRequested_DebugBuild()218 public void testStagedInstallDowngrade_DowngradeRequested_DebugBuild() throws Exception { 219 assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user"))); 220 221 runPhase("testStagedInstallDowngrade_DowngradeRequested_Commit"); 222 getDevice().reboot(); 223 runPhase("testStagedInstallDowngrade_DowngradeRequested_DebugBuild_VerifyPostReboot"); 224 } 225 226 @Test testStagedInstallDowngrade_DowngradeRequested_UserBuild()227 public void testStagedInstallDowngrade_DowngradeRequested_UserBuild() throws Exception { 228 assumeThat(getDevice().getBuildFlavor(), endsWith("-user")); 229 assumeFalse("Device is debuggable", isDebuggable()); 230 231 runPhase("testStagedInstallDowngrade_DowngradeRequested_Fails_Commit"); 232 } 233 234 @Test testShimApexShouldPreInstalledIfUpdatingApexIsSupported()235 public void testShimApexShouldPreInstalledIfUpdatingApexIsSupported() throws Exception { 236 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 237 238 final ITestDevice.ApexInfo shimApex = mHostUtils.getShimApex().orElseThrow( 239 () -> new AssertionError("Can't find " + SHIM_APEX_PACKAGE_NAME) 240 ); 241 assertThat(shimApex.versionCode).isEqualTo(1); 242 } 243 244 @Test 245 @LargeTest testInstallStagedApex()246 public void testInstallStagedApex() throws Exception { 247 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 248 249 setDefaultLauncher(BROADCAST_RECEIVER_COMPONENT); 250 runPhase("testInstallStagedApex_Commit"); 251 getDevice().reboot(); 252 runPhase("testInstallStagedApex_VerifyPostReboot"); 253 } 254 255 @Test 256 // Don't mark as @LargeTest since we want at least one test to install apex during pre-submit. testInstallStagedApexAndApk()257 public void testInstallStagedApexAndApk() throws Exception { 258 assumeSystemUser(); 259 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 260 261 setDefaultLauncher(BROADCAST_RECEIVER_COMPONENT); 262 runPhase("testInstallStagedApexAndApk_Commit"); 263 getDevice().reboot(); 264 runPhase("testInstallStagedApexAndApk_VerifyPostReboot"); 265 } 266 267 @Test testsFailsNonStagedApexInstall()268 public void testsFailsNonStagedApexInstall() throws Exception { 269 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 270 271 runPhase("testsFailsNonStagedApexInstall"); 272 } 273 274 @Test testInstallStagedNonPreInstalledApex_Fails()275 public void testInstallStagedNonPreInstalledApex_Fails() throws Exception { 276 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 277 278 runPhase("testInstallStagedNonPreInstalledApex_Fails"); 279 } 280 281 @Test testInstallStagedDifferentPackageNameWithInstalledApex_Fails()282 public void testInstallStagedDifferentPackageNameWithInstalledApex_Fails() throws Exception { 283 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 284 285 runPhase("testInstallStagedDifferentPackageNameWithInstalledApex_Fails"); 286 } 287 288 @Test 289 @LargeTest testStageApkWithSameNameAsApexShouldFail()290 public void testStageApkWithSameNameAsApexShouldFail() throws Exception { 291 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 292 293 runPhase("testStageApkWithSameNameAsApexShouldFail_Commit"); 294 getDevice().reboot(); 295 runPhase("testStageApkWithSameNameAsApexShouldFail_VerifyPostReboot"); 296 } 297 298 @Test testNonStagedInstallApkWithSameNameAsApexShouldFail()299 public void testNonStagedInstallApkWithSameNameAsApexShouldFail() throws Exception { 300 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 301 runPhase("testNonStagedInstallApkWithSameNameAsApexShouldFail"); 302 } 303 304 @Test 305 @LargeTest testStagedInstallDowngradeApex_DowngradeNotRequested_Fails()306 public void testStagedInstallDowngradeApex_DowngradeNotRequested_Fails() throws Exception { 307 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 308 309 installV3Apex(); 310 runPhase("testStagedInstallDowngradeApex_DowngradeNotRequested_Fails_Commit"); 311 getDevice().reboot(); 312 runPhase("testStagedInstallDowngradeApex_DowngradeNotRequested_Fails_VerifyPostReboot"); 313 } 314 315 @Test 316 @LargeTest testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild()317 public void testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild() throws Exception { 318 assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user"))); 319 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 320 321 installV3Apex(); 322 runPhase("testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild_Commit"); 323 getDevice().reboot(); 324 runPhase("testStagedInstallDowngradeApex_DowngradeRequested_DebugBuild_VerifyPostReboot"); 325 } 326 327 @Test 328 @LargeTest testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails()329 public void testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails() 330 throws Exception { 331 assumeThat(getDevice().getBuildFlavor(), endsWith("-user")); 332 assumeFalse("Device is debuggable", isDebuggable()); 333 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 334 335 installV3Apex(); 336 runPhase("testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails_Commit"); 337 getDevice().reboot(); 338 runPhase("testStagedInstallDowngradeApex_DowngradeRequested_UserBuild_Fails_" 339 + "VerifyPostReboot"); 340 } 341 342 @Test 343 @LargeTest testStagedInstallDowngradeApexToSystemVersion_DebugBuild()344 public void testStagedInstallDowngradeApexToSystemVersion_DebugBuild() throws Exception { 345 assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user"))); 346 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 347 348 installV2Apex(); 349 runPhase("testStagedInstallDowngradeApexToSystemVersion_DebugBuild_Commit"); 350 getDevice().reboot(); 351 runPhase("testStagedInstallDowngradeApexToSystemVersion_DebugBuild_VerifyPostReboot"); 352 } 353 354 @Test 355 @LargeTest testInstallStagedApex_SameGrade()356 public void testInstallStagedApex_SameGrade() throws Exception { 357 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 358 installV3Apex(); 359 ApexInfo shim1 = 360 readApexInfoList().stream() 361 .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) 362 .filter(ApexInfo::getIsActive) 363 .findAny() 364 .orElseThrow(() -> 365 new AssertionError( 366 "No active version of " + SHIM_APEX_PACKAGE_NAME 367 + " found in /apex/apex-info-list.xml")); 368 369 installV3Apex(); 370 ApexInfo shim2 = 371 readApexInfoList().stream() 372 .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) 373 .filter(ApexInfo::getIsActive) 374 .findAny() 375 .orElseThrow(() -> 376 new AssertionError( 377 "No active version of " + SHIM_APEX_PACKAGE_NAME 378 + " found in /apex/apex-info-list.xml")); 379 assertThat(shim1.getLastUpdateMillis()).isNotEqualTo(shim2.getLastUpdateMillis()); 380 } 381 382 @Test 383 @LargeTest testInstallStagedApex_SameGrade_NewOneWins()384 public void testInstallStagedApex_SameGrade_NewOneWins() throws Exception { 385 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 386 387 installV2Apex(); 388 389 runPhase("testInstallStagedApex_SameGrade_NewOneWins_Commit"); 390 getDevice().reboot(); 391 runPhase("testInstallStagedApex_SameGrade_NewOneWins_VerifyPostReboot"); 392 } 393 394 @Test testInstallApex_DeviceDoesNotSupportApex_Fails()395 public void testInstallApex_DeviceDoesNotSupportApex_Fails() throws Exception { 396 assumeFalse("Device supports updating APEX", mHostUtils.isApexUpdateSupported()); 397 398 runPhase("testInstallApex_DeviceDoesNotSupportApex_Fails"); 399 } 400 installV2Apex()401 private void installV2Apex()throws Exception { 402 runPhase("testInstallV2Apex_Commit"); 403 getDevice().reboot(); 404 runPhase("testInstallV2Apex_VerifyPostReboot"); 405 } 406 installV2SignedBobApex()407 private void installV2SignedBobApex() throws Exception { 408 runPhase("testInstallV2SignedBobApex_Commit"); 409 getDevice().reboot(); 410 runPhase("testInstallV2SignedBobApex_VerifyPostReboot"); 411 } 412 installV3Apex()413 private void installV3Apex()throws Exception { 414 runPhase("testInstallV3Apex_Commit"); 415 getDevice().reboot(); 416 runPhase("testInstallV3Apex_VerifyPostReboot"); 417 } 418 419 @Test testFailsInvalidApexInstall()420 public void testFailsInvalidApexInstall() throws Exception { 421 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 422 runPhase("testFailsInvalidApexInstall_Commit"); 423 runPhase("testFailsInvalidApexInstall_AbandonSessionIsNoop"); 424 } 425 426 @Test testStagedApkSessionCallbacks()427 public void testStagedApkSessionCallbacks() throws Exception { 428 runPhase("testStagedApkSessionCallbacks"); 429 } 430 431 @Test 432 @LargeTest testInstallStagedApexWithoutApexSuffix()433 public void testInstallStagedApexWithoutApexSuffix() throws Exception { 434 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 435 436 runPhase("testInstallStagedApexWithoutApexSuffix_Commit"); 437 getDevice().reboot(); 438 runPhase("testInstallStagedApexWithoutApexSuffix_VerifyPostReboot"); 439 } 440 441 @Test testRejectsApexDifferentCertificate()442 public void testRejectsApexDifferentCertificate() throws Exception { 443 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 444 445 runPhase("testRejectsApexDifferentCertificate"); 446 } 447 448 /** 449 * Tests for staged install involving rotated keys. 450 * 451 * Here alice means the original default key that cts.shim.v1 package was signed with and 452 * bob is the new key alice rotates to. Where ambiguous, we will refer keys as alice and bob 453 * instead of "old key" and "new key". 454 * 455 * By default, rotated keys have rollback capability enabled for old keys. When we remove 456 * rollback capability from a key, it is called "Distrusting Event" and the distrusted key can 457 * not update the app anymore. 458 */ 459 460 // Should not be able to update with a key that has not been rotated. 461 @Test testUpdateWithDifferentKeyButNoRotation()462 public void testUpdateWithDifferentKeyButNoRotation() throws Exception { 463 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 464 465 runPhase("testUpdateWithDifferentKeyButNoRotation"); 466 } 467 468 // Should be able to update with a key that has been rotated. 469 @Test 470 @LargeTest testUpdateWithDifferentKey()471 public void testUpdateWithDifferentKey() throws Exception { 472 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 473 474 runPhase("testUpdateWithDifferentKey_Commit"); 475 getDevice().reboot(); 476 runPhase("testUpdateWithDifferentKey_VerifyPostReboot"); 477 } 478 479 // Should not be able to update with a key that is no longer trusted (i.e, has no 480 // rollback capability) 481 @Test 482 @LargeTest testUntrustedOldKeyIsRejected()483 public void testUntrustedOldKeyIsRejected() throws Exception { 484 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 485 486 installV2SignedBobApex(); 487 runPhase("testUntrustedOldKeyIsRejected"); 488 } 489 490 // Should be able to update with an old key which is trusted 491 @Test 492 @LargeTest testTrustedOldKeyIsAccepted()493 public void testTrustedOldKeyIsAccepted() throws Exception { 494 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 495 496 runPhase("testTrustedOldKeyIsAccepted_Commit"); 497 getDevice().reboot(); 498 runPhase("testTrustedOldKeyIsAccepted_CommitPostReboot"); 499 getDevice().reboot(); 500 runPhase("testTrustedOldKeyIsAccepted_VerifyPostReboot"); 501 } 502 503 // Should be able to update further with rotated key 504 @Test 505 @LargeTest testAfterRotationNewKeyCanUpdateFurther()506 public void testAfterRotationNewKeyCanUpdateFurther() throws Exception { 507 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 508 509 installV2SignedBobApex(); 510 runPhase("testAfterRotationNewKeyCanUpdateFurther_CommitPostReboot"); 511 getDevice().reboot(); 512 runPhase("testAfterRotationNewKeyCanUpdateFurther_VerifyPostReboot"); 513 } 514 515 @Test 516 @LargeTest testAfterRotationNewKeyCanUpdateFurtherWithoutLineage()517 public void testAfterRotationNewKeyCanUpdateFurtherWithoutLineage() throws Exception { 518 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 519 520 installV2SignedBobApex(); 521 runPhase("testAfterRotationNewKeyCanUpdateFurtherWithoutLineage"); 522 } 523 524 /** 525 * Tests for staging and installing multiple staged sessions. 526 */ 527 528 // Should fail to stage multiple sessions when check-point is not available 529 @Test testFailStagingMultipleSessionsIfNoCheckPoint()530 public void testFailStagingMultipleSessionsIfNoCheckPoint() throws Exception { 531 assumeFalse("Device supports file-system checkpoint", 532 mHostUtils.isCheckpointSupported()); 533 534 runPhase("testFailStagingMultipleSessionsIfNoCheckPoint"); 535 } 536 537 @Test testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk()538 public void testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk() throws Exception { 539 assumeTrue("Device does not support file-system checkpoint", 540 mHostUtils.isCheckpointSupported()); 541 542 runPhase("testFailOverlappingMultipleStagedInstall_BothSinglePackage_Apk"); 543 } 544 545 @Test testAllowNonOverlappingMultipleStagedInstall_MultiPackageSinglePackage_Apk()546 public void testAllowNonOverlappingMultipleStagedInstall_MultiPackageSinglePackage_Apk() 547 throws Exception { 548 assumeTrue("Device does not support file-system checkpoint", 549 mHostUtils.isCheckpointSupported()); 550 551 runPhase("testAllowNonOverlappingMultipleStagedInstall_MultiPackageSinglePackage_Apk"); 552 } 553 554 @Test testFailOverlappingMultipleStagedInstall_BothMultiPackage_Apk()555 public void testFailOverlappingMultipleStagedInstall_BothMultiPackage_Apk() throws Exception { 556 assumeTrue("Device does not support file-system checkpoint", 557 mHostUtils.isCheckpointSupported()); 558 559 runPhase("testFailOverlappingMultipleStagedInstall_BothMultiPackage_Apk"); 560 } 561 562 // Test for installing multiple staged sessions at the same time 563 @Test 564 @LargeTest testMultipleStagedInstall_ApkOnly()565 public void testMultipleStagedInstall_ApkOnly() throws Exception { 566 assumeTrue("Device does not support file-system checkpoint", 567 mHostUtils.isCheckpointSupported()); 568 569 runPhase("testMultipleStagedInstall_ApkOnly_Commit"); 570 getDevice().reboot(); 571 runPhase("testMultipleStagedInstall_ApkOnly_VerifyPostReboot"); 572 } 573 574 // If apk installation fails in one staged session, then all staged session should fail. 575 @Test 576 @LargeTest testInstallMultipleStagedSession_PartialFail_ApkOnly()577 public void testInstallMultipleStagedSession_PartialFail_ApkOnly() throws Exception { 578 assumeTrue("Device does not support file-system checkpoint", 579 mHostUtils.isCheckpointSupported()); 580 581 runPhase("testInstallMultipleStagedSession_PartialFail_ApkOnly_Commit"); 582 getDevice().reboot(); 583 runPhase("testInstallMultipleStagedSession_PartialFail_ApkOnly_VerifyPostReboot"); 584 } 585 586 // Failure reason of staged install should be be persisted for single sessions 587 @Test 588 @LargeTest testFailureReasonPersists_SingleSession()589 public void testFailureReasonPersists_SingleSession() throws Exception { 590 assumeTrue("Device does not support file-system checkpoint", 591 mHostUtils.isCheckpointSupported()); 592 593 runPhase("testFailureReasonPersists_SingleSession_Commit"); 594 getDevice().reboot(); 595 runPhase("testFailureReasonPersists_SingleSession_VerifyPostReboot"); 596 } 597 598 // Failure reason of staged install should be be persisted for multi session staged install 599 @Test 600 @LargeTest testFailureReasonPersists_MultiSession()601 public void testFailureReasonPersists_MultiSession() throws Exception { 602 assumeTrue("Device does not support file-system checkpoint", 603 mHostUtils.isCheckpointSupported()); 604 605 runPhase("testFailureReasonPersists_MultipleSession_Commit"); 606 getDevice().reboot(); 607 runPhase("testFailureReasonPersists_MultipleSession_VerifyPostReboot"); 608 } 609 610 @Test 611 @LargeTest testSamegradeSystemApex()612 public void testSamegradeSystemApex() throws Exception { 613 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 614 615 runPhase("testSamegradeSystemApex_Commit"); 616 getDevice().reboot(); 617 runPhase("testSamegradeSystemApex_VerifyPostReboot"); 618 } 619 620 @Test 621 @LargeTest testInstallApkChangingFingerprint()622 public void testInstallApkChangingFingerprint() throws Exception { 623 try { 624 getDevice().executeShellCommand("setprop persist.pm.mock-upgrade true"); 625 runPhase("testInstallApkChangingFingerprint"); 626 getDevice().reboot(); 627 runPhase("testInstallApkChangingFingerprint_VerifyAborted"); 628 } finally { 629 getDevice().executeShellCommand("setprop persist.pm.mock-upgrade false"); 630 } 631 } 632 633 @Test 634 @LargeTest testInstallStagedNoHashtreeApex()635 public void testInstallStagedNoHashtreeApex() throws Exception { 636 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 637 638 runPhase("testInstallStagedNoHashtreeApex_Commit"); 639 getDevice().reboot(); 640 runPhase("testInstallStagedNoHashtreeApex_VerifyPostReboot"); 641 } 642 643 /** 644 * Should fail to verify apex targeting older dev sdk 645 */ 646 @Test testApexTargetingOldDevSdkFailsVerification()647 public void testApexTargetingOldDevSdkFailsVerification() throws Exception { 648 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 649 650 runPhase("testApexTargetingOldDevSdkFailsVerification"); 651 } 652 653 /** 654 * Apex should fail to install if apk-in-apex fails to get scanned 655 */ 656 @Test 657 @LargeTest testApexFailsToInstallIfApkInApexFailsToScan()658 public void testApexFailsToInstallIfApkInApexFailsToScan() throws Exception { 659 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 660 661 runPhase("testApexFailsToInstallIfApkInApexFailsToScan_Commit"); 662 getDevice().reboot(); 663 runPhase("testApexFailsToInstallIfApkInApexFailsToScan_VerifyPostReboot"); 664 } 665 666 @Test testCorruptedApexFailsVerification_b146895998()667 public void testCorruptedApexFailsVerification_b146895998() throws Exception { 668 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 669 670 runPhase("testCorruptedApexFailsVerification_b146895998"); 671 } 672 673 /** 674 * Should fail to pass apk signature check 675 */ 676 @Test testApexWithUnsignedApkFailsVerification()677 public void testApexWithUnsignedApkFailsVerification() throws Exception { 678 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 679 680 runPhase("testApexWithUnsignedApkFailsVerification"); 681 } 682 683 /** 684 * Should fail to verify apex signed payload with a different key 685 */ 686 @Test testApexSignPayloadWithDifferentKeyFailsVerification()687 public void testApexSignPayloadWithDifferentKeyFailsVerification() throws Exception { 688 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 689 690 runPhase("testApexSignPayloadWithDifferentKeyFailsVerification"); 691 } 692 693 /** 694 * Should fail to verify apex with unsigned payload 695 */ 696 @Test testApexWithUnsignedPayloadFailsVerification()697 public void testApexWithUnsignedPayloadFailsVerification() throws Exception { 698 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 699 700 runPhase("testApexWithUnsignedPayloadFailsVerification"); 701 } 702 703 @Test 704 @LargeTest testApexSetsUpdatedSystemAppFlag()705 public void testApexSetsUpdatedSystemAppFlag() throws Exception { 706 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 707 708 runPhase("testApexSetsUpdatedSystemAppFlag_preUpdate"); 709 installV2Apex(); 710 runPhase("testApexSetsUpdatedSystemAppFlag_postUpdate"); 711 } 712 713 /** 714 * Test non-priv apps cannot access /data/app-staging folder contents 715 */ 716 @Test testAppStagingDirCannotBeReadByNonPrivApps()717 public void testAppStagingDirCannotBeReadByNonPrivApps() throws Exception { 718 runPhase("testAppStagingDirCannotBeReadByNonPrivApps"); 719 } 720 721 @Test 722 @LargeTest testUpdatedApexFromDataApexActiveCanBePulled()723 public void testUpdatedApexFromDataApexActiveCanBePulled() throws Exception { 724 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 725 726 installV2Apex(); 727 728 final ITestDevice.ApexInfo shimApex = mHostUtils.getShimApex().orElseThrow( 729 () -> new AssertionError("Can't find " + SHIM_APEX_PACKAGE_NAME) 730 ); 731 732 assertThat(shimApex.sourceDir).startsWith("/data/apex/active"); 733 assertThat(getDevice().pullFile(shimApex.sourceDir)).isNotNull(); 734 } 735 736 @Test testApexInfoList()737 public void testApexInfoList() throws Exception { 738 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 739 740 // Check that content of /apex/apex-info-list.xml matches output of 741 // `adb shell pm list packages --apex-only --show-versioncode -f`. 742 List<ApexInfo> apexInfoList = 743 readApexInfoList().stream() 744 .filter(a -> a.getIsActive()) 745 .collect(Collectors.toList()); 746 Set<ITestDevice.ApexInfo> activeApexes = getDevice().getActiveApexes(); 747 assertThat(apexInfoList.size()).isEqualTo(activeApexes.size()); 748 for (ITestDevice.ApexInfo apex : activeApexes) { 749 // Note: we can't assert equality of the apex.name and apexInfo.getModuleName() since 750 // they represent different concepts (the former is package name, while latter is apex 751 // module name) 752 List<ApexInfo> temp = 753 apexInfoList.stream() 754 .filter(a -> a.getModulePath().equals(apex.sourceDir)) 755 .collect(Collectors.toList()); 756 assertThat(temp).hasSize(1); 757 ApexInfo apexInfo = temp.get(0); 758 assertThat(apexInfo.getModulePath()).isEqualTo(apex.sourceDir); 759 assertThat(apexInfo.getVersionCode()).isEqualTo(apex.versionCode); 760 assertThat(apexInfo.getIsActive()).isTrue(); 761 assertThat(apexInfo.getLastUpdateMillis()).isGreaterThan(0); 762 } 763 } 764 765 @Test 766 @LargeTest testApexInfoListAfterUpdate()767 public void testApexInfoListAfterUpdate() throws Exception { 768 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 769 770 ApexInfo shimBeforeUpdate = getShimApexInfo(); 771 772 installV2Apex(); 773 774 List<ApexInfo> shimApexInfo = 775 readApexInfoList().stream() 776 .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) 777 .collect(Collectors.toList()); 778 779 assertThat(shimApexInfo).hasSize(2); 780 781 ApexInfo factoryShimApexInfo = 782 shimApexInfo.stream() 783 .filter(ApexInfo::getIsFactory) 784 .findAny() 785 .orElseThrow(() -> 786 new AssertionError( 787 "No factory version of " + SHIM_APEX_PACKAGE_NAME 788 + " found in /apex/apex-info-list.xml")); 789 assertThat(factoryShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); 790 assertThat(factoryShimApexInfo.getIsActive()).isFalse(); 791 assertThat(factoryShimApexInfo.getIsFactory()).isTrue(); 792 assertThat(factoryShimApexInfo.getVersionCode()).isEqualTo(1); 793 assertThat(factoryShimApexInfo.getModulePath()) 794 .isEqualTo(factoryShimApexInfo.getPreinstalledModulePath()); 795 assertThat(factoryShimApexInfo.getLastUpdateMillis()) 796 .isEqualTo(shimBeforeUpdate.getLastUpdateMillis()); 797 798 ApexInfo activeShimApexInfo = 799 shimApexInfo.stream() 800 .filter(ApexInfo::getIsActive) 801 .findAny() 802 .orElseThrow(() -> 803 new AssertionError( 804 "No active version of " + SHIM_APEX_PACKAGE_NAME 805 + " found in /apex/apex-info-list.xml")); 806 assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); 807 assertThat(activeShimApexInfo.getIsActive()).isTrue(); 808 assertThat(activeShimApexInfo.getIsFactory()).isFalse(); 809 assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(2); 810 assertThat(activeShimApexInfo.getPreinstalledModulePath()) 811 .isEqualTo(factoryShimApexInfo.getModulePath()); 812 assertThat(activeShimApexInfo.getLastUpdateMillis()) 813 .isNotEqualTo(shimBeforeUpdate.getLastUpdateMillis()); 814 } 815 816 @Test 817 @LargeTest testRebootlessUpdate()818 public void testRebootlessUpdate() throws Exception { 819 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 820 821 runPhase("testRebootlessUpdate"); 822 ApexInfo activeShimApexInfo = getActiveShimApexInfo(); 823 assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); 824 assertThat(activeShimApexInfo.getIsActive()).isTrue(); 825 assertThat(activeShimApexInfo.getIsFactory()).isFalse(); 826 assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(2); 827 } 828 829 @Test 830 @LargeTest testRebootlessUpdate_fromV2ToV3_sameBoot()831 public void testRebootlessUpdate_fromV2ToV3_sameBoot() throws Exception { 832 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 833 834 runPhase("testRebootlessUpdate"); 835 runPhase("testRebootlessUpdate_installV3"); 836 ApexInfo activeShimApexInfo = getActiveShimApexInfo(); 837 assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); 838 assertThat(activeShimApexInfo.getIsActive()).isTrue(); 839 assertThat(activeShimApexInfo.getIsFactory()).isFalse(); 840 assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(3); 841 } 842 843 @Test 844 @LargeTest testRebootlessUpdate_fromV2ToV3_rebootInBetween()845 public void testRebootlessUpdate_fromV2ToV3_rebootInBetween() throws Exception { 846 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 847 848 runPhase("testRebootlessUpdate"); 849 getDevice().reboot(); 850 runPhase("testRebootlessUpdate_installV3"); 851 ApexInfo activeShimApexInfo = getActiveShimApexInfo(); 852 assertThat(activeShimApexInfo.getModuleName()).isEqualTo(SHIM_APEX_PACKAGE_NAME); 853 assertThat(activeShimApexInfo.getIsActive()).isTrue(); 854 assertThat(activeShimApexInfo.getIsFactory()).isFalse(); 855 assertThat(activeShimApexInfo.getVersionCode()).isEqualTo(3); 856 } 857 858 @Test 859 @LargeTest testRebootlessUpdate_downgrage_fails()860 public void testRebootlessUpdate_downgrage_fails() throws Exception { 861 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 862 863 runPhase("testRebootlessUpdate_installV3"); 864 runPhase("testRebootlessUpdate_downgradeToV2_fails"); 865 } 866 867 @Test testRebootlessUpdate_noPermission_fails()868 public void testRebootlessUpdate_noPermission_fails() throws Exception { 869 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 870 871 runPhase("testRebootlessUpdate_noPermission_fails"); 872 } 873 874 @Test testRebootlessUpdate_noPreInstalledApex_fails()875 public void testRebootlessUpdate_noPreInstalledApex_fails() throws Exception { 876 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 877 878 runPhase("testRebootlessUpdate_noPreInstalledApex_fails"); 879 } 880 881 @Test testRebootlessUpdate_unsignedPayload_fails()882 public void testRebootlessUpdate_unsignedPayload_fails() throws Exception { 883 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 884 885 runPhase("testRebootlessUpdate_unsignedPayload_fails"); 886 } 887 888 @Test testRebootlessUpdate_payloadSignedWithDifferentKey_fails()889 public void testRebootlessUpdate_payloadSignedWithDifferentKey_fails() throws Exception { 890 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 891 892 runPhase("testRebootlessUpdate_payloadSignedWithDifferentKey_fails"); 893 } 894 895 @Test testRebootlessUpdate_outerContainerSignedWithDifferentCert_fails()896 public void testRebootlessUpdate_outerContainerSignedWithDifferentCert_fails() 897 throws Exception { 898 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 899 900 runPhase("testRebootlessUpdate_outerContainerSignedWithDifferentCert_fails"); 901 } 902 903 @Test testRebootlessUpdate_outerContainerUnsigned_fails()904 public void testRebootlessUpdate_outerContainerUnsigned_fails() throws Exception { 905 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 906 907 runPhase("testRebootlessUpdate_outerContainerUnsigned_fails"); 908 } 909 910 @Test testRebootlessUpdate_targetsOlderSdk_fails()911 public void testRebootlessUpdate_targetsOlderSdk_fails() throws Exception { 912 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 913 914 runPhase("testRebootlessUpdate_targetsOlderSdk_fails"); 915 } 916 917 @Test 918 @LargeTest testGetInactiveApexFactoryPackagesAfterApexInstall_containsNoDuplicates()919 public void testGetInactiveApexFactoryPackagesAfterApexInstall_containsNoDuplicates() 920 throws Exception { 921 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 922 923 installV2Apex(); 924 runPhase("testGetInactiveApexFactoryPackagesAfterApexInstall_containsNoDuplicates"); 925 } 926 readApexInfoList()927 private List<ApexInfo> readApexInfoList() throws Exception { 928 File file = getDevice().pullFile("/apex/apex-info-list.xml"); 929 try (FileInputStream stream = new FileInputStream(file)) { 930 return XmlParser.readApexInfoList(stream).getApexInfo(); 931 } 932 } 933 getShimApexInfo()934 private ApexInfo getShimApexInfo() throws Exception { 935 List<ApexInfo> temp = 936 readApexInfoList().stream() 937 .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) 938 .collect(Collectors.toList()); 939 assertThat(temp).hasSize(1); 940 return temp.get(0); 941 } 942 getActiveShimApexInfo()943 private ApexInfo getActiveShimApexInfo() throws Exception { 944 return readApexInfoList().stream() 945 .filter(a -> a.getModuleName().equals(SHIM_APEX_PACKAGE_NAME)) 946 .filter(ApexInfo::getIsActive) 947 .findAny() 948 .orElseThrow(() -> 949 new AssertionError( 950 "No active version of " + SHIM_APEX_PACKAGE_NAME 951 + " found in /apex/apex-info-list.xml")); 952 } 953 954 /** 955 * Store the component name of the default launcher. This value will be used to reset the 956 * default launcher to its correct component upon test completion. 957 */ storeDefaultLauncher()958 private void storeDefaultLauncher() throws DeviceNotAvailableException { 959 final String PREFIX = "Launcher: ComponentInfo{"; 960 final String POSTFIX = "}"; 961 for (String s : getDevice().executeShellCommand("cmd shortcut get-default-launcher") 962 .split("\n")) { 963 if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) { 964 mDefaultLauncher = s.substring(PREFIX.length(), s.length() - POSTFIX.length()); 965 } 966 } 967 } 968 969 /** 970 * Set the default launcher to a given component. 971 * If set to the broadcast receiver component of this test app, this will allow the test app to 972 * receive SESSION_COMMITTED broadcasts. 973 */ setDefaultLauncher(String launcherComponent)974 private void setDefaultLauncher(String launcherComponent) throws DeviceNotAvailableException { 975 assertThat(launcherComponent).isNotEmpty(); 976 int user = getDevice().getCurrentUser(); 977 getDevice().executeShellCommand( 978 "cmd package set-home-activity --user " + user + " " + launcherComponent); 979 } 980 981 private static final class FailedTestLogHook extends TestWatcher { 982 983 private final BaseHostJUnit4Test mInstance; 984 private String mStagedSessionsBeforeTest; 985 FailedTestLogHook(BaseHostJUnit4Test instance)986 private FailedTestLogHook(BaseHostJUnit4Test instance) { 987 this.mInstance = instance; 988 } 989 990 @Override failed(Throwable e, Description description)991 protected void failed(Throwable e, Description description) { 992 String stagedSessionsAfterTest = getStagedSessions(); 993 Log.e(TAG, "Test " + description + " failed.\n" 994 + "Staged sessions before test started:\n" + mStagedSessionsBeforeTest + "\n" 995 + "Staged sessions after test failed:\n" + stagedSessionsAfterTest); 996 } 997 998 @Override starting(Description description)999 protected void starting(Description description) { 1000 mStagedSessionsBeforeTest = getStagedSessions(); 1001 } 1002 getStagedSessions()1003 private String getStagedSessions() { 1004 try { 1005 return mInstance.getDevice().executeShellV2Command("pm get-stagedsessions").getStdout(); 1006 } catch (DeviceNotAvailableException e) { 1007 Log.e(TAG, e); 1008 return "Failed to get staged sessions"; 1009 } 1010 } 1011 } 1012 isDebuggable()1013 private boolean isDebuggable() throws Exception { 1014 return getDevice().getIntProperty("ro.debuggable", 0) == 1; 1015 } 1016 } 1017