More multi-user stuff.

- New public APIs to find out when a user goes to the foreground,
  background, and is first initializing.
- New activity manager callback to be involved in the user switch
  process, allowing other services to let it know when it is safe
  to stop freezing the screen.
- Wallpaper service now implements this to handle its user switch,
  telling the activity manager when it is done.  (Currently this is
  only handling the old wallpaper going away, we need a little more
  work to correctly wait for the new wallpaper to get added.)
- Lock screen now implements the callback to do its user switch.  It
  also now locks itself when this happens, instead of relying on
  some other entity making sure it is locked.
- Pre-boot broadcasts now go to all users.
- WallpaperManager now has an API to find out if a named wallpaper is
  in use by any users.

Change-Id: I27877aef1d82126c0a1428c3d1861619ee5f8653
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index fc01f60..a58c4ea 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -83,6 +83,8 @@
 
     private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
 
+    private final int mUserLimit;
+
     private int[] mUserIds;
     private boolean mGuestEnabled;
     private int mNextSerialNumber;
@@ -125,6 +127,8 @@
             mPm = pm;
             mInstallLock = installLock;
             mPackagesLock = packagesLock;
+            mUserLimit = mContext.getResources().getInteger(
+                    com.android.internal.R.integer.config_multiuserMaximumUsers);
             mUsersDir = new File(dataDir, USER_INFO_DIR);
             mUsersDir.mkdirs();
             // Make zeroth user directory, for services to migrate their files to that location
@@ -237,16 +241,23 @@
         // TODO:
     }
 
+    public void makeInitialized(int userId) {
+        checkManageUsersPermission("makeInitialized");
+        synchronized (mPackagesLock) {
+            UserInfo info = mUsers.get(userId);
+            if (info != null && (info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+                info.flags |= UserInfo.FLAG_INITIALIZED;
+                writeUserLocked(info);
+            }
+        }
+    }
+
     /**
      * Check if we've hit the limit of how many users can be created.
      */
-    private boolean isUserLimitReached() {
-        synchronized (mInstallLock) {
-            int nUsers = mUsers.size();
-            int userLimit = mContext.getResources().getInteger(
-                    com.android.internal.R.integer.config_multiuserMaximumUsers);
-            return nUsers >= userLimit;
-        }
+    private boolean isUserLimitReachedLocked() {
+        int nUsers = mUsers.size();
+        return nUsers >= mUserLimit;
     }
 
     /**
@@ -535,28 +546,31 @@
     public UserInfo createUser(String name, int flags) {
         checkManageUsersPermission("Only the system can create users");
 
-        if (isUserLimitReached()) return null;
-
-        int userId = getNextAvailableId();
-        UserInfo userInfo = new UserInfo(userId, name, null, flags);
-        File userPath = new File(mBaseUserPath, Integer.toString(userId));
-        synchronized (mInstallLock) {
-            synchronized (mPackagesLock) {
-                userInfo.serialNumber = mNextSerialNumber++;
-                mUsers.put(userId, userInfo);
-                writeUserListLocked();
-                writeUserLocked(userInfo);
-                updateUserIdsLocked();
-                mPm.createNewUserLILPw(userId, userPath);
+        final long ident = Binder.clearCallingIdentity();
+        final UserInfo userInfo;
+        try {
+            synchronized (mInstallLock) {
+                synchronized (mPackagesLock) {
+                    if (isUserLimitReachedLocked()) return null;
+                    int userId = getNextAvailableIdLocked();
+                    userInfo = new UserInfo(userId, name, null, flags);
+                    File userPath = new File(mBaseUserPath, Integer.toString(userId));
+                    userInfo.serialNumber = mNextSerialNumber++;
+                    mUsers.put(userId, userInfo);
+                    writeUserListLocked();
+                    writeUserLocked(userInfo);
+                    updateUserIdsLocked();
+                    mPm.createNewUserLILPw(userId, userPath);
+                }
             }
-        }
-        if (userInfo != null) {
-            Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
-            addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
-            mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_BOOT_COMPLETED),
-                    new UserHandle(userInfo.id));
-            mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
-                    android.Manifest.permission.MANAGE_USERS);
+            if (userInfo != null) {
+                Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
+                addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
+                mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+                        android.Manifest.permission.MANAGE_USERS);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
         return userInfo;
     }
@@ -614,9 +628,15 @@
         }
 
         // Let other services shutdown any activity
-        Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
-        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
-        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
+        long ident = Binder.clearCallingIdentity();
+        try {
+            Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
+            addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+            mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+                    android.Manifest.permission.MANAGE_USERS);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
     private void removeDirectoryRecursive(File parent) {
@@ -666,7 +686,7 @@
      * for data and battery stats collection, or unexpected cross-talk.
      * @return
      */
-    private int getNextAvailableId() {
+    private int getNextAvailableIdLocked() {
         synchronized (mPackagesLock) {
             int i = 0;
             while (i < Integer.MAX_VALUE) {