Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 786b4404 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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
parent 9d9ea05c
Loading
Loading
Loading
Loading
+10 −51
Original line number Diff line number Diff line
@@ -178,11 +178,6 @@ public final class Pm {
            return;
        }

        if ("list-users".equals(op)) {
            runListUsers();
            return;
        }

        try {
            if (args.length == 1) {
                if (args[0].equalsIgnoreCase("-l")) {
@@ -222,7 +217,6 @@ public final class Pm {
        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 @@ public final class Pm {
            runListUsers();
        } else {
            System.err.println("Error: unknown list type '" + type + "'");
            showUsage();
        }
    }

@@ -276,13 +269,11 @@ public final class Pm {
                    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 @@ public final class Pm {
                    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 @@ public final class Pm {
                    dangerousOnly = true;
                } else {
                    System.err.println("Error: Unknown option: " + opt);
                    showUsage();
                    return;
                }
            }
@@ -678,7 +666,6 @@ public final class Pm {
        String pkg = nextArg();
        if (pkg == null) {
            System.err.println("Error: no package specified");
            showUsage();
            return;
        }
        displayPackageFilePath(pkg);
@@ -736,20 +723,17 @@ public final class Pm {
        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 @@ public final class Pm {
                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 @@ public final class Pm {
                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 @@ public final class Pm {
                || 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 @@ public final class Pm {
                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 @@ public final class Pm {
            apkURI = Uri.fromFile(new File(apkFilePath));
        } else {
            System.err.println("Error: no package specified");
            showUsage();
            return;
        }

@@ -1012,23 +983,16 @@ public final class Pm {
    }

    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 final class Pm {
    }

    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 final class Pm {
    }

    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 @@ public final class Pm {
        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 @@ public final class Pm {
        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");
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -173,6 +173,9 @@
    <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" />
+13 −7
Original line number Diff line number Diff line
@@ -9404,9 +9404,15 @@ public final class ActivityManagerService extends ActivityManagerNative
    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 @@ public final class ActivityManagerService extends ActivityManagerNative
        needSep = true;
        
        if (mStickyBroadcasts != null && dumpPackage == null) {
        if (!onlyHistory && mStickyBroadcasts != null && dumpPackage == null) {
            if (needSep) {
                pw.println();
            }
@@ -9471,7 +9477,7 @@ public final class ActivityManagerService extends ActivityManagerNative
            needSep = true;
        }
        
        if (dumpAll) {
        if (!onlyHistory && dumpAll) {
            pw.println();
            for (BroadcastQueue queue : mBroadcastQueues) {
                pw.println("  mBroadcastsScheduled [" + queue.mQueueName + "]="
@@ -10982,7 +10988,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                    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 @@ public final class ActivityManagerService extends ActivityManagerNative
            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 @@ public final class ActivityManagerService extends ActivityManagerNative
            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());
+13 −9
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ class BroadcastRecord extends Binder {
    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 @@ class BroadcastRecord extends Binder {
    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 @@ class BroadcastRecord extends Binder {
                        pw.println(curReceiver.applicationInfo.sourceDir);
            }
        }
        if (state != IDLE) {
            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;
            }
            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 @@ class BroadcastRecord extends Binder {
            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 @@ class BroadcastRecord extends Binder {
        sticky = _sticky;
        initialSticky = _initialSticky;
        onlySendToCaller = _onlySendToCaller;
        userId = _userId;
        nextReceiver = 0;
        state = IDLE;
    }
+65 −17
Original line number Diff line number Diff line
@@ -704,20 +704,56 @@ public class PackageManagerService extends IPackageManager.Stub {
                            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 class PackageManagerService extends IPackageManager.Stub {
        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 @@ public class PackageManagerService extends IPackageManager.Stub {
                // 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 @@ public class PackageManagerService extends IPackageManager.Stub {
                                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 @@ public class PackageManagerService extends IPackageManager.Stub {
                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 @@ public class PackageManagerService extends IPackageManager.Stub {
        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 @@ public class PackageManagerService extends IPackageManager.Stub {
    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 @@ public class PackageManagerService extends IPackageManager.Stub {
                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 @@ public class PackageManagerService extends IPackageManager.Stub {
                    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 @@ public class PackageManagerService extends IPackageManager.Stub {
                    systemApp = (ps.pkg.applicationInfo.flags &
                            ApplicationInfo.FLAG_SYSTEM) != 0;
                }
                res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
            }
        }

@@ -7630,9 +7677,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                    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 @@ public class PackageManagerService extends IPackageManager.Stub {
            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) {
Loading