1 /* 2 * Copyright (C) 2016 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.deviceowner; 18 19 import static android.os.UserManager.USER_OPERATION_SUCCESS; 20 21 import static com.google.common.truth.Truth.assertWithMessage; 22 23 import static org.testng.Assert.expectThrows; 24 25 import android.app.ActivityManager; 26 import android.app.Service; 27 import android.app.admin.DeviceAdminReceiver; 28 import android.app.admin.DevicePolicyManager; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.ServiceConnection; 33 import android.content.pm.PackageManager; 34 import android.os.Build; 35 import android.os.IBinder; 36 import android.os.PersistableBundle; 37 import android.os.RemoteException; 38 import android.os.SystemClock; 39 import android.os.UserHandle; 40 import android.os.UserManager; 41 import android.provider.Settings; 42 import android.util.DebugUtils; 43 import android.util.Log; 44 45 import com.android.compatibility.common.util.SystemUtil; 46 47 import java.lang.reflect.InvocationTargetException; 48 import java.lang.reflect.Method; 49 import java.util.Collections; 50 import java.util.HashSet; 51 import java.util.Iterator; 52 import java.util.List; 53 import java.util.Set; 54 import java.util.concurrent.Semaphore; 55 import java.util.concurrent.TimeUnit; 56 import java.util.function.Predicate; 57 import java.util.stream.Collectors; 58 59 /** 60 * Test {@link DevicePolicyManager#createAndManageUser}. 61 */ 62 public class CreateAndManageUserTest extends BaseDeviceOwnerTest { 63 private static final String TAG = "CreateAndManageUserTest"; 64 65 private static final int BROADCAST_TIMEOUT = 300_000; 66 67 private static final String AFFILIATION_ID = "affiliation.id"; 68 private static final String EXTRA_AFFILIATION_ID = "affiliationIdExtra"; 69 private static final String EXTRA_CURRENT_USER_PACKAGES = "currentUserPackages"; 70 private static final String EXTRA_METHOD_NAME = "methodName"; 71 private static final long ON_ENABLED_TIMEOUT_SECONDS = 120; 72 73 @Override tearDown()74 protected void tearDown() throws Exception { 75 mDevicePolicyManager.clearUserRestriction(getWho(), UserManager.DISALLOW_ADD_USER); 76 mDevicePolicyManager.clearUserRestriction(getWho(), UserManager.DISALLOW_REMOVE_USER); 77 super.tearDown(); 78 } 79 testCreateAndManageUser()80 public void testCreateAndManageUser() throws Exception { 81 UserHandle userHandle = createAndManageUser(); 82 83 assertWithMessage("New user").that(userHandle).isNotNull(); 84 } 85 testCreateAndManageUser_MaxUsers()86 public void testCreateAndManageUser_MaxUsers() throws Exception { 87 UserManager.UserOperationException e = expectThrows( 88 UserManager.UserOperationException.class, () -> createAndManageUser()); 89 90 assertUserOperationResult(e.getUserOperationResult(), 91 UserManager.USER_OPERATION_ERROR_MAX_USERS, 92 "user creation when max users is reached"); 93 } 94 95 @SuppressWarnings("unused") assertSkipSetupWizard(Context context, DevicePolicyManager devicePolicyManager, ComponentName componentName)96 private static void assertSkipSetupWizard(Context context, 97 DevicePolicyManager devicePolicyManager, ComponentName componentName) throws Exception { 98 assertWithMessage("user setup settings (%s)", Settings.Secure.USER_SETUP_COMPLETE) 99 .that(Settings.Secure.getInt(context.getContentResolver(), 100 Settings.Secure.USER_SETUP_COMPLETE)) 101 .isEqualTo(1); 102 } 103 testCreateAndManageUser_SkipSetupWizard()104 public void testCreateAndManageUser_SkipSetupWizard() throws Exception { 105 runCrossUserVerification(DevicePolicyManager.SKIP_SETUP_WIZARD, "assertSkipSetupWizard"); 106 107 PrimaryUserService.assertCrossUserCallArrived(); 108 } 109 testCreateAndManageUser_GetSecondaryUsers()110 public void testCreateAndManageUser_GetSecondaryUsers() throws Exception { 111 UserHandle newUserHandle = createAndManageUser(); 112 113 List<UserHandle> secondaryUsers = mDevicePolicyManager.getSecondaryUsers(getWho()); 114 if (isHeadlessSystemUserMode()) { 115 assertWithMessage("secondary users").that(secondaryUsers) 116 .containsExactly(getCurrentUser(), newUserHandle); 117 } else { 118 assertWithMessage("secondary users").that(secondaryUsers) 119 .containsExactly(newUserHandle); 120 } 121 } 122 testCreateAndManageUser_SwitchUser()123 public void testCreateAndManageUser_SwitchUser() throws Exception { 124 UserHandle userHandle = createAndManageUser(); 125 126 List<UserHandle> usersOnBroadcasts = switchUserAndWaitForBroadcasts(userHandle); 127 128 assertWithMessage("user on broadcasts").that(usersOnBroadcasts).containsExactly(userHandle, 129 userHandle); 130 } 131 testCreateAndManageUser_CannotStopCurrentUser()132 public void testCreateAndManageUser_CannotStopCurrentUser() throws Exception { 133 UserHandle userHandle = createAndManageUser(); 134 135 switchUserAndWaitForBroadcasts(userHandle); 136 137 stopUserAndCheckResult(userHandle, UserManager.USER_OPERATION_ERROR_CURRENT_USER); 138 } 139 testCreateAndManageUser_StartInBackground()140 public void testCreateAndManageUser_StartInBackground() throws Exception { 141 UserHandle userHandle = createAndManageUser(); 142 143 List<UserHandle> usersOnBroadcasts = startUserInBackgroundAndWaitForBroadcasts(userHandle); 144 145 assertWithMessage("user on broadcasts").that(usersOnBroadcasts).containsExactly(userHandle); 146 } 147 testCreateAndManageUser_StartInBackground_MaxRunningUsers()148 public void testCreateAndManageUser_StartInBackground_MaxRunningUsers() throws Exception { 149 UserHandle userHandle = createAndManageUser(); 150 151 // Start user in background and should receive max running users error 152 startUserInBackgroundAndCheckResult(userHandle, 153 UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS); 154 } 155 testCreateAndManageUser_StopUser()156 public void testCreateAndManageUser_StopUser() throws Exception { 157 UserHandle userHandle = createAndManageUser(); 158 startUserInBackgroundAndWaitForBroadcasts(userHandle); 159 160 List<UserHandle> usersOnBroadcasts = stopUserAndWaitForBroadcasts(userHandle); 161 162 assertWithMessage("user on broadcasts").that(usersOnBroadcasts).containsExactly(userHandle); 163 } 164 testCreateAndManageUser_StopEphemeralUser_DisallowRemoveUser()165 public void testCreateAndManageUser_StopEphemeralUser_DisallowRemoveUser() throws Exception { 166 // Set DISALLOW_REMOVE_USER restriction 167 mDevicePolicyManager.addUserRestriction(getWho(), UserManager.DISALLOW_REMOVE_USER); 168 169 UserHandle userHandle = createAndManageUser(DevicePolicyManager.MAKE_USER_EPHEMERAL); 170 startUserInBackgroundAndWaitForBroadcasts(userHandle); 171 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 172 getContext(), 173 BasicAdminReceiver.ACTION_USER_STOPPED, BasicAdminReceiver.ACTION_USER_REMOVED); 174 175 callback.runAndUnregisterSelf( 176 () -> stopUserAndCheckResult(userHandle, USER_OPERATION_SUCCESS)); 177 178 // It's running just one operation (which issues a ACTION_USER_STOPPED), but as the 179 // user is ephemeral, it will be automatically removed (which issues a 180 // ACTION_USER_REMOVED). 181 assertWithMessage("user on broadcasts").that(callback.getUsersOnReceivedBroadcasts()) 182 .containsExactly(userHandle, userHandle); 183 } 184 185 @SuppressWarnings("unused") logoutUser(Context context, DevicePolicyManager devicePolicyManager, ComponentName componentName)186 private static void logoutUser(Context context, DevicePolicyManager devicePolicyManager, 187 ComponentName componentName) { 188 Log.d(TAG, "calling logoutUser() on user " + context.getUserId()); 189 int result = devicePolicyManager.logoutUser(componentName); 190 Log.d(TAG, "result: " + userOperationResultToString(result)); 191 assertUserOperationResult(result, USER_OPERATION_SUCCESS, "cannot logout user"); 192 } 193 clearLogoutUserIfNecessary()194 private void clearLogoutUserIfNecessary() throws Exception { 195 UserHandle userHandle = mDevicePolicyManager.getLogoutUser(); 196 Log.d(TAG, "clearLogoutUserIfNecessary(): logoutUser=" + userHandle); 197 if (userHandle == null) { 198 Log.d(TAG, "clearLogoutUserIfNecessary(): Saul Goodman!"); 199 return; 200 } 201 Log.w(TAG, "test started with a logout user (" + userHandle + "); logging out"); 202 int result = SystemUtil 203 .callWithShellPermissionIdentity(() -> mDevicePolicyManager.logoutUser()); 204 Log.d(TAG, "Result: " + userOperationResultToString(result)); 205 } 206 testCreateAndManageUser_LogoutUser()207 public void testCreateAndManageUser_LogoutUser() throws Exception { 208 clearLogoutUserIfNecessary(); 209 210 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 211 getContext(), 212 BasicAdminReceiver.ACTION_USER_STARTED, BasicAdminReceiver.ACTION_USER_STOPPED); 213 214 UserHandle userHandle = runCrossUserVerification(callback, 215 /* createAndManageUserFlags= */ 0, "logoutUser", /* currentUserPackages= */ null); 216 217 List<UserHandle> users = callback.getUsersOnReceivedBroadcasts(); 218 Log.d(TAG, "users on brodcast: " + users); 219 assertWithMessage("users on broadcast").that(users).containsExactly(userHandle, userHandle); 220 assertWithMessage("final logout user").that(mDevicePolicyManager.getLogoutUser()) 221 .isNull(); 222 } 223 testCreateAndManageUser_LogoutUser_systemApi()224 public void testCreateAndManageUser_LogoutUser_systemApi() throws Exception { 225 clearLogoutUserIfNecessary(); 226 227 UserHandle currentUser = getCurrentUser(); 228 UserHandle newUser = createAndManageUser(); 229 List<UserHandle> usersOnBroadcasts = switchUserAndWaitForBroadcasts(newUser); 230 Log.d(TAG, "users on switch broadcast: " + usersOnBroadcasts); 231 assertWithMessage("user on broadcasts").that(usersOnBroadcasts).containsExactly(newUser, 232 newUser); 233 assertWithMessage("logout user after switch").that(mDevicePolicyManager.getLogoutUser()) 234 .isEqualTo(currentUser); 235 236 List<UserHandle> users = logoutUserUsingSystemApiAndWaitForBroadcasts(); 237 Log.d(TAG, "users on logout broadcast: " + users); 238 assertWithMessage("users on broadcast").that(users).containsExactly(currentUser); 239 assertWithMessage("final logout user").that(mDevicePolicyManager.getLogoutUser()) 240 .isNull(); 241 } 242 testCreateAndManageUser_newUserDisclaimer()243 public void testCreateAndManageUser_newUserDisclaimer() throws Exception { 244 if (Build.IS_USER) { 245 Log.i(TAG, "Skipping testCreateAndManageUser_newUserDisclaimer on user build"); 246 // TODO(b/220386262): STOPSHIP re-enable once fixed and/or migrated to new testing infra 247 return; 248 } 249 250 // First check that the current user doesn't need it 251 UserHandle currentUser = getCurrentUser(); 252 Log.d(TAG, "Checking if current user (" + currentUser + ") is acked"); 253 assertWithMessage("isNewUserDisclaimerAcknowledged() for current user %s", currentUser) 254 .that(mDevicePolicyManager.isNewUserDisclaimerAcknowledged()).isTrue(); 255 256 UserHandle newUser = runCrossUserVerificationSwitchingUser("newUserDisclaimer"); 257 PrimaryUserService.assertCrossUserCallArrived(); 258 } 259 260 @SuppressWarnings("unused") newUserDisclaimer(Context context, DevicePolicyManager dpm, ComponentName componentName)261 private static void newUserDisclaimer(Context context, DevicePolicyManager dpm, 262 ComponentName componentName) { 263 264 // Need to wait until host-side granted INTERACT_ACROSS_USERS - use getCurrentUser() to 265 // check 266 int currentUserId = UserHandle.USER_NULL; 267 long maxAttempts = ON_ENABLED_TIMEOUT_SECONDS; 268 int waitingTimeMs = 1_000; 269 int attempt = 0; 270 int myUserId = context.getUserId(); 271 do { 272 attempt++; 273 try { 274 Log.d(TAG, "checking if user " + myUserId + " is current user"); 275 currentUserId = ActivityManager.getCurrentUser(); 276 Log.d(TAG, "currentUserId: " + currentUserId); 277 } catch (SecurityException e) { 278 Log.d(TAG, "Got exception (" + e.getMessage() + ") on attempt #" + attempt 279 + ", waiting " + waitingTimeMs + "ms until app is authorized"); 280 SystemClock.sleep(waitingTimeMs); 281 282 } 283 } while (currentUserId != myUserId && attempt < maxAttempts); 284 Log.v(TAG, "Out of the loop, let's hope for the best..."); 285 286 if (currentUserId == UserHandle.USER_NULL) { 287 throw new IllegalStateException("App could was not authorized to check current user"); 288 } 289 assertWithMessage("current user").that(currentUserId).isEqualTo(myUserId); 290 291 // Now that the plumbing is done, go back to work... 292 Log.d(TAG, "Calling isNewUserDisclaimerAcknowledged()"); 293 boolean isAcked = dpm.isNewUserDisclaimerAcknowledged(); 294 295 Log.d(TAG, "is it: " + isAcked); 296 assertWithMessage("isNewUserDisclaimerAcknowledged()").that(isAcked).isFalse(); 297 Log.d(TAG, "Calling acknowledgeNewUserDisclaimer()"); 298 dpm.acknowledgeNewUserDisclaimer(); 299 300 Log.d(TAG, "Calling isNewUserDisclaimerAcknowledged() again"); 301 isAcked = dpm.isNewUserDisclaimerAcknowledged(); 302 Log.d(TAG, "is it now: " + isAcked); 303 assertWithMessage("isNewUserDisclaimerAcknowledged()").that(isAcked).isTrue(); 304 } 305 306 @SuppressWarnings("unused") assertAffiliatedUser(Context context, DevicePolicyManager devicePolicyManager, ComponentName componentName)307 private static void assertAffiliatedUser(Context context, 308 DevicePolicyManager devicePolicyManager, ComponentName componentName) { 309 assertWithMessage("affiliated user").that(devicePolicyManager.isAffiliatedUser()).isTrue(); 310 } 311 testCreateAndManageUser_Affiliated()312 public void testCreateAndManageUser_Affiliated() throws Exception { 313 runCrossUserVerification(/* createAndManageUserFlags= */ 0, "assertAffiliatedUser"); 314 PrimaryUserService.assertCrossUserCallArrived(); 315 } 316 317 @SuppressWarnings("unused") assertEphemeralUser(Context context, DevicePolicyManager devicePolicyManager, ComponentName componentName)318 private static void assertEphemeralUser(Context context, 319 DevicePolicyManager devicePolicyManager, ComponentName componentName) { 320 assertWithMessage("ephemeral user").that(devicePolicyManager.isEphemeralUser(componentName)) 321 .isTrue(); 322 } 323 testCreateAndManageUser_Ephemeral()324 public void testCreateAndManageUser_Ephemeral() throws Exception { 325 runCrossUserVerification(DevicePolicyManager.MAKE_USER_EPHEMERAL, "assertEphemeralUser"); 326 PrimaryUserService.assertCrossUserCallArrived(); 327 } 328 329 @SuppressWarnings("unused") assertAllSystemAppsInstalled(Context context, DevicePolicyManager devicePolicyManager, ComponentName componentName, Set<String> preInstalledSystemPackages)330 private static void assertAllSystemAppsInstalled(Context context, 331 DevicePolicyManager devicePolicyManager, ComponentName componentName, 332 Set<String> preInstalledSystemPackages) { 333 Log.d(TAG, "assertAllSystemAppsInstalled(): checking apps for user " + context.getUserId()); 334 335 PackageManager packageManager = context.getPackageManager(); 336 // First get a set of installed package names 337 Set<String> installedPackageNames = packageManager 338 .getInstalledApplications(/* flags= */ 0) 339 .stream() 340 .map(applicationInfo -> applicationInfo.packageName) 341 .collect(Collectors.toSet()); 342 // Then filter all package names by those that are not installed 343 Set<String> uninstalledPackageNames = packageManager 344 .getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES) 345 .stream() 346 .map(applicationInfo -> applicationInfo.packageName) 347 .filter(((Predicate<String>) installedPackageNames::contains).negate()) 348 .collect(Collectors.toSet()); 349 350 // Finally, filter out packages that are not pre-installed for the user 351 Iterator<String> iterator = uninstalledPackageNames.iterator(); 352 while (iterator.hasNext()) { 353 String pkg = iterator.next(); 354 if (!preInstalledSystemPackages.contains(pkg)) { 355 Log.i(TAG, "assertAllSystemAppsInstalled(): ignoring package " + pkg 356 + " as it's not pre-installed on current user"); 357 iterator.remove(); 358 } 359 } 360 361 // Assert that all expected apps are installed 362 assertWithMessage("uninstalled system apps").that(uninstalledPackageNames).isEmpty(); 363 } 364 testCreateAndManageUser_LeaveAllSystemApps()365 public void testCreateAndManageUser_LeaveAllSystemApps() throws Exception { 366 int currentUserId = ActivityManager.getCurrentUser(); 367 // TODO: instead of hard-coding the user type, calling getPreInstallableSystemPackages(), 368 // and passing the packages to runCrossUserVerification() / assertAllSystemAppsInstalled(), 369 // ideally the later should call um.getPreInstallableSystemPackages(um.getUsertype()) 370 // (where um is the UserManager with the context of the newly created user), 371 // but currently the list of pre-installed apps is passed to the new user in the bundle. 372 // Given that these tests will be refactored anyways, it's not worth to try to change it. 373 String newUserType = UserManager.USER_TYPE_FULL_SECONDARY; 374 Set<String> preInstalledSystemPackages = SystemUtil.callWithShellPermissionIdentity( 375 () -> UserManager.get(mContext).getPreInstallableSystemPackages(newUserType)); 376 if (preInstalledSystemPackages != null) { 377 Log.d(TAG, preInstalledSystemPackages.size() + " pre-installed system apps for " 378 + "new user of type " + newUserType + ": " + preInstalledSystemPackages); 379 } else { 380 Log.d(TAG, "no pre-installed system apps allowlist for new user of type" + newUserType); 381 } 382 383 runCrossUserVerification(/* callback= */ null, 384 DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLED, "assertAllSystemAppsInstalled", 385 preInstalledSystemPackages); 386 PrimaryUserService.assertCrossUserCallArrived(); 387 } 388 runCrossUserVerification(int createAndManageUserFlags, String methodName)389 private UserHandle runCrossUserVerification(int createAndManageUserFlags, String methodName) 390 throws Exception { 391 return runCrossUserVerification(/* callback= */ null, createAndManageUserFlags, methodName, 392 /* currentUserPackages= */ null); 393 } 394 runCrossUserVerification(UserActionCallback callback, int createAndManageUserFlags, String methodName, Set<String> currentUserPackages)395 private UserHandle runCrossUserVerification(UserActionCallback callback, 396 int createAndManageUserFlags, String methodName, 397 Set<String> currentUserPackages) throws Exception { 398 return runCrossUserVerification(callback, createAndManageUserFlags, methodName, 399 /* switchUser= */ false, currentUserPackages); 400 } 401 runCrossUserVerificationSwitchingUser(String methodName)402 private UserHandle runCrossUserVerificationSwitchingUser(String methodName) throws Exception { 403 return runCrossUserVerification(/* callback= */ null, /* createAndManageUserFlags= */ 0, 404 methodName, /* switchUser= */ true, /* currentUserPackages= */ null); 405 } 406 runCrossUserVerification(UserActionCallback callback, int createAndManageUserFlags, String methodName, boolean switchUser, Set<String> currentUserPackages)407 private UserHandle runCrossUserVerification(UserActionCallback callback, 408 int createAndManageUserFlags, String methodName, boolean switchUser, 409 Set<String> currentUserPackages) throws Exception { 410 Log.d(TAG, "runCrossUserVerification(): flags=" + createAndManageUserFlags 411 + ", method=" + methodName); 412 String testUserName = "TestUser_" + System.currentTimeMillis(); 413 414 // Set affiliation id to allow communication. 415 mDevicePolicyManager.setAffiliationIds(getWho(), Collections.singleton(AFFILIATION_ID)); 416 417 ComponentName profileOwner = SecondaryUserAdminReceiver.getComponentName(getContext()); 418 419 // Pack the affiliation id in a bundle so the secondary user can get it. 420 PersistableBundle bundle = new PersistableBundle(); 421 bundle.putString(EXTRA_AFFILIATION_ID, AFFILIATION_ID); 422 bundle.putString(EXTRA_METHOD_NAME, methodName); 423 if (currentUserPackages != null) { 424 String[] array = new String[currentUserPackages.size()]; 425 currentUserPackages.toArray(array); 426 bundle.putStringArray(EXTRA_CURRENT_USER_PACKAGES, array); 427 } 428 429 Log.d(TAG, "creating user with PO " + profileOwner); 430 431 UserHandle userHandle = createAndManageUser(profileOwner, bundle, createAndManageUserFlags); 432 if (switchUser) { 433 switchUserAndWaitForBroadcasts(userHandle); 434 } else if (callback != null) { 435 startUserInBackgroundAndWaitForBroadcasts(callback, userHandle); 436 } else { 437 startUserInBackgroundAndWaitForBroadcasts(userHandle); 438 } 439 return userHandle; 440 } 441 442 // createAndManageUser should circumvent the DISALLOW_ADD_USER restriction testCreateAndManageUser_AddRestrictionSet()443 public void testCreateAndManageUser_AddRestrictionSet() throws Exception { 444 mDevicePolicyManager.addUserRestriction(getWho(), UserManager.DISALLOW_ADD_USER); 445 446 createAndManageUser(); 447 } 448 testCreateAndManageUser_RemoveRestrictionSet()449 public void testCreateAndManageUser_RemoveRestrictionSet() throws Exception { 450 mDevicePolicyManager.addUserRestriction(getWho(), UserManager.DISALLOW_REMOVE_USER); 451 452 UserHandle userHandle = createAndManageUser(); 453 454 // When the device owner itself has set the user restriction, it should still be allowed 455 // to remove a user. 456 List<UserHandle> usersOnBroadcasts = removeUserAndWaitForBroadcasts(userHandle); 457 458 assertWithMessage("user on broadcasts").that(usersOnBroadcasts).containsExactly(userHandle); 459 } 460 testUserAddedOrRemovedBroadcasts()461 public void testUserAddedOrRemovedBroadcasts() throws Exception { 462 UserHandle userHandle = createAndManageUser(); 463 464 List<UserHandle> userHandles = removeUserAndWaitForBroadcasts(userHandle); 465 466 assertWithMessage("user on broadcasts").that(userHandles).containsExactly(userHandle); 467 } 468 createAndManageUser()469 private UserHandle createAndManageUser() throws Exception { 470 return createAndManageUser(/* flags= */ 0); 471 } 472 createAndManageUser(int flags)473 private UserHandle createAndManageUser(int flags) throws Exception { 474 return createAndManageUser(/* profileOwner= */ getWho(), /* adminExtras= */ null, flags); 475 } 476 createAndManageUser(ComponentName profileOwner, PersistableBundle adminExtras, int flags)477 private UserHandle createAndManageUser(ComponentName profileOwner, 478 PersistableBundle adminExtras, int flags) throws Exception { 479 String testUserName = "TestUser_" + System.currentTimeMillis(); 480 481 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 482 getContext(), BasicAdminReceiver.ACTION_USER_ADDED); 483 484 UserHandle userHandle = callback.callAndUnregisterSelf(() -> 485 mDevicePolicyManager.createAndManageUser( 486 /* admin= */ getWho(), 487 testUserName, 488 profileOwner, 489 adminExtras, 490 flags)); 491 Log.d(TAG, "User '" + testUserName + "' created: " + userHandle); 492 return userHandle; 493 } 494 495 /** 496 * Switches to the given user, or fails if the user could not be switched or if the expected 497 * broadcasts were not received in time. 498 * 499 * @return users received in the broadcasts 500 */ switchUserAndWaitForBroadcasts(UserHandle userHandle)501 private List<UserHandle> switchUserAndWaitForBroadcasts(UserHandle userHandle) 502 throws Exception { 503 Log.d(TAG, "Switching to user " + userHandle); 504 505 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 506 getContext(), 507 BasicAdminReceiver.ACTION_USER_STARTED, BasicAdminReceiver.ACTION_USER_SWITCHED); 508 509 callback.runAndUnregisterSelf(() -> { 510 Log.d(TAG, "Calling switchUser() on callback"); 511 boolean switched = mDevicePolicyManager.switchUser(getWho(), userHandle); 512 Log.d(TAG, "Switched: " + switched); 513 assertWithMessage("switched to user %s", userHandle).that(switched).isTrue(); 514 }); 515 return callback.getUsersOnReceivedBroadcasts(); 516 } 517 518 /** 519 * Logouts the current user using {@link DevicePolicyManager#logoutUser()}, or fails if the 520 * user could not be logged out or if the expected broadcasts were not received in time. 521 * 522 * @return users received in the broadcasts 523 */ logoutUserUsingSystemApiAndWaitForBroadcasts()524 private List<UserHandle> logoutUserUsingSystemApiAndWaitForBroadcasts() 525 throws Exception { 526 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 527 getContext(), BasicAdminReceiver.ACTION_USER_SWITCHED); 528 Log.d(TAG, "Logging out current user (" + getCurrentUser() + ") using system API"); 529 530 callback.runAndUnregisterSelf(() -> { 531 int result = SystemUtil 532 .callWithShellPermissionIdentity(() -> mDevicePolicyManager.logoutUser()); 533 Log.d(TAG, "Result: " + userOperationResultToString(result)); 534 assertUserOperationResult(result, USER_OPERATION_SUCCESS, "logout user"); 535 }); 536 return callback.getUsersOnReceivedBroadcasts(); 537 } 538 539 /** 540 * Removes the given user, or fails if the user could not be removed or if the expected 541 * broadcasts were not received in time. 542 * 543 * @return users received in the broadcasts 544 */ removeUserAndWaitForBroadcasts(UserHandle userHandle)545 private List<UserHandle> removeUserAndWaitForBroadcasts(UserHandle userHandle) 546 throws Exception { 547 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 548 getContext(), BasicAdminReceiver.ACTION_USER_REMOVED); 549 550 callback.runAndUnregisterSelf(() -> { 551 boolean removed = mDevicePolicyManager.removeUser(getWho(), userHandle); 552 assertWithMessage("removed user %s", userHandle).that(removed).isTrue(); 553 }); 554 555 return callback.getUsersOnReceivedBroadcasts(); 556 } 557 userOperationResultToString(int result)558 private static String userOperationResultToString(int result) { 559 return DebugUtils.constantToString(UserManager.class, "USER_OPERATION_", result); 560 } 561 assertUserOperationResult(int actualResult, int expectedResult, String operationFormat, Object... operationArgs)562 private static void assertUserOperationResult(int actualResult, int expectedResult, 563 String operationFormat, Object... operationArgs) { 564 String operation = String.format(operationFormat, operationArgs); 565 assertWithMessage("result for %s (%s instead of %s)", operation, 566 userOperationResultToString(actualResult), 567 userOperationResultToString(expectedResult)) 568 .that(actualResult).isEqualTo(expectedResult); 569 } 570 startUserInBackgroundAndCheckResult(UserHandle userHandle, int expectedResult)571 private void startUserInBackgroundAndCheckResult(UserHandle userHandle, int expectedResult) { 572 int actualResult = mDevicePolicyManager.startUserInBackground(getWho(), userHandle); 573 assertUserOperationResult(actualResult, expectedResult, "starting user %s in background", 574 userHandle); 575 } 576 577 /** 578 * Starts the given user in background, or fails if the user could not be started or if the 579 * expected broadcasts were not received in time. 580 * 581 * @return users received in the broadcasts 582 */ startUserInBackgroundAndWaitForBroadcasts(UserHandle userHandle)583 private List<UserHandle> startUserInBackgroundAndWaitForBroadcasts(UserHandle userHandle) 584 throws Exception { 585 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 586 getContext(), BasicAdminReceiver.ACTION_USER_STARTED); 587 return startUserInBackgroundAndWaitForBroadcasts(callback, userHandle); 588 } 589 startUserInBackgroundAndWaitForBroadcasts(UserActionCallback callback, UserHandle userHandle)590 private List<UserHandle> startUserInBackgroundAndWaitForBroadcasts(UserActionCallback callback, 591 UserHandle userHandle) throws Exception { 592 callback.runAndUnregisterSelf( 593 () -> startUserInBackgroundAndCheckResult(userHandle, USER_OPERATION_SUCCESS)); 594 return callback.getUsersOnReceivedBroadcasts(); 595 } 596 stopUserAndCheckResult(UserHandle userHandle, int expectedResult)597 private void stopUserAndCheckResult(UserHandle userHandle, int expectedResult) { 598 int actualResult = mDevicePolicyManager.stopUser(getWho(), userHandle); 599 assertUserOperationResult(actualResult, expectedResult, "stopping user %s", userHandle); 600 } 601 602 /** 603 * Stops the given user, or fails if the user could not be stop or if the expected broadcasts 604 * were not received in time. 605 * 606 * @return users received in the broadcasts 607 */ stopUserAndWaitForBroadcasts(UserHandle userHandle)608 private List<UserHandle> stopUserAndWaitForBroadcasts(UserHandle userHandle) throws Exception { 609 UserActionCallback callback = UserActionCallback.getCallbackForBroadcastActions( 610 getContext(), BasicAdminReceiver.ACTION_USER_STOPPED); 611 callback.runAndUnregisterSelf( 612 () -> stopUserAndCheckResult(userHandle, USER_OPERATION_SUCCESS)); 613 return callback.getUsersOnReceivedBroadcasts(); 614 } 615 616 public static final class PrimaryUserService extends Service { 617 private static final Semaphore sSemaphore = new Semaphore(0); 618 private static String sError; 619 620 private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() { 621 public void onEnabledCalled(String error) { 622 Log.d(TAG, "PrimaryUserService.onEnabledCalled() on user " 623 + getApplicationContext().getUserId() + " with error " + error); 624 sError = error; 625 sSemaphore.release(); 626 } 627 }; 628 629 @Override onBind(Intent intent)630 public IBinder onBind(Intent intent) { 631 Log.d(TAG, "PrimaryUserService.onBind() on user " 632 + getApplicationContext().getUserId() + ": " + intent); 633 return mBinder; 634 } 635 assertCrossUserCallArrived()636 static void assertCrossUserCallArrived() throws Exception { 637 Log.v(TAG, "assertCrossUserCallArrived(): waiting " + ON_ENABLED_TIMEOUT_SECONDS 638 + " seconds for callback"); 639 assertWithMessage("cross-user call arrived in %ss", ON_ENABLED_TIMEOUT_SECONDS) 640 .that(sSemaphore.tryAcquire(ON_ENABLED_TIMEOUT_SECONDS, TimeUnit.SECONDS)) 641 .isTrue(); 642 if (sError != null) { 643 Log.e(TAG, "assertCrossUserCallArrived() had error: " + sError); 644 throw new Exception(sError); 645 } 646 } 647 } 648 649 public static final class SecondaryUserAdminReceiver extends DeviceAdminReceiver { 650 @Override onEnabled(Context context, Intent intent)651 public void onEnabled(Context context, Intent intent) { 652 Log.d(TAG, "SecondaryUserAdminReceiver.onEnabled() called on user " 653 + context.getUserId() + " and thread " + Thread.currentThread()); 654 655 DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); 656 ComponentName who = getComponentName(context); 657 658 // Set affiliation ids 659 Set<String> ids = Collections.singleton(intent.getStringExtra(EXTRA_AFFILIATION_ID)); 660 Log.d(TAG, "setting affiliation ids as " + ids); 661 dpm.setAffiliationIds(who, ids); 662 663 String error = null; 664 try { 665 Method method; 666 if (intent.hasExtra(EXTRA_CURRENT_USER_PACKAGES)) { 667 method = CreateAndManageUserTest.class.getDeclaredMethod( 668 intent.getStringExtra(EXTRA_METHOD_NAME), Context.class, 669 DevicePolicyManager.class, ComponentName.class, Set.class); 670 } else { 671 method = CreateAndManageUserTest.class.getDeclaredMethod( 672 intent.getStringExtra(EXTRA_METHOD_NAME), Context.class, 673 DevicePolicyManager.class, ComponentName.class); 674 } 675 method.setAccessible(true); 676 Log.d(TAG, "Calling method " + method); 677 if (intent.hasExtra(EXTRA_CURRENT_USER_PACKAGES)) { 678 String[] pkgsArray = intent.getStringArrayExtra(EXTRA_CURRENT_USER_PACKAGES); 679 Set<String> pkgs = new HashSet<>(pkgsArray.length); 680 for (String pkg : pkgsArray) { 681 pkgs.add(pkg); 682 } 683 method.invoke(null, context, dpm, who, pkgs); 684 } else { 685 method.invoke(null, context, dpm, who); 686 } 687 } catch (NoSuchMethodException | IllegalAccessException e) { 688 error = e.toString(); 689 } catch (InvocationTargetException e) { 690 error = e.getCause().toString(); 691 } 692 if (error != null) { 693 Log.e(TAG, "Error calling method: " + error); 694 } 695 696 // Call all affiliated users 697 final List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(who); 698 Log.d(TAG, "target users: " + targetUsers); 699 assertWithMessage("target users").that(targetUsers).hasSize(1); 700 701 pingTargetUser(context, dpm, targetUsers.get(0), error); 702 } 703 pingTargetUser(Context context, DevicePolicyManager dpm, UserHandle target, String error)704 private void pingTargetUser(Context context, DevicePolicyManager dpm, 705 UserHandle target, String error) { 706 Log.d(TAG, "Pinging target " + target + " with error " + error); 707 final ServiceConnection serviceConnection = new ServiceConnection() { 708 @Override 709 public void onServiceConnected(ComponentName name, IBinder service) { 710 Log.d(TAG, "onServiceConnected() is called in " + Thread.currentThread()); 711 ICrossUserService crossUserService = ICrossUserService 712 .Stub.asInterface(service); 713 try { 714 crossUserService.onEnabledCalled(error); 715 } catch (RemoteException re) { 716 Log.e(TAG, "Error when calling primary user", re); 717 // Do nothing, primary user will time out 718 } 719 } 720 721 @Override 722 public void onServiceDisconnected(ComponentName name) { 723 Log.d(TAG, "onServiceDisconnected() is called"); 724 } 725 }; 726 Intent serviceIntent = new Intent(context, PrimaryUserService.class); 727 boolean bound = dpm.bindDeviceAdminServiceAsUser( 728 getComponentName(context), 729 serviceIntent, 730 serviceConnection, 731 Context.BIND_AUTO_CREATE, 732 target); 733 assertWithMessage("bound to user %s using intent %s", target, serviceIntent).that(bound) 734 .isTrue(); 735 } 736 getComponentName(Context context)737 public static ComponentName getComponentName(Context context) { 738 return new ComponentName(context, SecondaryUserAdminReceiver.class); 739 } 740 } 741 } 742