diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 721a444f0f15b..cccc9294c2d5d 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -585,6 +585,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. */ public void onEnabled(@NonNull Context context, @NonNull Intent intent) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onEnabled() on user " + context.getUserId()); + } } /** @@ -600,6 +603,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public @Nullable CharSequence onDisableRequested(@NonNull Context context, @NonNull Intent intent) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onDisableRequested() on user " + + context.getUserId()); + } return null; } @@ -612,6 +619,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. */ public void onDisabled(@NonNull Context context, @NonNull Intent intent) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onDisabled() on user " + context.getUserId()); + } } /** @@ -786,6 +796,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver { * @param intent The received intent as per {@link #onReceive}. */ public void onProfileProvisioningComplete(@NonNull Context context, @NonNull Intent intent) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onProfileProvisioningComplete() on user " + + context.getUserId()); + } } /** @@ -961,6 +975,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public void onUserAdded(@NonNull Context context, @NonNull Intent intent, @NonNull UserHandle addedUser) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onUserAdded() on user " + context.getUserId()); + } } /** @@ -974,6 +991,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public void onUserRemoved(@NonNull Context context, @NonNull Intent intent, @NonNull UserHandle removedUser) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onUserRemoved() on user " + context.getUserId()); + } } /** @@ -987,6 +1007,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public void onUserStarted(@NonNull Context context, @NonNull Intent intent, @NonNull UserHandle startedUser) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onUserStarted() on user " + context.getUserId()); + } } /** @@ -1000,6 +1023,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public void onUserStopped(@NonNull Context context, @NonNull Intent intent, @NonNull UserHandle stoppedUser) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onUserStopped() on user " + context.getUserId()); + } } /** @@ -1013,6 +1039,9 @@ public class DeviceAdminReceiver extends BroadcastReceiver { */ public void onUserSwitched(@NonNull Context context, @NonNull Intent intent, @NonNull UserHandle switchedUser) { + if (LOCAL_LOGV) { + Log.v(TAG, getClass().getName() + ".onUserSwitched() on user " + context.getUserId()); + } } /** @@ -1104,7 +1133,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver { public void onReceive(@NonNull Context context, @NonNull Intent intent) { String action = intent.getAction(); if (LOCAL_LOGV) { - Log.v(TAG, "onReceive(): received " + action + " on user " + context.getUserId()); + Log.v(TAG, getClass().getName() + ".onReceive(): received " + action + " on user " + + context.getUserId()); } if (ACTION_PASSWORD_CHANGED.equals(action)) { diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index c17d2e4b0c62c..eb2de60127451 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -63,8 +63,13 @@ public abstract class UserManagerInternal { */ public interface UserLifecycleListener { - /** Called when a new user is created. */ - default void onUserCreated(UserInfo user) {} + /** + * Called when a new user is created. + * + * @param user new user. + * @param token token passed to the method that created the user. + */ + default void onUserCreated(UserInfo user, @Nullable Object token) {} /** Called when an existing user is removed. */ default void onUserRemoved(UserInfo user) {} @@ -179,10 +184,12 @@ public abstract class UserManagerInternal { * {@link UserManager#DISALLOW_ADD_USER} and {@link UserManager#DISALLOW_ADD_MANAGED_PROFILE} * *

Called by the {@link com.android.server.devicepolicy.DevicePolicyManagerService} when - * createAndManageUser is called by the device owner. + * createAndManageUser is called by the device owner; it uses {@code token} to block until + * the user is created (as it will be passed back to it through + * {@link UserLifecycleListener#onUserCreated(UserInfo, Object)}); */ public abstract UserInfo createUserEvenWhenDisallowed(String name, String userType, - int flags, String[] disallowedPackages) + int flags, String[] disallowedPackages, @Nullable Object token) throws UserManager.CheckedUserOperationException; /** diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 24c27bedb9f7a..e10b052ece7a3 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3309,7 +3309,7 @@ public class UserManagerService extends IUserManager.Stub { checkManageOrCreateUsersPermission(flags); try { return createUserInternalUnchecked(name, userType, flags, userId, - /* preCreate= */ false, disallowedPackages); + /* preCreate= */ false, disallowedPackages, /* token= */ null); } catch (UserManager.CheckedUserOperationException e) { throw e.toServiceSpecificException(); } @@ -3342,7 +3342,7 @@ public class UserManagerService extends IUserManager.Stub { try { return createUserInternalUnchecked(/* name= */ null, userType, flags, /* parentId= */ UserHandle.USER_NULL, /* preCreate= */ true, - /* disallowedPackages= */ null); + /* disallowedPackages= */ null, /* token= */ null); } catch (UserManager.CheckedUserOperationException e) { throw e.toServiceSpecificException(); } @@ -3358,12 +3358,13 @@ public class UserManagerService extends IUserManager.Stub { enforceUserRestriction(restriction, UserHandle.getCallingUserId(), "Cannot add user"); return createUserInternalUnchecked(name, userType, flags, parentId, - /* preCreate= */ false, disallowedPackages); + /* preCreate= */ false, disallowedPackages, /* token= */ null); } private UserInfo createUserInternalUnchecked(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId, - boolean preCreate, @Nullable String[] disallowedPackages) + boolean preCreate, @Nullable String[] disallowedPackages, + @Nullable Object token) throws UserManager.CheckedUserOperationException { final int nextProbableUserId = getNextAvailableId(); final TimingsTraceAndSlog t = new TimingsTraceAndSlog(); @@ -3372,7 +3373,7 @@ public class UserManagerService extends IUserManager.Stub { UserInfo newUser = null; try { newUser = createUserInternalUncheckedNoTracing(name, userType, flags, parentId, - preCreate, disallowedPackages, t); + preCreate, disallowedPackages, t, token); return newUser; } finally { logUserCreateJourneyFinish(sessionId, nextProbableUserId, newUser != null); @@ -3383,7 +3384,8 @@ public class UserManagerService extends IUserManager.Stub { private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags, @UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages, - @NonNull TimingsTraceAndSlog t) throws UserManager.CheckedUserOperationException { + @NonNull TimingsTraceAndSlog t, @Nullable Object token) + throws UserManager.CheckedUserOperationException { final UserTypeDetails userTypeDetails = mUserTypes.get(userType); if (userTypeDetails == null) { Slog.e(LOG_TAG, "Cannot create user of invalid user type: " + userType); @@ -3409,7 +3411,8 @@ public class UserManagerService extends IUserManager.Stub { // Try to use a pre-created user (if available). if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) { - final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name); + final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name, + token); if (preCreatedUser != null) { return preCreatedUser; } @@ -3588,7 +3591,7 @@ public class UserManagerService extends IUserManager.Stub { Slog.w(LOG_TAG, "could not start pre-created user " + userId, e); } } else { - dispatchUserAdded(userInfo); + dispatchUserAdded(userInfo, token); } } finally { @@ -3688,7 +3691,7 @@ public class UserManagerService extends IUserManager.Stub { * @return the converted user, or {@code null} if no pre-created user could be converted. */ private @Nullable UserInfo convertPreCreatedUserIfPossible(String userType, - @UserInfoFlag int flags, String name) { + @UserInfoFlag int flags, String name, @Nullable Object token) { final UserData preCreatedUserData; synchronized (mUsersLock) { preCreatedUserData = getPreCreatedUserLU(userType); @@ -3726,7 +3729,7 @@ public class UserManagerService extends IUserManager.Stub { } updateUserIds(); mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true); - dispatchUserAdded(preCreatedUser); + dispatchUserAdded(preCreatedUser, token); return preCreatedUser; } @@ -3758,11 +3761,11 @@ public class UserManagerService extends IUserManager.Stub { return (now > EPOCH_PLUS_30_YEARS) ? now : 0; } - private void dispatchUserAdded(@NonNull UserInfo userInfo) { + private void dispatchUserAdded(@NonNull UserInfo userInfo, @Nullable Object token) { // Notify internal listeners first... synchronized (mUserLifecycleListeners) { for (int i = 0; i < mUserLifecycleListeners.size(); i++) { - mUserLifecycleListeners.get(i).onUserCreated(userInfo); + mUserLifecycleListeners.get(i).onUserCreated(userInfo, token); } } @@ -5367,10 +5370,10 @@ public class UserManagerService extends IUserManager.Stub { @Override public UserInfo createUserEvenWhenDisallowed(String name, @NonNull String userType, - @UserInfoFlag int flags, String[] disallowedPackages) + @UserInfoFlag int flags, String[] disallowedPackages, @Nullable Object token) throws UserManager.CheckedUserOperationException { return createUserInternalUnchecked(name, userType, flags, - UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages); + UserHandle.USER_NULL, /* preCreated= */ false, disallowedPackages, token); } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 524892b2ec4bc..aabe65030bf0d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -715,6 +715,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Nullable private DevicePolicySafetyChecker mSafetyChecker; + @GuardedBy("getLockObject()") + private final ArrayList mPendingUserCreatedCallbackTokens = new ArrayList<>(); + public static final class Lifecycle extends SystemService { private BaseIDevicePolicyManager mService; @@ -965,8 +968,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener { @Override - public void onUserCreated(UserInfo user) { - mHandler.post(() -> handleNewUserCreated(user)); + public void onUserCreated(UserInfo user, Object token) { + mHandler.post(() -> handleNewUserCreated(user, token)); } } @@ -3151,11 +3154,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!mHasFeature) { return; } - setActiveAdmin(adminReceiver, refreshing, userHandle, null); - } - - private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle, - Bundle onEnableData) { Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId"); final CallerIdentity caller = getCallerIdentity(); @@ -3198,7 +3196,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } saveSettingsLocked(userHandle); sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, - onEnableData, null); + /* adminExtras= */ null, /* result= */ null); }); } } @@ -9190,6 +9188,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus())); pw.println(); + + if (mPendingUserCreatedCallbackTokens.isEmpty()) { + pw.println("no pending user created callback tokens"); + } else { + int size = mPendingUserCreatedCallbackTokens.size(); + pw.printf("%d pending user created callback token%s\n", size, + (size == 1 ? "" : "s")); + } + pw.println(); + mPolicyCache.dump(pw); pw.println(); mStateCache.dump(pw); @@ -9946,8 +9954,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { clearInitBundle = sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, initBundle == null ? null : new Bundle(initBundle), - null /* result receiver */, - true /* send in foreground */); + /* result= */ null , + /* inForeground= */ true); } if (clearInitBundle) { // If there's no admin or we've successfully called the admin, clear the init bundle @@ -10020,9 +10028,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { UserHandle.myUserId(), ACTION_PROVISION_MANAGED_USER).toArray( new String[0]); } + + Object token = new Object(); + Slog.d(LOG_TAG, "Adding new pending token: " + token); + mPendingUserCreatedCallbackTokens.add(token); try { UserInfo userInfo = mUserManagerInternal.createUserEvenWhenDisallowed(name, - userType, userInfoFlags, disallowedPackages); + userType, userInfoFlags, disallowedPackages, token); if (userInfo != null) { user = userInfo.getUserHandle(); } @@ -10032,7 +10044,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } finally { mInjector.binderRestoreCallingIdentity(id); } - } + } // synchronized + if (user == null) { if (targetSdkVersion >= Build.VERSION_CODES.P) { throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN, @@ -10054,14 +10067,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long id = mInjector.binderClearCallingIdentity(); try { - if (!mInjector.userManagerIsHeadlessSystemUserMode()) { - manageUserUnchecked(admin, profileOwner, userHandle, adminExtras, - /* showDisclaimer= */ true); - } else if (VERBOSE_LOG) { - Slog.v(LOG_TAG, "createAndManageUser(): skipping manageUserUnchecked() on user " - + userHandle + " on headless system user as it will be called by " - + "handleNewUserCreated()"); - } + manageUserUnchecked(admin, profileOwner, userHandle, adminExtras, + /* showDisclaimer= */ true); if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) { Settings.Secure.putIntForUser(mContext.getContentResolver(), @@ -10083,7 +10090,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void manageUserUnchecked(ComponentName admin, ComponentName profileOwner, - @UserIdInt int userId, PersistableBundle adminExtras, boolean showDisclaimer) { + @UserIdInt int userId, @Nullable PersistableBundle adminExtras, + boolean showDisclaimer) { + synchronized (getLockObject()) { + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "manageUserUnchecked(): admin=" + admin + ", po=" + profileOwner + + ", userId=" + userId + ", hasAdminExtras=" + (adminExtras != null) + + ", showDisclaimer=" + showDisclaimer); + } + } final String adminPkg = admin.getPackageName(); try { // Install the profile owner if not present. @@ -10113,23 +10128,37 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { ? DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED : DevicePolicyData.NEW_USER_DISCLAIMER_NOT_NEEDED; saveSettingsLocked(userId); + } } - private void handleNewUserCreated(UserInfo user) { - if (VERBOSE_LOG) Slog.v(LOG_TAG, "handleNewUserCreated(): " + user.toFullString()); - - if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return; + private void handleNewUserCreated(UserInfo user, @Nullable Object token) { + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "handleNewUserCreated(): user=" + user.toFullString() + + ", token=" + token); + } final int userId = user.id; + if (token != null) { + synchronized (getLockObject()) { + if (mPendingUserCreatedCallbackTokens.contains(token)) { + // Ignore because it was triggered by createAndManageUser() + Slog.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId + + " due to token" + token); + mPendingUserCreatedCallbackTokens.remove(token); + return; + } + } + } + + if (!mOwners.hasDeviceOwner() || !user.isFull() || user.isManagedProfile()) return; if (mInjector.userManagerIsHeadlessSystemUserMode()) { ComponentName admin = mOwners.getDeviceOwnerComponent(); Slog.i(LOG_TAG, "Automatically setting profile owner (" + admin + ") on new user " + userId); manageUserUnchecked(/* deviceOwner= */ admin, /* profileOwner= */ admin, - /* managedUser= */ userId, /* adminExtras= */ null, - /* showDisclaimer= */ true); + /* managedUser= */ userId, /* adminExtras= */ null, /* showDisclaimer= */ true); } else { Log.i(LOG_TAG, "User " + userId + " added on DO mode; setting ShowNewUserDisclaimer"); setShowNewUserDisclaimer(userId, DevicePolicyData.NEW_USER_DISCLAIMER_NEEDED); @@ -10250,11 +10279,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long id = mInjector.binderClearCallingIdentity(); try { if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) { - Log.w(LOG_TAG, "Cannot start more users in background"); + Log.w(LOG_TAG, "Cannot start user " + userId + ", too many users in background"); return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS; } if (mInjector.getIActivityManager().startUserInBackground(userId)) { + Log.i(LOG_TAG, "Started used " + userId + " in background"); return UserManager.USER_OPERATION_SUCCESS; } else { return UserManager.USER_OPERATION_ERROR_UNKNOWN;