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.cts.rollback.host; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.hamcrest.CoreMatchers.endsWith; 22 import static org.hamcrest.CoreMatchers.equalTo; 23 import static org.hamcrest.CoreMatchers.not; 24 import static org.junit.Assume.assumeThat; 25 import static org.junit.Assume.assumeTrue; 26 import static org.junit.Assume.assumeThat; 27 28 import android.cts.install.lib.host.InstallUtilsHost; 29 30 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; 31 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; 32 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 /** 39 * CTS host tests for RollbackManager APIs. 40 */ 41 @RunWith(DeviceJUnit4ClassRunner.class) 42 public class RollbackManagerHostTest extends BaseHostJUnit4Test { 43 44 private static final String TAG = "RollbackManagerHostTest"; 45 private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this); 46 47 /** 48 * Runs the helper app test method on device. 49 * Throws an exception if the test method fails. 50 * <p> 51 * For example, <code>run("testApkOnlyEnableRollback");</code> 52 */ run(String method)53 private void run(String method) throws Exception { 54 assertThat(runDeviceTests("com.android.cts.rollback.host.app", 55 "com.android.cts.rollback.host.app.HostTestHelper", 56 method)).isTrue(); 57 } 58 59 /** 60 * Runs the helper app test method on device targeted for 61 * com.android.cts.rollback.host.app2.HostTestHelper. 62 */ run2(String method)63 private void run2(String method) throws Exception { 64 assertThat(runDeviceTests("com.android.cts.rollback.host.app2", 65 "com.android.cts.rollback.host.app2.HostTestHelper", 66 method)).isTrue(); 67 } 68 69 /** 70 * Uninstalls any version greater than 1 of shim apex and reboots the device if necessary 71 * to complete the uninstall. 72 * 73 * <p>This is needed because the apex cannot be deleted using PackageInstaller API. 74 * 75 * Also abandon sessions left by previous tests so staged-installs won't fail. 76 */ 77 @Before 78 @After cleanUp()79 public void cleanUp() throws Exception { 80 getDevice().executeShellCommand("for i in $(pm list staged-sessions --only-sessionid " 81 + "--only-parent); do pm install-abandon $i; done"); 82 getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A"); 83 getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.B"); 84 getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.C"); 85 run("cleanUp"); 86 mHostUtils.uninstallShimApexIfNecessary(); 87 } 88 89 /** 90 * Tests staged rollbacks involving only apks. 91 */ 92 @Test testApkOnlyStagedRollback()93 public void testApkOnlyStagedRollback() throws Exception { 94 run("testApkOnlyStagedRollback_Phase1_Install"); 95 getDevice().reboot(); 96 run("testApkOnlyStagedRollback_Phase2_RollBack"); 97 getDevice().reboot(); 98 run("testApkOnlyStagedRollback_Phase3_Confirm"); 99 } 100 101 /** 102 * Tests multiple staged rollbacks involving only apks. 103 */ 104 @Test testApkOnlyMultipleStagedRollback()105 public void testApkOnlyMultipleStagedRollback() throws Exception { 106 assumeTrue("Device does not support file-system checkpoint", 107 mHostUtils.isCheckpointSupported()); 108 109 run("testApkOnlyMultipleStagedRollback_Phase1_Install"); 110 getDevice().reboot(); 111 run("testApkOnlyMultipleStagedRollback_Phase2_RollBack"); 112 getDevice().reboot(); 113 run("testApkOnlyMultipleStagedRollback_Phase3_Confirm"); 114 } 115 116 /** 117 * Tests multiple staged partial rollbacks involving only apks. 118 */ 119 @Test testApkOnlyMultipleStagedPartialRollback()120 public void testApkOnlyMultipleStagedPartialRollback() throws Exception { 121 assumeTrue("Device does not support file-system checkpoint", 122 mHostUtils.isCheckpointSupported()); 123 124 run("testApkOnlyMultipleStagedPartialRollback_Phase1_Install"); 125 getDevice().reboot(); 126 run("testApkOnlyMultipleStagedPartialRollback_Phase2_RollBack"); 127 getDevice().reboot(); 128 run("testApkOnlyMultipleStagedPartialRollback_Phase3_Confirm"); 129 } 130 131 /** 132 * Tests staged rollbacks involving only apex. 133 */ 134 @Test testApexOnlyStagedRollback()135 public void testApexOnlyStagedRollback() throws Exception { 136 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 137 138 run("testApexOnlyStagedRollback_Phase1_InstallFirst"); 139 getDevice().reboot(); 140 run("testApexOnlyStagedRollback_Phase2_InstallSecond"); 141 getDevice().reboot(); 142 run("testApexOnlyStagedRollback_Phase3_RollBack"); 143 getDevice().reboot(); 144 run("testApexOnlyStagedRollback_Phase4_Confirm"); 145 } 146 147 /** 148 * Tests staged rollbacks to system version involving only apex. 149 */ 150 @Test testApexOnlySystemVersionStagedRollback()151 public void testApexOnlySystemVersionStagedRollback() throws Exception { 152 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 153 154 run("testApexOnlySystemVersionStagedRollback_Phase1_Install"); 155 getDevice().reboot(); 156 run("testApexOnlySystemVersionStagedRollback_Phase2_RollBack"); 157 getDevice().reboot(); 158 run("testApexOnlySystemVersionStagedRollback_Phase3_Confirm"); 159 } 160 161 /** 162 * Tests staged rollbacks involving apex and apk. 163 */ 164 @Test testApexAndApkStagedRollback()165 public void testApexAndApkStagedRollback() throws Exception { 166 assumeSystemUser(); 167 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 168 169 run("testApexAndApkStagedRollback_Phase1_InstallFirst"); 170 getDevice().reboot(); 171 run("testApexAndApkStagedRollback_Phase2_InstallSecond"); 172 getDevice().reboot(); 173 run("testApexAndApkStagedRollback_Phase3_RollBack"); 174 getDevice().reboot(); 175 run("testApexAndApkStagedRollback_Phase4_Confirm"); 176 } 177 assumeSystemUser()178 private void assumeSystemUser() throws Exception { 179 String systemUser = "0"; 180 assumeThat("Current user is not system user", 181 getDevice().executeShellCommand("am get-current-user").trim(), equalTo(systemUser)); 182 } 183 184 /** 185 * Tests that apex update expires existing rollbacks for that apex. 186 */ 187 @Test testApexRollbackExpiration()188 public void testApexRollbackExpiration() throws Exception { 189 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 190 191 run("testApexRollbackExpiration_Phase1_InstallFirst"); 192 getDevice().reboot(); 193 run("testApexRollbackExpiration_Phase2_InstallSecond"); 194 getDevice().reboot(); 195 run("testApexRollbackExpiration_Phase3_Confirm"); 196 } 197 198 /** 199 * Tests staged rollbacks involving apex with rotated keys. 200 */ 201 @Test testApexKeyRotationStagedRollback()202 public void testApexKeyRotationStagedRollback() throws Exception { 203 assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported()); 204 205 run("testApexKeyRotationStagedRollback_Phase1_Install"); 206 getDevice().reboot(); 207 run("testApexKeyRotationStagedRollback_Phase2_RollBack"); 208 getDevice().reboot(); 209 run("testApexKeyRotationStagedRollback_Phase3_Confirm"); 210 } 211 212 /** 213 * Tests installer B can't rollback a package installed by A. 214 */ 215 @Test testApkRollbackByAnotherInstaller()216 public void testApkRollbackByAnotherInstaller() throws Exception { 217 run("testApkRollbackByAnotherInstaller_Phase1_FirstInstaller"); 218 run2("testApkRollbackByAnotherInstaller_Phase2_SecondInstaller"); 219 } 220 221 /** 222 * Tests that existing staged sessions are failed when rollback is committed 223 */ 224 @Test testRollbackFailsOtherSessions()225 public void testRollbackFailsOtherSessions() throws Exception { 226 assumeTrue("Device does not support file-system checkpoint", 227 mHostUtils.isCheckpointSupported()); 228 229 run("testRollbackFailsOtherSessions_Phase1_Install"); 230 getDevice().reboot(); 231 run("testRollbackFailsOtherSessions_Phase2_RollBack"); 232 getDevice().reboot(); 233 run("testRollbackFailsOtherSessions_Phase3_Confirm"); 234 } 235 236 /** 237 * Tests that simultaneous rollbacks both succeed - neither causes the other to fail. 238 */ 239 @Test testSimultaneousRollbacksBothSucceed()240 public void testSimultaneousRollbacksBothSucceed() throws Exception { 241 assumeTrue("Device does not support file-system checkpoint", 242 mHostUtils.isCheckpointSupported()); 243 244 run("testSimultaneousRollbacksBothSucceed_Phase1_Install"); 245 getDevice().reboot(); 246 run("testSimultaneousRollbacksBothSucceed_Phase2_RollBack"); 247 getDevice().reboot(); 248 run("testSimultaneousRollbacksBothSucceed_Phase3_Confirm"); 249 } 250 251 /** 252 * Tests that rollbacks are invalidated upon fingerprint changes. 253 */ 254 @Test testFingerprintChange()255 public void testFingerprintChange() throws Exception { 256 assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user"))); 257 258 try { 259 getDevice().executeShellCommand("setprop persist.pm.mock-upgrade true"); 260 261 run("testFingerprintChange_Phase1_Install"); 262 getDevice().reboot(); 263 run("testFingerprintChange_Phase2_Confirm"); 264 } finally { 265 getDevice().executeShellCommand("setprop persist.pm.mock-upgrade false"); 266 } 267 } 268 } 269