Fix installing applications from non-primary users.

We also now send the correct broadcasts to each user.

You no longer need to be running the shell as root
to be able to create/remove users.

Also added some more man page material to the pm command, and
got rid of a bunch of showUsage() calls that now make error
messages completely buried because of how large the usage info
has become.

And the package manager now shows the user each historical broadcast
was sent to.

Change-Id: Iab42498e1352a0c023069139c80fc04d2d69ab4b
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 8cc4e69..e621ceb 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -178,11 +178,6 @@
             return;
         }
 
-        if ("list-users".equals(op)) {
-            runListUsers();
-            return;
-        }
-
         try {
             if (args.length == 1) {
                 if (args[0].equalsIgnoreCase("-l")) {
@@ -222,7 +217,6 @@
         String type = nextArg();
         if (type == null) {
             System.err.println("Error: didn't specify type of data to list");
-            showUsage();
             return;
         }
         if ("package".equals(type) || "packages".equals(type)) {
@@ -241,7 +235,6 @@
             runListUsers();
         } else {
             System.err.println("Error: unknown list type '" + type + "'");
-            showUsage();
         }
     }
 
@@ -276,13 +269,11 @@
                     getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
                 } else {
                     System.err.println("Error: Unknown option: " + opt);
-                    showUsage();
                     return;
                 }
             }
         } catch (RuntimeException ex) {
             System.err.println("Error: " + ex.toString());
-            showUsage();
             return;
         }
 
@@ -431,13 +422,11 @@
                     targetPackage = opt;
                 } else {
                     System.err.println("Error: Unknown option: " + opt);
-                    showUsage();
                     return;
                 }
             }
         } catch (RuntimeException ex) {
             System.err.println("Error: " + ex.toString());
-            showUsage();
             return;
         }
 
@@ -529,7 +518,6 @@
                     dangerousOnly = true;
                 } else {
                     System.err.println("Error: Unknown option: " + opt);
-                    showUsage();
                     return;
                 }
             }
@@ -678,7 +666,6 @@
         String pkg = nextArg();
         if (pkg == null) {
             System.err.println("Error: no package specified");
-            showUsage();
             return;
         }
         displayPackageFilePath(pkg);
