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         run("cleanUp");
85         mHostUtils.uninstallShimApexIfNecessary();
86     }
87 
88     /**
89      * Tests staged rollbacks involving only apks.
90      */
91     @Test
testApkOnlyStagedRollback()92     public void testApkOnlyStagedRollback() throws Exception {
93         run("testApkOnlyStagedRollback_Phase1_Install");
94         getDevice().reboot();
95         run("testApkOnlyStagedRollback_Phase2_RollBack");
96         getDevice().reboot();
97         run("testApkOnlyStagedRollback_Phase3_Confirm");
98     }
99 
100     /**
101      * Tests multiple staged rollbacks involving only apks.
102      */
103     @Test
testApkOnlyMultipleStagedRollback()104     public void testApkOnlyMultipleStagedRollback() throws Exception {
105         assumeTrue("Device does not support file-system checkpoint",
106                 mHostUtils.isCheckpointSupported());
107 
108         run("testApkOnlyMultipleStagedRollback_Phase1_Install");
109         getDevice().reboot();
110         run("testApkOnlyMultipleStagedRollback_Phase2_RollBack");
111         getDevice().reboot();
112         run("testApkOnlyMultipleStagedRollback_Phase3_Confirm");
113     }
114 
115     /**
116      * Tests multiple staged partial rollbacks involving only apks.
117      */
118     @Test
testApkOnlyMultipleStagedPartialRollback()119     public void testApkOnlyMultipleStagedPartialRollback() throws Exception {
120         assumeTrue("Device does not support file-system checkpoint",
121                 mHostUtils.isCheckpointSupported());
122 
123         run("testApkOnlyMultipleStagedPartialRollback_Phase1_Install");
124         getDevice().reboot();
125         run("testApkOnlyMultipleStagedPartialRollback_Phase2_RollBack");
126         getDevice().reboot();
127         run("testApkOnlyMultipleStagedPartialRollback_Phase3_Confirm");
128     }
129 
130     /**
131      * Tests staged rollbacks involving only apex.
132      */
133     @Test
testApexOnlyStagedRollback()134     public void testApexOnlyStagedRollback() throws Exception {
135         assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
136 
137         run("testApexOnlyStagedRollback_Phase1_InstallFirst");
138         getDevice().reboot();
139         run("testApexOnlyStagedRollback_Phase2_InstallSecond");
140         getDevice().reboot();
141         run("testApexOnlyStagedRollback_Phase3_RollBack");
142         getDevice().reboot();
143         run("testApexOnlyStagedRollback_Phase4_Confirm");
144     }
145 
146     /**
147      * Tests staged rollbacks to system version involving only apex.
148      */
149     @Test
testApexOnlySystemVersionStagedRollback()150     public void testApexOnlySystemVersionStagedRollback() throws Exception {
151         assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
152 
153         run("testApexOnlySystemVersionStagedRollback_Phase1_Install");
154         getDevice().reboot();
155         run("testApexOnlySystemVersionStagedRollback_Phase2_RollBack");
156         getDevice().reboot();
157         run("testApexOnlySystemVersionStagedRollback_Phase3_Confirm");
158     }
159 
160     /**
161      * Tests staged rollbacks involving apex and apk.
162      */
163     @Test
testApexAndApkStagedRollback()164     public void testApexAndApkStagedRollback() throws Exception {
165         assumeSystemUser();
166         assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
167 
168         run("testApexAndApkStagedRollback_Phase1_InstallFirst");
169         getDevice().reboot();
170         run("testApexAndApkStagedRollback_Phase2_InstallSecond");
171         getDevice().reboot();
172         run("testApexAndApkStagedRollback_Phase3_RollBack");
173         getDevice().reboot();
174         run("testApexAndApkStagedRollback_Phase4_Confirm");
175     }
176 
assumeSystemUser()177     private void assumeSystemUser() throws Exception {
178         String systemUser = "0";
179         assumeThat("Current user is not system user",
180                 getDevice().executeShellCommand("am get-current-user").trim(), equalTo(systemUser));
181     }
182 
183     /**
184      * Tests that apex update expires existing rollbacks for that apex.
185      */
186     @Test
testApexRollbackExpiration()187     public void testApexRollbackExpiration() throws Exception {
188         assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
189 
190         run("testApexRollbackExpiration_Phase1_InstallFirst");
191         getDevice().reboot();
192         run("testApexRollbackExpiration_Phase2_InstallSecond");
193         getDevice().reboot();
194         run("testApexRollbackExpiration_Phase3_Confirm");
195     }
196 
197     /**
198      * Tests staged rollbacks involving apex with rotated keys.
199      */
200     @Test
testApexKeyRotationStagedRollback()201     public void testApexKeyRotationStagedRollback() throws Exception {
202         assumeTrue("Device does not support updating APEX", mHostUtils.isApexUpdateSupported());
203 
204         run("testApexKeyRotationStagedRollback_Phase1_Install");
205         getDevice().reboot();
206         run("testApexKeyRotationStagedRollback_Phase2_RollBack");
207         getDevice().reboot();
208         run("testApexKeyRotationStagedRollback_Phase3_Confirm");
209     }
210 
211     /**
212      * Tests installer B can't rollback a package installed by A.
213      */
214     @Test
testApkRollbackByAnotherInstaller()215     public void testApkRollbackByAnotherInstaller() throws Exception {
216         run("testApkRollbackByAnotherInstaller_Phase1_FirstInstaller");
217         run2("testApkRollbackByAnotherInstaller_Phase2_SecondInstaller");
218     }
219 
220     /**
221      * Tests that existing staged sessions are failed when rollback is committed
222      */
223     @Test
testRollbackFailsOtherSessions()224     public void testRollbackFailsOtherSessions() throws Exception {
225         assumeTrue("Device does not support file-system checkpoint",
226                 mHostUtils.isCheckpointSupported());
227 
228         run("testRollbackFailsOtherSessions_Phase1_Install");
229         getDevice().reboot();
230         run("testRollbackFailsOtherSessions_Phase2_RollBack");
231         getDevice().reboot();
232         run("testRollbackFailsOtherSessions_Phase3_Confirm");
233     }
234 
235     /**
236      * Tests that simultaneous rollbacks both succeed - neither causes the other to fail.
237      */
238     @Test
testSimultaneousRollbacksBothSucceed()239     public void testSimultaneousRollbacksBothSucceed() throws Exception {
240         assumeTrue("Device does not support file-system checkpoint",
241                 mHostUtils.isCheckpointSupported());
242 
243         run("testSimultaneousRollbacksBothSucceed_Phase1_Install");
244         getDevice().reboot();
245         run("testSimultaneousRollbacksBothSucceed_Phase2_RollBack");
246         getDevice().reboot();
247         run("testSimultaneousRollbacksBothSucceed_Phase3_Confirm");
248     }
249 
250     /**
251      * Tests that rollbacks are invalidated upon fingerprint changes.
252      */
253     @Test
testFingerprintChange()254     public void testFingerprintChange() throws Exception {
255         assumeThat(getDevice().getBuildFlavor(), not(endsWith("-user")));
256 
257         try {
258             getDevice().executeShellCommand("setprop persist.pm.mock-upgrade true");
259 
260             run("testFingerprintChange_Phase1_Install");
261             getDevice().reboot();
262             run("testFingerprintChange_Phase2_Confirm");
263         } finally {
264             getDevice().executeShellCommand("setprop persist.pm.mock-upgrade false");
265         }
266     }
267 }
268