Multi-user - wallpaper service

- Allow each user to have their own wallpaper (live or static).
- Migrate old wallpaper on upgrade.
- Update SystemBackupAgent to backup/restore from primary user's
  new wallpaper directory.

Reduce dependency on Binder.getOrigCallingUser() by passing the
userId for bindService.

Change-Id: I19c8c3296d3d2efa7f28f951d4b84407489e2166
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 5a70dcf..f66b99b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -49,6 +49,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.app.WallpaperManager;
 import android.app.backup.IBackupManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -1363,24 +1364,6 @@
      */
     final ArrayList mCancelledThumbnails = new ArrayList();
 
-    /**
-     * All of the currently running global content providers.  Keys are a
-     * string containing the provider name and values are a
-     * ContentProviderRecord object containing the data about it.  Note
-     * that a single provider may be published under multiple names, so
-     * there may be multiple entries here for a single one in mProvidersByClass.
-     */
-    final HashMap<String, ContentProviderRecord> mProvidersByName
-            = new HashMap<String, ContentProviderRecord>();
-
-    /**
-     * All of the currently running global content providers.  Keys are a
-     * string containing the provider's implementation class and values are a
-     * ContentProviderRecord object containing the data about it.
-     */
-    final HashMap<ComponentName, ContentProviderRecord> mProvidersByClass
-            = new HashMap<ComponentName, ContentProviderRecord>();
-
     final ProviderMap mProviderMap = new ProviderMap();
 
     /**
@@ -4434,7 +4417,7 @@
         }
 
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-        for (ContentProviderRecord provider : mProvidersByClass.values()) {
+        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
             if (provider.info.packageName.equals(name)
                     && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
                 if (!doit) {
@@ -11361,18 +11344,18 @@
     }
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
-            String resolvedType, int callingPid, int callingUid) {
+            String resolvedType, int callingPid, int callingUid, int userId) {
         ServiceRecord r = null;
         if (DEBUG_SERVICE)
             Slog.v(TAG, "retrieveServiceLocked: " + service + " type=" + resolvedType
-                    + " origCallingUid=" + callingUid);
+                    + " callingUid=" + callingUid);
 
         if (service.getComponent() != null) {
-            r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
+            r = mServiceMap.getServiceByName(service.getComponent(), userId);
         }
         if (r == null) {
             Intent.FilterComparison filter = new Intent.FilterComparison(service);
-            r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
+            r = mServiceMap.getServiceByIntent(filter, userId);
         }
         if (r == null) {
             try {
@@ -11386,13 +11369,12 @@
                           ": not found");
                     return null;
                 }
-                if (Binder.getOrigCallingUser() > 0) {
-                    sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo,
-                            Binder.getOrigCallingUser());
+                if (userId > 0) {
+                    sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
                 }
                 ComponentName name = new ComponentName(
                         sInfo.applicationInfo.packageName, sInfo.name);
-                r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
+                r = mServiceMap.getServiceByName(name, userId);
                 if (r == null) {
                     Intent.FilterComparison filter = new Intent.FilterComparison(
                             service.cloneFilter());
@@ -11956,7 +11938,7 @@
 
             ServiceLookupResult res =
                 retrieveServiceLocked(service, resolvedType,
-                        callingPid, callingUid);
+                        callingPid, callingUid, UserId.getUserId(callingUid));
             if (res == null) {
                 return null;
             }
@@ -12206,13 +12188,15 @@
     
     public int bindService(IApplicationThread caller, IBinder token,
             Intent service, String resolvedType,
-            IServiceConnection connection, int flags) {
+            IServiceConnection connection, int flags, int userId) {
         enforceNotIsolatedCaller("bindService");
         // Refuse possible leaked file descriptors
         if (service != null && service.hasFileDescriptors() == true) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
+        checkValidCaller(Binder.getCallingUid(), userId);
+
         synchronized(this) {
             if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
                     + " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -12262,7 +12246,7 @@
             
             ServiceLookupResult res =
                 retrieveServiceLocked(service, resolvedType,
-                        Binder.getCallingPid(), Binder.getOrigCallingUid());
+                        Binder.getCallingPid(), Binder.getCallingUid(), userId);
             if (res == null) {
                 return 0;
             }
@@ -15259,6 +15243,25 @@
 
     private int mCurrentUserId;
     private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
+    private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
+
+    public interface UserListener {
+        public void onUserChanged(int userId);
+
+        public void onUserAdded(int userId);
+
+        public void onUserRemoved(int userId);
+
+        public void onUserLoggedOut(int userId);
+    }
+
+    public void addUserListener(UserListener listener) {
+        synchronized (this) {
+            if (!mUserListeners.contains(listener)) {
+                mUserListeners.add(listener);
+            }
+        }
+    }
 
     public boolean switchUser(int userId) {
         final int callingUid = Binder.getCallingUid();
@@ -15269,6 +15272,8 @@
         if (mCurrentUserId == userId)
             return true;
 
+        ArrayList<UserListener> listeners;
+
         synchronized (this) {
             // Check if user is already logged in, otherwise check if user exists first before
             // adding to the list of logged in users.
@@ -15284,6 +15289,12 @@
             if (!haveActivities) {
                 startHomeActivityLocked(userId);
             }
+
+            listeners = (ArrayList<UserListener>) mUserListeners.clone();
+        }
+        // Inform the listeners
+        for (UserListener listener : listeners) {
+            listener.onUserChanged(userId);
         }
         return true;
     }
@@ -15303,6 +15314,12 @@
         return false;
     }
 
+    private void checkValidCaller(int uid, int userId) {
+        if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
+
+        throw new SecurityException("Caller uid=" + uid
+                + " is not privileged to communicate with user=" + userId);
+    }
 
     private int applyUserId(int uid, int userId) {
         return UserId.getUid(userId, uid);