Flesh out multi-user in am commands.

Now we default to the current user instead of user 0 for most commands
(except where we can do the command for all users).

Many more commands take a user argument: force-stop, kill, profile,
dumpheap.

Improved help text.

Change-Id: I719a13b4d31b668f57ca21e51d7043ac3e0d4e1b
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c28afb2..73e82ab 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -37,14 +37,12 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.provider.Settings;
 import android.server.search.SearchManagerService;
 import android.service.dreams.DreamManagerService;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.view.Display;
 import android.view.WindowManager;
 
 import com.android.internal.os.BinderInternal;
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 2975880..3bb95a8 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1763,12 +1763,11 @@
             if (ActivityManager.checkUidPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     uid) == PackageManager.PERMISSION_GRANTED) {
-                List<UserInfo> users = mAm.getUserManager().getUsers();
-                for (int ui=0; ui<users.size() && res.size() < maxNum; ui++) {
-                    final UserInfo user = users.get(ui);
-                    if (mServiceMap.getAllServices(user.id).size() > 0) {
+                int[] users = mAm.getUsersLocked();
+                for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
+                    if (mServiceMap.getAllServices(users[ui]).size() > 0) {
                         Iterator<ServiceRecord> it = mServiceMap.getAllServices(
-                                user.id).iterator();
+                                users[ui]).iterator();
                         while (it.hasNext() && res.size() < maxNum) {
                             res.add(makeRunningServiceInfoLocked(it.next()));
                         }
@@ -1873,14 +1872,13 @@
 
         pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)");
         try {
-            List<UserInfo> users = mAm.getUserManager().getUsers();
-            for (int ui=0; ui<users.size(); ui++) {
-                final UserInfo user = users.get(ui);
-                if (mServiceMap.getAllServices(user.id).size() > 0) {
+            int[] users = mAm.getUsersLocked();
+            for (int user : users) {
+                if (mServiceMap.getAllServices(user).size() > 0) {
                     boolean printed = false;
                     long nowReal = SystemClock.elapsedRealtime();
                     Iterator<ServiceRecord> it = mServiceMap.getAllServices(
-                            user.id).iterator();
+                            user).iterator();
                     needSep = false;
                     while (it.hasNext()) {
                         ServiceRecord r = it.next();
@@ -1891,10 +1889,10 @@
                             continue;
                         }
                         if (!printed) {
-                            if (ui > 0) {
+                            if (user != 0) {
                                 pw.println();
                             }
-                            pw.println("  User " + user.id + " active services:");
+                            pw.println("  User " + user + " active services:");
                             printed = true;
                         }
                         if (needSep) {
@@ -2070,32 +2068,30 @@
             int opti, boolean dumpAll) {
         ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
 
-        List<UserInfo> users = mAm.getUserManager().getUsers();
-        if ("all".equals(name)) {
-            synchronized (this) {
-                for (UserInfo user : users) {
-                    for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
+        synchronized (this) {
+            int[] users = mAm.getUsersLocked();
+            if ("all".equals(name)) {
+                for (int user : users) {
+                    for (ServiceRecord r1 : mServiceMap.getAllServices(user)) {
                         services.add(r1);
                     }
                 }
-            }
-        } else {
-            ComponentName componentName = name != null
-                    ? ComponentName.unflattenFromString(name) : null;
-            int objectId = 0;
-            if (componentName == null) {
-                // Not a '/' separated full component name; maybe an object ID?
-                try {
-                    objectId = Integer.parseInt(name, 16);
-                    name = null;
-                    componentName = null;
-                } catch (RuntimeException e) {
+            } else {
+                ComponentName componentName = name != null
+                        ? ComponentName.unflattenFromString(name) : null;
+                int objectId = 0;
+                if (componentName == null) {
+                    // Not a '/' separated full component name; maybe an object ID?
+                    try {
+                        objectId = Integer.parseInt(name, 16);
+                        name = null;
+                        componentName = null;
+                    } catch (RuntimeException e) {
+                    }
                 }
-            }
 
-            synchronized (this) {
-                for (UserInfo user : users) {
-                    for (ServiceRecord r1 : mServiceMap.getAllServices(user.id)) {
+                for (int user : users) {
+                    for (ServiceRecord r1 : mServiceMap.getAllServices(user)) {
                         if (componentName != null) {
                             if (r1.name.equals(componentName)) {
                                 services.add(r1);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0b2d769..ca90368 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -27,6 +27,7 @@
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.pm.UserManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.Zygote;
@@ -99,6 +100,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IPermissionController;
+import android.os.IUserManager;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -112,7 +114,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.text.format.Time;
 import android.util.EventLog;
@@ -811,7 +812,7 @@
     static ActivityThread mSystemThread;
 
     private int mCurrentUserId;
-    private UserManager mUserManager;
+    private UserManagerService mUserManager;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
         final ProcessRecord mApp;
@@ -3401,10 +3402,12 @@
     }
     
     public boolean clearApplicationUserData(final String packageName,
-            final IPackageDataObserver observer, final int userId) {
+            final IPackageDataObserver observer, int userId) {
         enforceNotIsolatedCaller("clearApplicationUserData");
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
+        userId = handleIncomingUserLocked(pid, uid,
+                userId, false, true, "clearApplicationUserData", null);
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -3446,7 +3449,7 @@
         return true;
     }
 
-    public void killBackgroundProcesses(final String packageName) {
+    public void killBackgroundProcesses(final String packageName, int userId) {
         if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
                 != PackageManager.PERMISSION_GRANTED &&
                 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
@@ -3458,22 +3461,23 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        
-        int userId = UserHandle.getCallingUserId();
+
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, true, true, "killBackgroundProcesses", null);
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
-            int pkgUid = -1;
             synchronized(this) {
+                int appId = -1;
                 try {
-                    pkgUid = pm.getPackageUid(packageName, userId);
+                    appId = UserHandle.getAppId(pm.getPackageUid(packageName, 0));
                 } catch (RemoteException e) {
                 }
-                if (pkgUid == -1) {
+                if (appId == -1) {
                     Slog.w(TAG, "Invalid packageName: " + packageName);
                     return;
                 }
-                killPackageProcessesLocked(packageName, pkgUid, -1,
+                killPackageProcessesLocked(packageName, appId, userId,
                         ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");
             }
         } finally {
@@ -3523,7 +3527,7 @@
         }
     }
 
-    public void forceStopPackage(final String packageName) {
+    public void forceStopPackage(final String packageName, int userId) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: forceStopPackage() from pid="
@@ -3533,27 +3537,34 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        final int userId = UserHandle.getCallingUserId();
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, true, true, "forceStopPackage", null);
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
-            int pkgUid = -1;
             synchronized(this) {
-                try {
-                    pkgUid = pm.getPackageUid(packageName, userId);
-                } catch (RemoteException e) {
-                }
-                if (pkgUid == -1) {
-                    Slog.w(TAG, "Invalid packageName: " + packageName);
-                    return;
-                }
-                forceStopPackageLocked(packageName, pkgUid);
-                try {
-                    pm.setPackageStoppedState(packageName, true, userId);
-                } catch (RemoteException e) {
-                } catch (IllegalArgumentException e) {
-                    Slog.w(TAG, "Failed trying to unstop package "
-                            + packageName + ": " + e);
+                int[] users = userId == UserHandle.USER_ALL
+                        ? getUsersLocked() : new int[] { userId };
+                for (int user : users) {
+                    int pkgUid = -1;
+                    try {
+                        pkgUid = pm.getPackageUid(packageName, user);
+                    } catch (RemoteException e) {
+                    }
+                    if (pkgUid == -1) {
+                        Slog.w(TAG, "Invalid packageName: " + packageName);
+                        continue;
+                    }
+                    try {
+                        pm.setPackageStoppedState(packageName, true, user);
+                    } catch (RemoteException e) {
+                    } catch (IllegalArgumentException e) {
+                        Slog.w(TAG, "Failed trying to unstop package "
+                                + packageName + ": " + e);
+                    }
+                    if (isUserRunningLocked(user)) {
+                        forceStopPackageLocked(packageName, pkgUid);
+                    }
                 }
             }
         } finally {
@@ -3685,8 +3696,8 @@
     }
 
     private void forceStopPackageLocked(final String packageName, int uid) {
-        forceStopPackageLocked(packageName, uid, false, false, true, false,
-                UserHandle.getUserId(uid));
+        forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
+                false, true, false, UserHandle.getUserId(uid));
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         if (!mProcessesReady) {
@@ -13688,7 +13699,7 @@
         mAutoStopProfiler = false;
     }
 
-    public boolean profileControl(String process, boolean start,
+    public boolean profileControl(String process, int userId, boolean start,
             String path, ParcelFileDescriptor fd, int profileType) throws RemoteException {
 
         try {
@@ -13707,22 +13718,7 @@
 
                 ProcessRecord proc = null;
                 if (process != null) {
-                    try {
-                        int pid = Integer.parseInt(process);
-                        synchronized (mPidsSelfLocked) {
-                            proc = mPidsSelfLocked.get(pid);
-                        }
-                    } catch (NumberFormatException e) {
-                    }
-
-                    if (proc == null) {
-                        HashMap<String, SparseArray<ProcessRecord>> all
-                                = mProcessNames.getMap();
-                        SparseArray<ProcessRecord> procs = all.get(process);
-                        if (procs != null && procs.size() > 0) {
-                            proc = procs.valueAt(0);
-                        }
-                    }
+                    proc = findProcessLocked(process, userId, "profileControl");
                 }
 
                 if (start && (proc == null || proc.thread == null)) {
@@ -13766,7 +13762,40 @@
         }
     }
 
-    public boolean dumpHeap(String process, boolean managed,
+    private ProcessRecord findProcessLocked(String process, int userId, String callName) {
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, true, true, callName, null);
+        ProcessRecord proc = null;
+        try {
+            int pid = Integer.parseInt(process);
+            synchronized (mPidsSelfLocked) {
+                proc = mPidsSelfLocked.get(pid);
+            }
+        } catch (NumberFormatException e) {
+        }
+
+        if (proc == null) {
+            HashMap<String, SparseArray<ProcessRecord>> all
+                    = mProcessNames.getMap();
+            SparseArray<ProcessRecord> procs = all.get(process);
+            if (procs != null && procs.size() > 0) {
+                proc = procs.valueAt(0);
+                if (userId != UserHandle.USER_ALL && proc.userId != userId) {
+                    for (int i=1; i<procs.size(); i++) {
+                        ProcessRecord thisProc = procs.valueAt(i);
+                        if (thisProc.userId == userId) {
+                            proc = thisProc;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        return proc;
+    }
+
+    public boolean dumpHeap(String process, int userId, boolean managed,
             String path, ParcelFileDescriptor fd) throws RemoteException {
 
         try {
@@ -13783,24 +13812,7 @@
                     throw new IllegalArgumentException("null fd");
                 }
 
-                ProcessRecord proc = null;
-                try {
-                    int pid = Integer.parseInt(process);
-                    synchronized (mPidsSelfLocked) {
-                        proc = mPidsSelfLocked.get(pid);
-                    }
-                } catch (NumberFormatException e) {
-                }
-
-                if (proc == null) {
-                    HashMap<String, SparseArray<ProcessRecord>> all
-                            = mProcessNames.getMap();
-                    SparseArray<ProcessRecord> procs = all.get(process);
-                    if (procs != null && procs.size() > 0) {
-                        proc = procs.valueAt(0);
-                    }
-                }
-
+                ProcessRecord proc = findProcessLocked(process, userId, "dumpHeap");
                 if (proc == null || proc.thread == null) {
                     throw new IllegalArgumentException("Unknown process: " + process);
                 }
@@ -14018,7 +14030,7 @@
             throw new SecurityException(msg);
         }
         synchronized (this) {
-            return getUserManager().getUserInfo(mCurrentUserId);
+            return getUserManagerLocked().getUserInfo(mCurrentUserId);
         }
     }
 
@@ -14034,19 +14046,32 @@
             throw new SecurityException(msg);
         }
         synchronized (this) {
-            UserStartedState state = mStartedUsers.get(userId);
-            return state != null && state.mState != UserStartedState.STATE_STOPPING;
+            return isUserRunningLocked(userId);
         }
     }
 
-    private boolean userExists(int userId) {
-        UserInfo user = getUserManager().getUserInfo(userId);
-        return user != null;
+    boolean isUserRunningLocked(int userId) {
+        UserStartedState state = mStartedUsers.get(userId);
+        return state != null && state.mState != UserStartedState.STATE_STOPPING;
     }
 
-    UserManager getUserManager() {
+    private boolean userExists(int userId) {
+        if (userId == 0) {
+            return true;
+        }
+        UserManagerService ums = getUserManagerLocked();
+        return ums != null ? (ums.getUserInfo(userId) != null) : false;
+    }
+
+    int[] getUsersLocked() {
+        UserManagerService ums = getUserManagerLocked();
+        return ums != null ? ums.getUserIds() : new int[] { 0 };
+    }
+
+    UserManagerService getUserManagerLocked() {
         if (mUserManager == null) {
-            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+            IBinder b = ServiceManager.getService(Context.USER_SERVICE);
+            mUserManager = (UserManagerService)IUserManager.Stub.asInterface(b);
         }
         return mUserManager;
     }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index a13c16e..3391668 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -281,7 +281,7 @@
      * cache it elsewhere.
      * @return the array of user ids.
      */
-    int[] getUserIds() {
+    public int[] getUserIds() {
         synchronized (mPackagesLock) {
             return mUserIds;
         }