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