• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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