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