• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package android.host.multiuser;
17 
18 import static com.google.common.truth.Truth.assertWithMessage;
19 
20 import static org.junit.Assume.assumeTrue;
21 
22 import android.platform.test.annotations.LargeTest;
23 import android.platform.test.annotations.Presubmit;
24 
25 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
26 import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
27 
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 
32 /**
33  * Test verifies that ephemeral users are removed after switched away and after reboot.
34  *
35  * Run: atest android.host.multiuser.EphemeralTest
36  */
37 @LargeTest
38 @RunWith(DeviceJUnit4ClassRunner.class)
39 public class EphemeralTest extends BaseMultiUserTest {
40 
41     private static final String TEST_APP_PKG_NAME = "com.android.cts.multiuser";
42     private static final String TEST_APP_PKG_APK = "CtsMultiuserApp.apk";
43 
44     private static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
45 
46     // Values below were copied from UserManager
47     private static final int REMOVE_RESULT_REMOVED = 0;
48     private static final int REMOVE_RESULT_DEFERRED = 1;
49     private static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2;
50     private static final String DISALLOW_REMOVE_USER = "no_remove_user";
51 
52     @Rule
53     public final SupportsMultiUserRule mSupportsMultiUserRule = new SupportsMultiUserRule(this);
54 
55     /** Test to verify ephemeral user is removed after switch out to another user. */
56     @Presubmit
57     @Test
testSwitchAndRemoveEphemeralUser()58     public void testSwitchAndRemoveEphemeralUser() throws Exception {
59         final int ephemeralUserId = createEphemeralUser();
60 
61         assertSwitchToUser(ephemeralUserId);
62         assertSwitchToUser(mInitialUserId);
63         waitForUserRemove(ephemeralUserId);
64         assertUserNotPresent(ephemeralUserId);
65     }
66 
67     /** Test to verify ephemeral user is removed after reboot. */
68     @Presubmit
69     @Test
testRebootAndRemoveEphemeralUser()70     public void testRebootAndRemoveEphemeralUser() throws Exception {
71         final int ephemeralUserId = createEphemeralUser();
72 
73         assertSwitchToUser(ephemeralUserId);
74         getDevice().reboot();
75         assertUserNotPresent(ephemeralUserId);
76     }
77 
78     /**
79      * Test to verify that an ephemeral user, with an account, is safely removed after rebooting
80      * from it.
81      */
82     @Test
testRebootAndRemoveEphemeralUser_withAccount()83     public void testRebootAndRemoveEphemeralUser_withAccount() throws Exception {
84         final int ephemeralUserId = createEphemeralUser();
85         assertSwitchToUser(ephemeralUserId);
86 
87         installPackageAsUser(
88                 TEST_APP_PKG_APK, /* grantPermissions= */true, ephemeralUserId, /* options= */"-t");
89         assertWithMessage("isPackageInstalled(app=%s, user=%s)", TEST_APP_PKG_APK, ephemeralUserId)
90                 .that(getDevice().isPackageInstalled(TEST_APP_PKG_NAME,
91                         String.valueOf(ephemeralUserId)))
92                 .isTrue();
93 
94         final boolean appResult = runDeviceTests(getDevice(),
95                 TEST_APP_PKG_NAME,
96                 TEST_APP_PKG_NAME + ".AccountCreator",
97                 "addMockAccountForCurrentUser",
98                 ephemeralUserId,
99                 5 * 60 * 1000L /* ms */);
100         assertWithMessage("Device-side test passing").that(appResult).isTrue();
101 
102         getDevice().reboot();
103         assertUserNotPresent(ephemeralUserId);
104     }
105 
106     /**
107      * Test to verify that
108      * {@link android.os.UserManager#removeUserWhenPossible(UserHandle, boolean)} immediately
109      * removes a user that isn't running.
110      * <p>
111      * Indirectly executed by means of the --set-ephemeral-if-in-use flag
112      */
113     @Presubmit
114     @Test
testRemoveUserWhenPossible_nonRunningUserRemoved()115     public void testRemoveUserWhenPossible_nonRunningUserRemoved() throws Exception {
116         final int userId = createUser();
117 
118         executeRemoveUserWhenPossible(userId, /* expectedResult= */ REMOVE_RESULT_REMOVED);
119 
120         assertUserNotPresent(userId);
121     }
122 
123     /**
124      * Test to verify that
125      * {@link android.os.UserManager#removeUserWhenPossible(UserHandle, boolean)} sets the current
126      * user to ephemeral and removes the user after user switch.
127      * <p>
128      * Indirectly executed by means of the --set-ephemeral-if-in-use flag
129      */
130     @Presubmit
131     @Test
testRemoveUserWhenPossible_currentUserSetEphemeral_removeAfterSwitch()132     public void testRemoveUserWhenPossible_currentUserSetEphemeral_removeAfterSwitch()
133             throws Exception {
134         final int userId = createUser();
135 
136         assertSwitchToUser(userId);
137         executeRemoveUserWhenPossible(userId, /* expectedResult= */ REMOVE_RESULT_DEFERRED);
138         assertUserEphemeral(userId);
139 
140         assertSwitchToUser(mInitialUserId);
141         waitForUserRemove(userId);
142         assertUserNotPresent(userId);
143     }
144 
145     /**
146      * Test to verify that
147      * {@link android.os.UserManager#removeUserWhenPossible(UserHandle, boolean)} sets the current
148      * user to ephemeral and removes that user after reboot.
149      * <p>
150      * Indirectly executed by means of the --set-ephemeral-if-in-use flag
151      */
152     @Presubmit
153     @Test
testRemoveUserWhenPossible_currentUserSetEphemeral_removeAfterReboot()154     public void testRemoveUserWhenPossible_currentUserSetEphemeral_removeAfterReboot()
155             throws Exception {
156         final int userId = createUser();
157 
158         assertSwitchToUser(userId);
159         executeRemoveUserWhenPossible(userId, /* expectedResult= */ REMOVE_RESULT_DEFERRED);
160         assertUserEphemeral(userId);
161 
162         getDevice().reboot();
163         assertUserNotPresent(userId);
164     }
165 
166     /**
167      * Test to verify that
168      * {@link android.os.UserManager#removeUserWhenPossible(UserHandle, boolean)} works correctly
169      * when a DPC set the {@code no_remove_user} restriction in the current user.
170      */
171     @Presubmit
172     @Test
testRemoveUserWhenPossible_devicePolicyIsSet()173     public void testRemoveUserWhenPossible_devicePolicyIsSet() throws Exception {
174         assumeTrue("Test requires device with device admin support",
175                 getDevice().hasFeature(FEATURE_DEVICE_ADMIN));
176         installPackage(DpcCommander.PKG_APK, /* options= */ "-t");
177         assertWithMessage("isPackageInstalled(%s)", DpcCommander.PKG_APK)
178                 .that(getDevice().isPackageInstalled(DpcCommander.PKG_NAME))
179                 .isTrue();
180 
181         final DpcCommander dpc = DpcCommander.forCurrentUser(getDevice());
182         final int userId = createUser();
183 
184         dpc.setProfileOwner();
185         try {
186             dpc.addUserRestriction(DISALLOW_REMOVE_USER);
187             try {
188                 executeRemoveUserWhenPossible(userId, /* overrideDevicePolicy= */ false,
189                         /* expectedResult= */ REMOVE_RESULT_ERROR_USER_RESTRICTION);
190                 assertUserPresent(userId);
191 
192                 executeRemoveUserWhenPossible(userId, /* overrideDevicePolicy= */ true,
193                         /* expectedResult= */ REMOVE_RESULT_REMOVED);
194                 assertUserNotPresent(userId);
195             } finally {
196                 dpc.clearUserRestriction(DISALLOW_REMOVE_USER);
197             }
198         } finally {
199             dpc.removeActiveAdmin();
200         }
201     }
202 
executeRemoveUserWhenPossible(int userId, int expectedResult)203     private void executeRemoveUserWhenPossible(int userId, int expectedResult) throws Exception {
204         executeRemoveUserWhenPossible(userId, /* overrideDevicePolicy= */ false, expectedResult);
205     }
206 
executeRemoveUserWhenPossible(int userId, boolean overrideDevicePolicy, int expectedResult)207     private void executeRemoveUserWhenPossible(int userId, boolean overrideDevicePolicy,
208             int expectedResult) throws Exception {
209         installPackage(TEST_APP_PKG_APK, /* options= */"-t");
210         assertWithMessage("isPackageInstalled(%s)", TEST_APP_PKG_APK)
211                 .that(getDevice().isPackageInstalled(TEST_APP_PKG_NAME))
212                 .isTrue();
213 
214         DeviceTestRunOptions options = new DeviceTestRunOptions(TEST_APP_PKG_NAME)
215                 .setDevice(getDevice())
216                 .setTestClassName(TEST_APP_PKG_NAME + ".UserOperationsTest")
217                 .setTestMethodName("removeUserWhenPossibleDeviceSide")
218                 .addInstrumentationArg("userId", String.valueOf(userId))
219                 .addInstrumentationArg("overrideDevicePolicy", String.valueOf(overrideDevicePolicy))
220                 .addInstrumentationArg("expectedResult", String.valueOf(expectedResult));
221         final boolean appResult = runDeviceTests(options);
222         assertWithMessage("Device-side test passing").that(appResult).isTrue();
223     }
224 
assertUserEphemeral(int userId)225     private void assertUserEphemeral(int userId) throws Exception {
226         assertUserPresent(userId);
227         assertWithMessage("User ID %s should be flagged as ephemeral", userId)
228                 .that(getDevice().getUserInfos().get(userId).isEphemeral()).isTrue();
229     }
230 
createUser()231     private int createUser() throws Exception {
232         return createUser(/* isGuest= */ false, /* isEphemeral= */ false);
233     }
234 
createEphemeralUser()235     private int createEphemeralUser() throws Exception {
236         return createUser(/* isGuest= */ false, /* isEphemeral= */ true);
237     }
238 
createUser(boolean isGuest, boolean isEphemeral)239     private int createUser(boolean isGuest, boolean isEphemeral) throws Exception {
240         final String name = "TestUser_" + System.currentTimeMillis();
241         try {
242             return getDevice().createUser(name, isGuest, isEphemeral);
243         } catch (Exception e) {
244             throw new IllegalStateException(String.format(
245                     "Failed to create user (name=%s, isGuest=%s, isEphemeral=%s)",
246                     name, isGuest, isEphemeral), e);
247         }
248     }
249 }
250