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.app; 18 19 import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import android.Manifest; 24 import android.content.rollback.RollbackInfo; 25 26 import androidx.test.InstrumentationRegistry; 27 28 import com.android.cts.rollback.lib.Install; 29 import com.android.cts.rollback.lib.Rollback; 30 import com.android.cts.rollback.lib.TestApp; 31 import com.android.cts.rollback.lib.Utils; 32 33 import org.junit.After; 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 import java.io.IOException; 40 41 /** 42 * On-device helper test methods used for host-driven rollback tests. 43 */ 44 @RunWith(JUnit4.class) 45 public class HostTestHelper { 46 47 /** 48 * Adopts common permissions needed to test rollbacks. 49 */ 50 @Before setup()51 public void setup() throws InterruptedException, IOException { 52 InstrumentationRegistry.getInstrumentation().getUiAutomation() 53 .adoptShellPermissionIdentity( 54 Manifest.permission.INSTALL_PACKAGES, 55 Manifest.permission.DELETE_PACKAGES, 56 Manifest.permission.TEST_MANAGE_ROLLBACKS); 57 } 58 59 /** 60 * Drops adopted shell permissions. 61 */ 62 @After teardown()63 public void teardown() throws InterruptedException, IOException { 64 InstrumentationRegistry.getInstrumentation().getUiAutomation() 65 .dropShellPermissionIdentity(); 66 } 67 68 69 /** 70 * Test rollbacks of staged installs involving only apks. 71 * Commits TestApp.A2 as a staged install with rollback enabled. 72 */ 73 @Test testApkOnlyEnableRollback()74 public void testApkOnlyEnableRollback() throws Exception { 75 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(-1); 76 77 Install.single(TestApp.A1).commit(); 78 Install.single(TestApp.A2).setStaged().setEnableRollback().commit(); 79 80 // At this point, the host test driver will reboot the device and run 81 // testApkOnlyCommitRollback(). 82 } 83 84 /** 85 * Test rollbacks of staged installs involving only apks. 86 * Confirms a staged rollback is available for TestApp.A2 and commits the 87 * rollback. 88 */ 89 @Test testApkOnlyCommitRollback()90 public void testApkOnlyCommitRollback() throws Exception { 91 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2); 92 RollbackInfo available = Utils.getAvailableRollback(TestApp.A); 93 assertThat(available).isStaged(); 94 assertThat(available).packagesContainsExactly( 95 Rollback.from(TestApp.A2).to(TestApp.A1)); 96 assertThat(Utils.getCommittedRollback(TestApp.A)).isNull(); 97 98 Utils.rollback(available.getRollbackId(), TestApp.A2); 99 RollbackInfo committed = Utils.getCommittedRollback(TestApp.A); 100 assertThat(committed).hasRollbackId(available.getRollbackId()); 101 assertThat(committed).isStaged(); 102 assertThat(committed).packagesContainsExactly( 103 Rollback.from(TestApp.A2).to(TestApp.A1)); 104 assertThat(committed).causePackagesContainsExactly(TestApp.A2); 105 assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1); 106 107 // Note: The app is not rolled back until after the rollback is staged 108 // and the device has been rebooted. 109 Utils.waitForSessionReady(committed.getCommittedSessionId()); 110 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2); 111 112 // At this point, the host test driver will reboot the device and run 113 // testApkOnlyConfirmRollback(). 114 } 115 116 /** 117 * Test rollbacks of staged installs involving only apks. 118 * Confirms TestApp.A2 was rolled back. 119 */ 120 @Test testApkOnlyConfirmRollback()121 public void testApkOnlyConfirmRollback() throws Exception { 122 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1); 123 124 RollbackInfo committed = Utils.getCommittedRollback(TestApp.A); 125 assertThat(committed).isStaged(); 126 assertThat(committed).packagesContainsExactly( 127 Rollback.from(TestApp.A2).to(TestApp.A1)); 128 assertThat(committed).causePackagesContainsExactly(TestApp.A2); 129 assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1); 130 } 131 132 /** 133 * Test rollbacks of staged installs involving only apex. 134 * Install first version phase. 135 * 136 * <p> We can't rollback to version 1, which is already installed, so we start by installing 137 * version 2. The test ultimately rolls back from 3 to 2. 138 */ 139 @Test testApexOnlyInstallFirstVersion()140 public void testApexOnlyInstallFirstVersion() throws Exception { 141 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1); 142 143 Install.single(TestApp.Apex2).setStaged().commit(); 144 145 // At this point, the host test driver will reboot the device and run 146 // testApexOnlyEnableRollback(). 147 } 148 149 /** 150 * Test rollbacks of staged installs involving only apex. 151 * Enable rollback phase. 152 */ 153 @Test testApexOnlyEnableRollback()154 public void testApexOnlyEnableRollback() throws Exception { 155 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2); 156 Install.single(TestApp.Apex3).setStaged().setEnableRollback().commit(); 157 158 // At this point, the host test driver will reboot the device and run 159 // testApexOnlyCommitRollback(). 160 } 161 162 /** 163 * Test rollbacks of staged installs involving only apex. 164 * Commit rollback phase. 165 */ 166 @Test testApexOnlyCommitRollback()167 public void testApexOnlyCommitRollback() throws Exception { 168 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3); 169 RollbackInfo available = Utils.getAvailableRollback(TestApp.Apex); 170 assertThat(available).isStaged(); 171 assertThat(available).packagesContainsExactly( 172 Rollback.from(TestApp.Apex3).to(TestApp.Apex2)); 173 174 Utils.rollback(available.getRollbackId(), TestApp.Apex3); 175 RollbackInfo committed = Utils.getCommittedRollbackById(available.getRollbackId()); 176 assertThat(committed).isNotNull(); 177 assertThat(committed).isStaged(); 178 assertThat(committed).packagesContainsExactly( 179 Rollback.from(TestApp.Apex3).to(TestApp.Apex2)); 180 assertThat(committed).causePackagesContainsExactly(TestApp.Apex3); 181 assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1); 182 183 // Note: The app is not rolled back until after the rollback is staged 184 // and the device has been rebooted. 185 Utils.waitForSessionReady(committed.getCommittedSessionId()); 186 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3); 187 188 // At this point, the host test driver will reboot the device and run 189 // testApexOnlyConfirmRollback(). 190 } 191 192 /** 193 * Test rollbacks of staged installs involving only apex. 194 * Confirm rollback phase. 195 */ 196 @Test testApexOnlyConfirmRollback()197 public void testApexOnlyConfirmRollback() throws Exception { 198 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2); 199 200 // Rollback data for shim apex will remain in storage since the apex cannot be completely 201 // removed and thus the rollback data won't be expired. Unfortunately, we can't also delete 202 // the rollback data manually from storage. 203 204 // At this point, the host test driver will reboot the device to complete the uninstall. 205 } 206 207 208 /** 209 * Test rollbacks of staged installs involving apex and apk. 210 * Install first version phase. 211 * 212 * <p> See {@link #testApexOnlyInstallFirstVersion()} 213 */ 214 @Test testApexAndApkInstallFirstVersion()215 public void testApexAndApkInstallFirstVersion() throws Exception { 216 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1); 217 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(-1); 218 219 Install.multi(TestApp.Apex2, TestApp.A1).setStaged().commit(); 220 221 // At this point, the host test driver will reboot the device and run 222 // testApexOnlyEnableRollback(). 223 } 224 225 /** 226 * Test rollbacks of staged installs involving apex and apk. 227 * Enable rollback phase. 228 */ 229 @Test testApexAndApkEnableRollback()230 public void testApexAndApkEnableRollback() throws Exception { 231 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2); 232 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(1); 233 Install.multi(TestApp.Apex3, TestApp.A2).setStaged().setEnableRollback().commit(); 234 235 // At this point, the host test driver will reboot the device and run 236 // testApexOnlyCommitRollback(). 237 } 238 239 /** 240 * Test rollbacks of staged installs involving apex and apk. 241 * Commit rollback phase. 242 */ 243 @Test testApexAndApkCommitRollback()244 public void testApexAndApkCommitRollback() throws Exception { 245 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3); 246 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2); 247 RollbackInfo available = Utils.getAvailableRollback(TestApp.Apex); 248 assertThat(available).isStaged(); 249 assertThat(available).packagesContainsExactly( 250 Rollback.from(TestApp.Apex3).to(TestApp.Apex2), 251 Rollback.from(TestApp.A2).to(TestApp.A1)); 252 253 Utils.rollback(available.getRollbackId(), TestApp.Apex3, TestApp.A2); 254 RollbackInfo committed = Utils.getCommittedRollback(TestApp.A); 255 assertThat(committed).isNotNull(); 256 assertThat(committed).isStaged(); 257 assertThat(committed).packagesContainsExactly( 258 Rollback.from(TestApp.Apex3).to(TestApp.Apex2), 259 Rollback.from(TestApp.A2).to(TestApp.A1)); 260 assertThat(committed).causePackagesContainsExactly(TestApp.Apex3, TestApp.A2); 261 assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1); 262 263 // Note: The app is not rolled back until after the rollback is staged 264 // and the device has been rebooted. 265 Utils.waitForSessionReady(committed.getCommittedSessionId()); 266 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3); 267 assertThat(Utils.getInstalledVersion(TestApp.A)).isEqualTo(2); 268 269 // At this point, the host test driver will reboot the device and run 270 // testApexOnlyConfirmRollback(). 271 } 272 273 /** 274 * Test rollbacks of staged installs involving apex and apk. 275 * Confirm rollback phase. 276 */ 277 @Test testApexAndApkConfirmRollback()278 public void testApexAndApkConfirmRollback() throws Exception { 279 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2); 280 281 RollbackInfo committed = Utils.getCommittedRollback(TestApp.A); 282 assertThat(committed).isStaged(); 283 assertThat(committed).packagesContainsExactly( 284 Rollback.from(TestApp.Apex3).to(TestApp.Apex2), 285 Rollback.from(TestApp.A2).to(TestApp.A1)); 286 assertThat(committed).causePackagesContainsExactly(TestApp.Apex3, TestApp.A2); 287 assertThat(committed.getCommittedSessionId()).isNotEqualTo(-1); 288 289 // Rollback data for shim apex will remain in storage since the apex cannot be completely 290 // removed and thus the rollback data won't be expired. Unfortunately, we can't also delete 291 // the rollback data manually from storage due to SEPolicy rules. 292 293 // At this point, the host test driver will reboot the device to complete the uninstall. 294 } 295 296 /** 297 * Tests that apex update expires existing rollbacks for that apex. 298 * Enable rollback phase. 299 */ 300 @Test testApexRollbackExpirationEnableRollback()301 public void testApexRollbackExpirationEnableRollback() throws Exception { 302 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(1); 303 304 Install.single(TestApp.Apex2).setStaged().setEnableRollback().commit(); 305 306 // At this point, the host test driver will reboot the device and run 307 // testApexRollbackExpirationUpdateApex(). 308 } 309 310 /** 311 * Tests that apex update expires existing rollbacks for that apex. 312 * Update apex phase. 313 */ 314 @Test testApexRollbackExpirationUpdateApex()315 public void testApexRollbackExpirationUpdateApex() throws Exception { 316 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(2); 317 assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNotNull(); 318 Install.single(TestApp.Apex3).setStaged().commit(); 319 320 // At this point, the host test driver will reboot the device and run 321 // testApexRollbackExpirationConfirmExpiration(). 322 } 323 324 /** 325 * Tests that apex update expires existing rollbacks for that apex. 326 * Confirm expiration phase. 327 */ 328 @Test testApexRollbackExpirationConfirmExpiration()329 public void testApexRollbackExpirationConfirmExpiration() throws Exception { 330 assertThat(Utils.getInstalledVersion(TestApp.Apex)).isEqualTo(3); 331 assertThat(Utils.getAvailableRollback(TestApp.Apex)).isNull(); 332 } 333 } 334