Loading core/java/android/os/IUserManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ interface IUserManager { boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne); UserInfo getProfileParent(int userId); boolean isSameProfileGroup(int userId, int otherUserHandle); boolean isHeadlessSystemUserMode(); boolean isUserOfType(int userId, in String userType); @UnsupportedAppUsage UserInfo getUserInfo(int userId); Loading core/java/android/os/UserManager.java +16 −22 Original line number Diff line number Diff line Loading @@ -91,7 +91,6 @@ import java.util.Set; public class UserManager { private static final String TAG = "UserManager"; private static final boolean VERBOSE = false; @UnsupportedAppUsage private final IUserManager mService; Loading @@ -104,6 +103,9 @@ public class UserManager { /** The userType of UserHandle.myUserId(); empty string if not a profile; null until cached. */ private String mProfileTypeOfProcessUser = null; /** Whether the device is in headless system user mode; null until cached. */ private static Boolean sIsHeadlessSystemUser = null; /** * User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user. * This type of user cannot be created; it can only pre-exist on first boot. Loading Loading @@ -2068,28 +2070,20 @@ public class UserManager { * @return whether the device is running in a headless system user mode. */ public static boolean isHeadlessSystemUserMode() { final boolean realMode = RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; if (!Build.isDebuggable()) { return realMode; // No need for synchronization. Once it becomes non-null, it'll be non-null forever. // (Its value is determined when UMS is constructed and cannot change.) // Worst case we might end up calling the AIDL method multiple times but that's fine. if (sIsHeadlessSystemUser == null) { // Unfortunately this API is static, but the property no longer is. So go fetch the UMS. try { final IUserManager service = IUserManager.Stub.asInterface( ServiceManager.getService(Context.USER_SERVICE)); sIsHeadlessSystemUser = service.isHeadlessSystemUserMode(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } final String emulatedMode = SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY); switch (emulatedMode) { case SYSTEM_USER_MODE_EMULATION_FULL: if (VERBOSE) Log.v(TAG, "isHeadlessSystemUserMode(): emulating as false"); return false; case SYSTEM_USER_MODE_EMULATION_HEADLESS: if (VERBOSE) Log.v(TAG, "isHeadlessSystemUserMode(): emulating as true"); return true; case SYSTEM_USER_MODE_EMULATION_DEFAULT: case "": // property not set return realMode; default: Log.wtf(TAG, "isHeadlessSystemUserMode(): invalid value of property " + SYSTEM_USER_MODE_EMULATION_PROPERTY + " (" + emulatedMode + "); using" + " default value (headless=" + realMode + ")"); return realMode; } return sIsHeadlessSystemUser; } /** Loading core/java/com/android/internal/os/RoSystemProperties.java +9 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,15 @@ public class RoSystemProperties { // ------ ro.fw.* ------------ // public static final boolean FW_SYSTEM_USER_SPLIT = SystemProperties.getBoolean("ro.fw.system_user_split", false); /** * Indicates whether the device should run in headless system user mode, * in which user 0 only runs the system, not a real user. * <p>WARNING about changing this value during an non-wiping update (OTA): * <li>If this value is modified via an update, the change will have no effect, since an * already-existing system user cannot change its mode. * <li>Changing this value during an OTA from a pre-R device is not permitted; attempting to * do so will corrupt the system user. */ public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER = SystemProperties.getBoolean("ro.fw.mu.headless_system_user", false); Loading services/core/java/com/android/server/pm/UserManagerService.java +47 −30 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.pm; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.UserManager.DISALLOW_USER_SWITCH; import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY; import android.Manifest; import android.accounts.Account; Loading Loading @@ -314,7 +315,7 @@ public class UserManagerService extends IUserManager.Stub { @VisibleForTesting static class UserData { // Basic user information and properties UserInfo info; @NonNull UserInfo info; // Account name used when there is a strong association between a user and an account String account; // Account information for seeding into a newly created user. This could also be Loading Loading @@ -3268,11 +3269,39 @@ public class UserManagerService extends IUserManager.Stub { } } /** Checks whether the device is currently in headless system user mode (for any reason). */ @Override public boolean isHeadlessSystemUserMode() { synchronized (mUsersLock) { final UserData systemUserData = mUsers.get(UserHandle.USER_SYSTEM); return !systemUserData.info.isFull(); } } /** * Checks whether the device is really headless system user mode, ignoring system user mode * emulation. * Checks whether the default state of the device is headless system user mode, i.e. what the * mode would be if we did a fresh factory reset. * If the mode is being emulated (via SYSTEM_USER_MODE_EMULATION_PROPERTY) then that will be * returned instead. * Note that, even in the absence of emulation, a device might deviate from the current default * due to an OTA changing the default (which won't change the already-decided mode). */ private boolean isReallyHeadlessSystemUserMode() { private boolean isDefaultHeadlessSystemUserMode() { if (!Build.isDebuggable()) { return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; } final String emulatedValue = SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY); if (!TextUtils.isEmpty(emulatedValue)) { if (UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS.equals(emulatedValue)) return true; if (UserManager.SYSTEM_USER_MODE_EMULATION_FULL.equals(emulatedValue)) return false; if (!UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT.equals(emulatedValue)) { Slogf.e(LOG_TAG, "isDefaultHeadlessSystemUserMode(): ignoring invalid valued of " + "property %s: %s", SYSTEM_USER_MODE_EMULATION_PROPERTY, emulatedValue); } } return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; } Loading @@ -3284,30 +3313,11 @@ public class UserManagerService extends IUserManager.Stub { if (!Build.isDebuggable()) { return; } final String emulatedValue = SystemProperties .get(UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY); if (TextUtils.isEmpty(emulatedValue)) { if (TextUtils.isEmpty(SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY))) { return; } final boolean newHeadlessSystemUserMode; switch (emulatedValue) { case UserManager.SYSTEM_USER_MODE_EMULATION_FULL: newHeadlessSystemUserMode = false; break; case UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS: newHeadlessSystemUserMode = true; break; case UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT: newHeadlessSystemUserMode = isReallyHeadlessSystemUserMode(); break; default: Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): ignoring invalid valued of " + "property %s: %s", UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, emulatedValue); return; } final boolean newHeadlessSystemUserMode = isDefaultHeadlessSystemUserMode(); // Update system user type synchronized (mPackagesLock) { Loading Loading @@ -3343,7 +3353,7 @@ public class UserManagerService extends IUserManager.Stub { } } // Update emulated mode, which will used to triger an update on user packages // Update emulated mode, which will used to trigger an update on user packages mUpdatingSystemUserMode = true; } Loading Loading @@ -3533,7 +3543,11 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mUsersLock) { UserData userData = mUsers.get(UserHandle.USER_SYSTEM); userData.info.flags |= UserInfo.FLAG_SYSTEM; if (!UserManager.isHeadlessSystemUserMode()) { // We assume that isDefaultHeadlessSystemUserMode() does not change during the OTA // from userVersion < 8 since it is documented that pre-R devices do not support its // modification. Therefore, its current value should be the same as the pre-update // version. if (!isDefaultHeadlessSystemUserMode()) { userData.info.flags |= UserInfo.FLAG_FULL; } userIdsToWrite.add(userData.info.id); Loading Loading @@ -3742,7 +3756,7 @@ public class UserManagerService extends IUserManager.Stub { int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY; // Create the system user String systemUserType = UserManager.isHeadlessSystemUserMode() String systemUserType = isDefaultHeadlessSystemUserMode() ? UserManager.USER_TYPE_SYSTEM_HEADLESS : UserManager.USER_TYPE_FULL_SYSTEM; flags |= mUserTypes.get(systemUserType).getDefaultUserInfoFlags(); Loading Loading @@ -6210,9 +6224,12 @@ public class UserManagerService extends IUserManager.Stub { com.android.internal.R.bool.config_guestUserEphemeral)); pw.println(" Force ephemeral users: " + mForceEphemeralUsers); pw.println(" Is split-system user: " + UserManager.isSplitSystemUser()); final boolean isHeadlessSystemUserMode = UserManager.isHeadlessSystemUserMode(); final boolean isHeadlessSystemUserMode = isHeadlessSystemUserMode(); pw.println(" Is headless-system mode: " + isHeadlessSystemUserMode); if (isHeadlessSystemUserMode != isReallyHeadlessSystemUserMode()) { if (isHeadlessSystemUserMode != RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER) { pw.println(" (differs from the current default build value)"); } if (!TextUtils.isEmpty(SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY))) { pw.println(" (emulated by 'cmd user set-system-user-mode-emulation')"); if (mUpdatingSystemUserMode) { pw.println(" (and being updated after boot)"); Loading Loading
core/java/android/os/IUserManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ interface IUserManager { boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne); UserInfo getProfileParent(int userId); boolean isSameProfileGroup(int userId, int otherUserHandle); boolean isHeadlessSystemUserMode(); boolean isUserOfType(int userId, in String userType); @UnsupportedAppUsage UserInfo getUserInfo(int userId); Loading
core/java/android/os/UserManager.java +16 −22 Original line number Diff line number Diff line Loading @@ -91,7 +91,6 @@ import java.util.Set; public class UserManager { private static final String TAG = "UserManager"; private static final boolean VERBOSE = false; @UnsupportedAppUsage private final IUserManager mService; Loading @@ -104,6 +103,9 @@ public class UserManager { /** The userType of UserHandle.myUserId(); empty string if not a profile; null until cached. */ private String mProfileTypeOfProcessUser = null; /** Whether the device is in headless system user mode; null until cached. */ private static Boolean sIsHeadlessSystemUser = null; /** * User type representing a {@link UserHandle#USER_SYSTEM system} user that is a human user. * This type of user cannot be created; it can only pre-exist on first boot. Loading Loading @@ -2068,28 +2070,20 @@ public class UserManager { * @return whether the device is running in a headless system user mode. */ public static boolean isHeadlessSystemUserMode() { final boolean realMode = RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; if (!Build.isDebuggable()) { return realMode; // No need for synchronization. Once it becomes non-null, it'll be non-null forever. // (Its value is determined when UMS is constructed and cannot change.) // Worst case we might end up calling the AIDL method multiple times but that's fine. if (sIsHeadlessSystemUser == null) { // Unfortunately this API is static, but the property no longer is. So go fetch the UMS. try { final IUserManager service = IUserManager.Stub.asInterface( ServiceManager.getService(Context.USER_SERVICE)); sIsHeadlessSystemUser = service.isHeadlessSystemUserMode(); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } final String emulatedMode = SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY); switch (emulatedMode) { case SYSTEM_USER_MODE_EMULATION_FULL: if (VERBOSE) Log.v(TAG, "isHeadlessSystemUserMode(): emulating as false"); return false; case SYSTEM_USER_MODE_EMULATION_HEADLESS: if (VERBOSE) Log.v(TAG, "isHeadlessSystemUserMode(): emulating as true"); return true; case SYSTEM_USER_MODE_EMULATION_DEFAULT: case "": // property not set return realMode; default: Log.wtf(TAG, "isHeadlessSystemUserMode(): invalid value of property " + SYSTEM_USER_MODE_EMULATION_PROPERTY + " (" + emulatedMode + "); using" + " default value (headless=" + realMode + ")"); return realMode; } return sIsHeadlessSystemUser; } /** Loading
core/java/com/android/internal/os/RoSystemProperties.java +9 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,15 @@ public class RoSystemProperties { // ------ ro.fw.* ------------ // public static final boolean FW_SYSTEM_USER_SPLIT = SystemProperties.getBoolean("ro.fw.system_user_split", false); /** * Indicates whether the device should run in headless system user mode, * in which user 0 only runs the system, not a real user. * <p>WARNING about changing this value during an non-wiping update (OTA): * <li>If this value is modified via an update, the change will have no effect, since an * already-existing system user cannot change its mode. * <li>Changing this value during an OTA from a pre-R device is not permitted; attempting to * do so will corrupt the system user. */ public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER = SystemProperties.getBoolean("ro.fw.mu.headless_system_user", false); Loading
services/core/java/com/android/server/pm/UserManagerService.java +47 −30 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.pm; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.UserManager.DISALLOW_USER_SWITCH; import static android.os.UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY; import android.Manifest; import android.accounts.Account; Loading Loading @@ -314,7 +315,7 @@ public class UserManagerService extends IUserManager.Stub { @VisibleForTesting static class UserData { // Basic user information and properties UserInfo info; @NonNull UserInfo info; // Account name used when there is a strong association between a user and an account String account; // Account information for seeding into a newly created user. This could also be Loading Loading @@ -3268,11 +3269,39 @@ public class UserManagerService extends IUserManager.Stub { } } /** Checks whether the device is currently in headless system user mode (for any reason). */ @Override public boolean isHeadlessSystemUserMode() { synchronized (mUsersLock) { final UserData systemUserData = mUsers.get(UserHandle.USER_SYSTEM); return !systemUserData.info.isFull(); } } /** * Checks whether the device is really headless system user mode, ignoring system user mode * emulation. * Checks whether the default state of the device is headless system user mode, i.e. what the * mode would be if we did a fresh factory reset. * If the mode is being emulated (via SYSTEM_USER_MODE_EMULATION_PROPERTY) then that will be * returned instead. * Note that, even in the absence of emulation, a device might deviate from the current default * due to an OTA changing the default (which won't change the already-decided mode). */ private boolean isReallyHeadlessSystemUserMode() { private boolean isDefaultHeadlessSystemUserMode() { if (!Build.isDebuggable()) { return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; } final String emulatedValue = SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY); if (!TextUtils.isEmpty(emulatedValue)) { if (UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS.equals(emulatedValue)) return true; if (UserManager.SYSTEM_USER_MODE_EMULATION_FULL.equals(emulatedValue)) return false; if (!UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT.equals(emulatedValue)) { Slogf.e(LOG_TAG, "isDefaultHeadlessSystemUserMode(): ignoring invalid valued of " + "property %s: %s", SYSTEM_USER_MODE_EMULATION_PROPERTY, emulatedValue); } } return RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER; } Loading @@ -3284,30 +3313,11 @@ public class UserManagerService extends IUserManager.Stub { if (!Build.isDebuggable()) { return; } final String emulatedValue = SystemProperties .get(UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY); if (TextUtils.isEmpty(emulatedValue)) { if (TextUtils.isEmpty(SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY))) { return; } final boolean newHeadlessSystemUserMode; switch (emulatedValue) { case UserManager.SYSTEM_USER_MODE_EMULATION_FULL: newHeadlessSystemUserMode = false; break; case UserManager.SYSTEM_USER_MODE_EMULATION_HEADLESS: newHeadlessSystemUserMode = true; break; case UserManager.SYSTEM_USER_MODE_EMULATION_DEFAULT: newHeadlessSystemUserMode = isReallyHeadlessSystemUserMode(); break; default: Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): ignoring invalid valued of " + "property %s: %s", UserManager.SYSTEM_USER_MODE_EMULATION_PROPERTY, emulatedValue); return; } final boolean newHeadlessSystemUserMode = isDefaultHeadlessSystemUserMode(); // Update system user type synchronized (mPackagesLock) { Loading Loading @@ -3343,7 +3353,7 @@ public class UserManagerService extends IUserManager.Stub { } } // Update emulated mode, which will used to triger an update on user packages // Update emulated mode, which will used to trigger an update on user packages mUpdatingSystemUserMode = true; } Loading Loading @@ -3533,7 +3543,11 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mUsersLock) { UserData userData = mUsers.get(UserHandle.USER_SYSTEM); userData.info.flags |= UserInfo.FLAG_SYSTEM; if (!UserManager.isHeadlessSystemUserMode()) { // We assume that isDefaultHeadlessSystemUserMode() does not change during the OTA // from userVersion < 8 since it is documented that pre-R devices do not support its // modification. Therefore, its current value should be the same as the pre-update // version. if (!isDefaultHeadlessSystemUserMode()) { userData.info.flags |= UserInfo.FLAG_FULL; } userIdsToWrite.add(userData.info.id); Loading Loading @@ -3742,7 +3756,7 @@ public class UserManagerService extends IUserManager.Stub { int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY; // Create the system user String systemUserType = UserManager.isHeadlessSystemUserMode() String systemUserType = isDefaultHeadlessSystemUserMode() ? UserManager.USER_TYPE_SYSTEM_HEADLESS : UserManager.USER_TYPE_FULL_SYSTEM; flags |= mUserTypes.get(systemUserType).getDefaultUserInfoFlags(); Loading Loading @@ -6210,9 +6224,12 @@ public class UserManagerService extends IUserManager.Stub { com.android.internal.R.bool.config_guestUserEphemeral)); pw.println(" Force ephemeral users: " + mForceEphemeralUsers); pw.println(" Is split-system user: " + UserManager.isSplitSystemUser()); final boolean isHeadlessSystemUserMode = UserManager.isHeadlessSystemUserMode(); final boolean isHeadlessSystemUserMode = isHeadlessSystemUserMode(); pw.println(" Is headless-system mode: " + isHeadlessSystemUserMode); if (isHeadlessSystemUserMode != isReallyHeadlessSystemUserMode()) { if (isHeadlessSystemUserMode != RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER) { pw.println(" (differs from the current default build value)"); } if (!TextUtils.isEmpty(SystemProperties.get(SYSTEM_USER_MODE_EMULATION_PROPERTY))) { pw.println(" (emulated by 'cmd user set-system-user-mode-emulation')"); if (mUpdatingSystemUserMode) { pw.println(" (and being updated after boot)"); Loading