@@ -736,20 +723,17 @@
         String arg = nextArg();
         if (arg == null) {
             System.err.println("Error: no install location specified.");
-            showUsage();
             return;
         }
         try {
             loc = Integer.parseInt(arg);
         } catch (NumberFormatException e) {
             System.err.println("Error: install location has to be a number.");
-            showUsage();
             return;
         }
         try {
             if (!mPm.setInstallLocation(loc)) {
                 System.err.println("Error: install location has to be a number.");
-                showUsage();
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
@@ -800,7 +784,6 @@
                 installerPackageName = nextOptionData();
                 if (installerPackageName == null) {
                     System.err.println("Error: no value specified for -i");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("-t")) {
@@ -817,61 +800,52 @@
                 algo = nextOptionData();
                 if (algo == null) {
                     System.err.println("Error: must supply argument for --algo");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--iv")) {
                 iv = hexToBytes(nextOptionData());
                 if (iv == null) {
                     System.err.println("Error: must supply argument for --iv");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--key")) {
                 key = hexToBytes(nextOptionData());
                 if (key == null) {
                     System.err.println("Error: must supply argument for --key");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--macalgo")) {
                 macAlgo = nextOptionData();
                 if (macAlgo == null) {
                     System.err.println("Error: must supply argument for --macalgo");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--mackey")) {
                 macKey = hexToBytes(nextOptionData());
                 if (macKey == null) {
                     System.err.println("Error: must supply argument for --mackey");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--tag")) {
                 tag = hexToBytes(nextOptionData());
                 if (tag == null) {
                     System.err.println("Error: must supply argument for --tag");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--originating-uri")) {
                 originatingUriString = nextOptionData();
                 if (originatingUriString == null) {
                     System.err.println("Error: must supply argument for --originating-uri");
-                    showUsage();
                     return;
                 }
             } else if (opt.equals("--referrer")) {
                 referrer = nextOptionData();
                 if (referrer == null) {
                     System.err.println("Error: must supply argument for --referrer");
-                    showUsage();
                     return;
                 }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
-                showUsage();
                 return;
             }
         }
@@ -881,7 +855,6 @@
                 || tag != null) {
             if (algo == null || iv == null || key == null) {
                 System.err.println("Error: all of --algo, --iv, and --key must be specified");
-                showUsage();
                 return;
             }
 
@@ -889,7 +862,6 @@
                 if (macAlgo == null || macKey == null || tag == null) {
                     System.err.println("Error: all of --macalgo, --mackey, and --tag must "
                             + "be specified");
-                    showUsage();
                     return;
                 }
             }
@@ -938,7 +910,6 @@
             apkURI = Uri.fromFile(new File(apkFilePath));
         } else {
             System.err.println("Error: no package specified");
-            showUsage();
             return;
         }
 
@@ -1012,23 +983,16 @@
     }
 
     public void runCreateUser() {
-        // Need to be run as root
-        if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: create-user must be run as root");
-            return;
-        }
         String name;
         String arg = nextArg();
         if (arg == null) {
             System.err.println("Error: no user name specified.");
-            showUsage();
             return;
         }
         name = arg;
         try {
             if (mUm.createUser(name, 0) == null) {
                 System.err.println("Error: couldn't create User.");
-                showUsage();
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
@@ -1038,29 +1002,21 @@
     }
 
     public void runRemoveUser() {
-        // Need to be run as root
-        if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: remove-user must be run as root");
-            return;
-        }
         int userId;
         String arg = nextArg();
         if (arg == null) {
             System.err.println("Error: no user id specified.");
-            showUsage();
             return;
         }
         try {
             userId = Integer.parseInt(arg);
         } catch (NumberFormatException e) {
-            System.err.println("Error: user id has to be a number.");
-            showUsage();
+            System.err.println("Error: user id '" + arg + "' is not a number.");
             return;
         }
         try {
             if (!mUm.removeUser(userId)) {
-                System.err.println("Error: couldn't remove user.");
-                showUsage();
+                System.err.println("Error: couldn't remove user #" + userId + ".");
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
@@ -1069,11 +1025,6 @@
     }
 
     public void runListUsers() {
-        // Need to be run as root
-        if (Process.myUid() != ROOT_UID) {
-            System.err.println("Error: list-users must be run as root");
-            return;
-        }
         try {
             List<UserInfo> users = mUm.getUsers();
             if (users == null) {
@@ -1521,6 +1472,8 @@
         System.err.println("");
         System.err.println("pm list features: prints all features of the system.");
         System.err.println("");
+        System.err.println("pm list users: prints all users on the system.");
+        System.err.println("");
         System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
         System.err.println("");
         System.err.println("pm install: installs a package to the system.  Options:");
@@ -1557,5 +1510,11 @@
         System.err.println("    2 [external]: Install on external media");
         System.err.println("");
         System.err.println("pm trim-caches: trim cache files to reach the given free space.");
+        System.err.println("");
+        System.err.println("pm create-user: create a new user with the given USER_NAME,");
+        System.err.println("  printing the new user identifier of the user.");
+        System.err.println("");
+        System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
+        System.err.println("  deleting all data associated with that user");
     }
 }
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 1b69daf..a19b9b4 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -173,7 +173,10 @@
     <assign-permission name="android.permission.SET_SCREEN_COMPATIBILITY" uid="shell" />
     <assign-permission name="android.permission.READ_EXTERNAL_STORAGE" uid="shell" />
     <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
-
+    <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="shell" />
+    <assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="shell" />
+    <assign-permission name="android.permission.MANAGE_USERS" uid="shell" />
+    
     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
     <assign-permission name="android.permission.ACCESS_DRM" uid="media" />
     <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2b4f8b1..5921d88 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9404,9 +9404,15 @@
     boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
-        
+        boolean onlyHistory = false;
+
+        if ("history".equals(dumpPackage)) {
+            onlyHistory = true;
+            dumpPackage = null;
+        }
+
         pw.println("ACTIVITY MANAGER BROADCAST STATE (dumpsys activity broadcasts)");
-        if (dumpAll) {
+        if (!onlyHistory && dumpAll) {
             if (mRegisteredReceivers.size() > 0) {
                 boolean printed = false;
                 Iterator it = mRegisteredReceivers.values().iterator();
@@ -9439,7 +9445,7 @@
 
         needSep = true;
         
-        if (mStickyBroadcasts != null && dumpPackage == null) {
+        if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
             if (needSep) {
                 pw.println();
             }
@@ -9471,7 +9477,7 @@
             needSep = true;
         }
         
-        if (dumpAll) {
+        if (!onlyHistory && dumpAll) {
             pw.println();
             for (BroadcastQueue queue : mBroadcastQueues) {
                 pw.println("  mBroadcastsScheduled [" + queue.mQueueName + "]="
@@ -10982,7 +10988,7 @@
                     BroadcastQueue queue = broadcastQueueForIntent(intent);
                     BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                             null, -1, -1, null, receivers, null, 0, null, null,
-                            false, true, true, false);
+                            false, true, true, false, -1);
                     queue.enqueueParallelBroadcastLocked(r);
                     queue.scheduleBroadcastsLocked();
                 }
@@ -11288,7 +11294,7 @@
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     registeredReceivers, resultTo, resultCode, resultData, map,
-                    ordered, sticky, false, onlySendToCaller);
+                    ordered, sticky, false, onlySendToCaller, userId);
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing parallel broadcast " + r);
             final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
@@ -11378,7 +11384,7 @@
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, requiredPermission,
                     receivers, resultTo, resultCode, resultData, map, ordered,
-                    sticky, false, onlySendToCaller);
+                    sticky, false, onlySendToCaller, userId);
             if (DEBUG_BROADCAST) Slog.v(
                     TAG, "Enqueueing ordered broadcast " + r
                     + ": prev had " + queue.mOrderedBroadcasts.size());
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 799b609..87f1111 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -45,6 +45,7 @@
     final boolean sticky;   // originated from existing sticky data?
     final boolean initialSticky; // initial broadcast from register to sticky?
     final boolean onlySendToCaller; // only allow receipt by sender's components?
+    final int userId;       // user id this broadcast was for
     final String requiredPermission; // a permission the caller has required
     final List receivers;   // contains BroadcastFilter and ResolveInfo
     IIntentReceiver resultTo; // who receives final result if non-null
@@ -80,7 +81,7 @@
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
 
-        pw.print(prefix); pw.println(this);
+        pw.print(prefix); pw.print(this); pw.print(" to user "); pw.println(userId);
         pw.print(prefix); pw.println(intent);
         if (sticky) {
             Bundle bundle = intent.getExtras();
@@ -141,14 +142,15 @@
                         pw.println(curReceiver.applicationInfo.sourceDir);
             }
         }
-        String stateStr = " (?)";
-        switch (state) {
-            case IDLE:              stateStr=" (IDLE)"; break;
-            case APP_RECEIVE:       stateStr=" (APP_RECEIVE)"; break;
-            case CALL_IN_RECEIVE:   stateStr=" (CALL_IN_RECEIVE)"; break;
-            case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+        if (state != IDLE) {
+            String stateStr = " (?)";
+            switch (state) {
+                case APP_RECEIVE:       stateStr=" (APP_RECEIVE)"; break;
+                case CALL_IN_RECEIVE:   stateStr=" (CALL_IN_RECEIVE)"; break;
+                case CALL_DONE_RECEIVE: stateStr=" (CALL_DONE_RECEIVE)"; break;
+            }
+            pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
         }
-        pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr);
         final int N = receivers != null ? receivers.size() : 0;
         String p2 = prefix + "  ";
         PrintWriterPrinter printer = new PrintWriterPrinter(pw);
@@ -168,7 +170,8 @@
             int _callingPid, int _callingUid, String _requiredPermission,
             List _receivers, IIntentReceiver _resultTo, int _resultCode,
             String _resultData, Bundle _resultExtras, boolean _serialized,
-            boolean _sticky, boolean _initialSticky, boolean _onlySendToCaller) {
+            boolean _sticky, boolean _initialSticky, boolean _onlySendToCaller,
+            int _userId) {
         queue = _queue;
         intent = _intent;
         callerApp = _callerApp;
@@ -185,6 +188,7 @@
         sticky = _sticky;
         initialSticky = _initialSticky;
         onlySendToCaller = _onlySendToCaller;
+        userId = _userId;
         nextReceiver = 0;
         state = IDLE;
     }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 0345df1..65d1882 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -704,20 +704,56 @@
                             res.removedInfo.sendBroadcast(false, true);
                             Bundle extras = new Bundle(1);
                             extras.putInt(Intent.EXTRA_UID, res.uid);
+                            // Determine the set of users who are adding this
+                            // package for the first time vs. those who are seeing
+                            // an update.
+                            int[] firstUsers;
+                            int[] updateUsers = new int[0];
+                            if (res.origUsers == null || res.origUsers.length == 0) {
+                                firstUsers = res.newUsers;
+                            } else {
+                                firstUsers = new int[0];
+                                for (int i=0; i<res.newUsers.length; i++) {
+                                    int user = res.newUsers[i];
+                                    boolean isNew = true;
+                                    for (int j=0; j<res.origUsers.length; j++) {
+                                        if (res.origUsers[j] == user) {
+                                            isNew = false;
+                                            break;
+                                        }
+                                    }
+                                    if (isNew) {
+                                        int[] newFirst = new int[firstUsers.length+1];
+                                        System.arraycopy(firstUsers, 0, newFirst, 0,
+                                                firstUsers.length);
+                                        newFirst[firstUsers.length] = user;
+                                        firstUsers = newFirst;
+                                    } else {
+                                        int[] newUpdate = new int[updateUsers.length+1];
+                                        System.arraycopy(updateUsers, 0, newUpdate, 0,
+                                                updateUsers.length);
+                                        newUpdate[updateUsers.length] = user;
+                                        updateUsers = newUpdate;
+                                    }
+                                }
+                            }
+                            sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
+                                    res.pkg.applicationInfo.packageName,
+                                    extras, null, null, firstUsers);
                             final boolean update = res.removedInfo.removedPackage != null;
                             if (update) {
                                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras, null, null, res.users);
+                                    extras, null, null, updateUsers);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras, null, null, res.users);
+                                        extras, null, null, updateUsers);
                                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                         null, null,
-                                        res.pkg.applicationInfo.packageName, null, res.users);
+                                        res.pkg.applicationInfo.packageName, null, updateUsers);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -5337,8 +5373,10 @@
         public void onEvent(int event, String path) {
             String removedPackage = null;
             int removedUid = -1;
+            int[] removedUsers = null;
             String addedPackage = null;
             int addedUid = -1;
+            int[] addedUsers = null;
 
             // TODO post a message to the handler to obtain serial ordering
             synchronized (mInstallLock) {
@@ -5367,6 +5405,15 @@
                 // reader
                 synchronized (mPackages) {
                     p = mAppDirs.get(fullPathStr);
+                    if (p != null) {
+                        PackageSetting ps = mSettings.mPackages.get(p.applicationInfo.packageName);
+                        if (ps != null) {
+                            removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+                        } else {
+                            removedUsers = sUserManager.getUserIds();
+                        }
+                    }
+                    addedUsers = sUserManager.getUserIds();
                 }
                 if ((event&REMOVE_EVENTS) != 0) {
                     if (p != null) {
@@ -5384,7 +5431,7 @@
                                 PackageParser.PARSE_CHATTY |
                                 PackageParser.PARSE_MUST_BE_APK,
                                 SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
-                                System.currentTimeMillis(), null);
+                                System.currentTimeMillis(), UserHandle.ALL);
                         if (p != null) {
                             /*
                              * TODO this seems dangerous as the package may have
@@ -5413,13 +5460,13 @@
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null, null);
+                        extras, null, null, removedUsers);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
-                        extras, null, null, null);
+                        extras, null, null, addedUsers);
             }
         }
 
@@ -5462,7 +5509,7 @@
         if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
             user = UserHandle.ALL;
         } else {
-            user = Process.myUserHandle();
+            user = new UserHandle(UserHandle.getUserId(uid));
         }
 
         final int filteredFlags;
@@ -7205,7 +7252,10 @@
     class PackageInstalledInfo {
         String name;
         int uid;
-        int[] users;
+        // The set of users that originally had this package installed.
+        int[] origUsers;
+        // The set of users that now have this package installed.
+        int[] newUsers;
         PackageParser.Package pkg;
         int returnCode;
         PackageRemovedInfo removedInfo;
@@ -7355,7 +7405,7 @@
                 int oldScanMode = (oldOnSd ? 0 : SCAN_MONITOR) | SCAN_UPDATE_SIGNATURE
                         | SCAN_UPDATE_TIME;
                 if (scanPackageLI(restoreFile, oldParseFlags, oldScanMode,
-                        origUpdateTime, user) == null) {
+                        origUpdateTime, null) == null) {
                     Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade");
                     return;
                 }
@@ -7504,10 +7554,6 @@
                     UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0
                             ? UPDATE_PERMISSIONS_ALL : 0));
             res.name = pkgName;
-            PackageSetting ps = mSettings.mPackages.get(pkgName);
-            if (ps != null) {
-                res.users = ps.getInstalledUsers(sUserManager.getUserIds());
-            }
             res.uid = newPackage.applicationInfo.uid;
             res.pkg = newPackage;
             mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
@@ -7605,6 +7651,7 @@
                     systemApp = (ps.pkg.applicationInfo.flags &
                             ApplicationInfo.FLAG_SYSTEM) != 0;
                 }
+                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
             }
         }
 
@@ -7627,12 +7674,12 @@
                     installerPackageName, res);
         } else {
             installNewPackageLI(pkg, parseFlags, scanMode, args.user,
-                    installerPackageName,res);
+                    installerPackageName, res);
         }
         synchronized (mPackages) {
-            PackageSetting ps = mSettings.mPackages.get(pkgName);
+            final PackageSetting ps = mSettings.mPackages.get(pkgName);
             if (ps != null) {
-                res.users = ps.getInstalledUsers(sUserManager.getUserIds());
+                res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
             }
         }
     }
@@ -7858,7 +7905,8 @@
             if (outInfo != null) {
                 outInfo.removedPackage = packageName;
                 outInfo.removedUsers = deletedPs != null
-                        ? deletedPs.getInstalledUsers(sUserManager.getUserIds()) : null;
+                        ? deletedPs.queryInstalledUsers(sUserManager.getUserIds(), true)
+                        : null;
             }
         }
         if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index 6d31f0e..d8f7345 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -210,17 +210,17 @@
         return false;
     }
 
-    int[] getInstalledUsers(int[] users) {
+    int[] queryInstalledUsers(int[] users, boolean installed) {
         int num = 0;
         for (int user : users) {
-            if (getInstalled(user)) {
+            if (getInstalled(user) == installed) {
                 num++;
             }
         }
         int[] res = new int[num];
         num = 0;
         for (int user : users) {
-            if (getInstalled(user)) {
+            if (getInstalled(user) == installed) {
                 res[num] = user;
                 num++;
             }