UserInfo: FULL and SYSTEM flags

Introduces two new UserInfo flags:

SYSTEM - refers to the system user, i.e. user 0. Although
UserManagerService already knows which user is the system, this flag
will be useful in other contexts.

FULL - refers to a non-profile human user.

Right now, for every user, one of the following flag combos are true:
SYSTEM (user 0 on a headless-user-0 device)
SYSTEM | FULL (user 0 on a regular device)
FULL (secondary user)
MANAGED_PROFILE (profile users)

Test: Manual verification via "pm list users" of new flags when adding a new user
Test: Manual verification via "pm list users" of new flags for pre-existing users
Test: Later cls will test the functionality as it is introduced
Bug: 134605778
Change-Id: Ife92bfa8a91cc4567d825da8e6a1b3894b088b22
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a707aa8..2ccb6c1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -75,6 +75,7 @@
 import android.security.GateKeeper;
 import android.service.gatekeeper.IGateKeeperService;
 import android.stats.devicepolicy.DevicePolicyEnums;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.IntArray;
 import android.util.Log;
@@ -125,6 +126,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Service for {@link UserManager}.
@@ -214,7 +216,7 @@
     @VisibleForTesting
     static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;
 
-    private static final int USER_VERSION = 7;
+    private static final int USER_VERSION = 8;
 
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
@@ -2139,6 +2141,7 @@
      */
     @GuardedBy({"mRestrictionsLock", "mPackagesLock"})
     private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
+        Set<Integer> userIdsToWrite = new ArraySet<>();
         final int originalVersion = mUserVersion;
         int userVersion = mUserVersion;
         if (userVersion < 1) {
@@ -2147,7 +2150,7 @@
             if ("Primary".equals(userData.info.name)) {
                 userData.info.name =
                         mContext.getResources().getString(com.android.internal.R.string.owner_name);
-                scheduleWriteUser(userData);
+                userIdsToWrite.add(userData.info.id);
             }
             userVersion = 1;
         }
@@ -2157,7 +2160,7 @@
             UserData userData = getUserDataNoChecks(UserHandle.USER_SYSTEM);
             if ((userData.info.flags & UserInfo.FLAG_INITIALIZED) == 0) {
                 userData.info.flags |= UserInfo.FLAG_INITIALIZED;
-                scheduleWriteUser(userData);
+                userIdsToWrite.add(userData.info.id);
             }
             userVersion = 2;
         }
@@ -2182,7 +2185,7 @@
                             && (userData.info.restrictedProfileParentId
                                     == UserInfo.NO_PROFILE_GROUP_ID)) {
                         userData.info.restrictedProfileParentId = UserHandle.USER_SYSTEM;
-                        scheduleWriteUser(userData);
+                        userIdsToWrite.add(userData.info.id);
                     }
                 }
             }
@@ -2206,6 +2209,29 @@
             userVersion = 7;
         }
 
+        if (userVersion < 8) {
+            // Added FLAG_FULL and FLAG_SYSTEM flags.
+            synchronized (mUsersLock) {
+                UserData userData = mUsers.get(UserHandle.USER_SYSTEM);
+                userData.info.flags |= UserInfo.FLAG_SYSTEM;
+                if (!UserManager.isHeadlessSystemUserMode()) {
+                    userData.info.flags |= UserInfo.FLAG_FULL;
+                }
+                userIdsToWrite.add(userData.info.id);
+
+                // Mark FULL all non-profile users except USER_SYSTEM.
+                // Start index at 1 since USER_SYSTEM is the smallest userId and we're skipping it.
+                for (int i = 1; i < mUsers.size(); i++) {
+                    userData = mUsers.valueAt(i);
+                    if ((userData.info.flags & UserInfo.FLAG_MANAGED_PROFILE) == 0) {
+                        userData.info.flags |= UserInfo.FLAG_FULL;
+                        userIdsToWrite.add(userData.info.id);
+                    }
+                }
+            }
+            userVersion = 8;
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);
@@ -2213,6 +2239,12 @@
             mUserVersion = userVersion;
 
             if (originalVersion < mUserVersion) {
+                for (int userId : userIdsToWrite) {
+                    UserData userData = getUserDataNoChecks(userId);
+                    if (userData != null) {
+                        writeUserLP(userData);
+                    }
+                }
                 writeUserListLP();
             }
         }
@@ -2220,12 +2252,15 @@
 
     @GuardedBy({"mPackagesLock", "mRestrictionsLock"})
     private void fallbackToSingleUserLP() {
-        int flags = UserInfo.FLAG_INITIALIZED;
+        int flags = UserInfo.FLAG_SYSTEM | UserInfo.FLAG_INITIALIZED;
         // In split system user mode, the admin and primary flags are assigned to the first human
         // user.
         if (!UserManager.isSplitSystemUser()) {
             flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY;
         }
+        if (!UserManager.isHeadlessSystemUserMode()) {
+            flags |= UserInfo.FLAG_FULL;
+        }
         // Create the system user
         UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
         UserData userData = putUserInfo(system);
@@ -2262,14 +2297,14 @@
         return mContext.getResources().getString(com.android.internal.R.string.owner_name);
     }
 
-    private void scheduleWriteUser(UserData UserData) {
+    private void scheduleWriteUser(UserData userData) {
         if (DBG) {
             debug("scheduleWriteUser");
         }
         // No need to wrap it within a lock -- worst case, we'll just post the same message
         // twice.
-        if (!mHandler.hasMessages(WRITE_USER_MSG, UserData)) {
-            Message msg = mHandler.obtainMessage(WRITE_USER_MSG, UserData);
+        if (!mHandler.hasMessages(WRITE_USER_MSG, userData)) {
+            Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userData);
             mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY);
         }
     }
@@ -2749,6 +2784,10 @@
                         }
                     }
                 }
+                if (!isManagedProfile) {
+                    // New users cannot be system, and it's not a profile, so per-force it's FULL.
+                    flags |= UserInfo.FLAG_FULL;
+                }
 
                 userId = getNextAvailableId();
                 Environment.getUserSystemDirectory(userId).mkdirs();