Start removing remaining pm code to package manager

Everything is now moved out of the pm command except for
the various install commands.  I am going to hold of on
those since they require doing some resolution with the
current implementations in the package manager to make
sure they match and behave identically to the implementations
currently in the pm command.  But other than that, everything
in pm is now just redirecting over to "cmd package".

Also fix up some of the dumpsys output of a few other sevices
when asking to print the data for a particular package, so
the "pm dump" command gives a little more sane result.

Test: manual

Change-Id: I139e06e560203b72243d7eea9543c2240db0f8f8
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 60ec8a9..29433f3 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -116,9 +116,8 @@
     }
 
     public int run(String[] args) throws RemoteException {
-        boolean validCommand = false;
         if (args.length < 1) {
-            return showUsage();
+            return runShellCommand("package", mArgs);
         }
         mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
         mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
@@ -134,18 +133,6 @@
         String op = args[0];
         mNextArg = 1;
 
-        if ("list".equals(op)) {
-            return runList();
-        }
-
-        if ("path".equals(op)) {
-            return runPath();
-        }
-
-        if ("dump".equals(op)) {
-            return runDump();
-        }
-
         if ("install".equals(op)) {
             return runInstall();
         }
@@ -166,134 +153,7 @@
             return runInstallAbandon();
         }
 
-        if ("set-installer".equals(op)) {
-            return runSetInstaller();
-        }
-
-        if ("uninstall".equals(op)) {
-            return runUninstall();
-        }
-
-        if ("clear".equals(op)) {
-            return runClear();
-        }
-
-        if ("enable".equals(op)) {
-            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
-        }
-
-        if ("disable".equals(op)) {
-            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
-        }
-
-        if ("disable-user".equals(op)) {
-            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
-        }
-
-        if ("disable-until-used".equals(op)) {
-            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
-        }
-
-        if ("default-state".equals(op)) {
-            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
-        }
-
-        if ("hide".equals(op)) {
-            return runSetHiddenSetting(true);
-        }
-
-        if ("unhide".equals(op)) {
-            return runSetHiddenSetting(false);
-        }
-
-        if ("grant".equals(op)) {
-            return runGrantRevokePermission(true);
-        }
-
-        if ("revoke".equals(op)) {
-            return runGrantRevokePermission(false);
-        }
-
-        if ("reset-permissions".equals(op)) {
-            return runResetPermissions();
-        }
-
-        if ("set-permission-enforced".equals(op)) {
-            return runSetPermissionEnforced();
-        }
-
-        if ("set-app-link".equals(op)) {
-            return runSetAppLink();
-        }
-
-        if ("get-app-link".equals(op)) {
-            return runGetAppLink();
-        }
-
-        if ("set-install-location".equals(op)) {
-            return runSetInstallLocation();
-        }
-
-        if ("get-install-location".equals(op)) {
-            return runGetInstallLocation();
-        }
-
-        if ("trim-caches".equals(op)) {
-            return runTrimCaches();
-        }
-
-        if ("create-user".equals(op)) {
-            return runCreateUser();
-        }
-
-        if ("remove-user".equals(op)) {
-            return runRemoveUser();
-        }
-
-        if ("get-max-users".equals(op)) {
-            return runGetMaxUsers();
-        }
-
-        if ("force-dex-opt".equals(op)) {
-            return runForceDexOpt();
-        }
-
-        if ("move-package".equals(op)) {
-            return runMovePackage();
-        }
-
-        if ("move-primary-storage".equals(op)) {
-            return runMovePrimaryStorage();
-        }
-
-        if ("set-user-restriction".equals(op)) {
-            return runSetUserRestriction();
-        }
-
-        try {
-            if (args.length == 1) {
-                if (args[0].equalsIgnoreCase("-l")) {
-                    validCommand = true;
-                    return runShellCommand("package", new String[] { "list", "package" });
-                } else if (args[0].equalsIgnoreCase("-lf")) {
-                    validCommand = true;
-                    return runShellCommand("package", new String[] { "list", "package", "-f" });
-                }
-            } else if (args.length == 2) {
-                if (args[0].equalsIgnoreCase("-p")) {
-                    validCommand = true;
-                    return displayPackageFilePath(args[1], UserHandle.USER_SYSTEM);
-                }
-            }
-            return 1;
-        } finally {
-            if (validCommand == false) {
-                if (op != null) {
-                    System.err.println("Error: unknown command '" + op + "'");
-                }
-                showUsage();
-            }
-        }
+        return runShellCommand("package", mArgs);
     }
 
     static final class MyShellCallback extends ShellCallback {
@@ -704,59 +564,6 @@
         }
     }
 
-    /**
-     * Execute the list sub-command.
-     *
-     * pm list [package | packages]
-     * pm list permission-groups
-     * pm list permissions
-     * pm list features
-     * pm list libraries
-     * pm list instrumentation
-     */
-    private int runList() {
-        final String type = nextArg();
-        if ("users".equals(type)) {
-            return runShellCommand("user", new String[] { "list" });
-        }
-        return runShellCommand("package", mArgs);
-    }
-
-    private int runUninstall() {
-        return runShellCommand("package", mArgs);
-    }
-
-    private int runPath() {
-        int userId = UserHandle.USER_SYSTEM;
-        String option = nextOption();
-        if (option != null && option.equals("--user")) {
-            String optionData = nextOptionData();
-            if (optionData == null || !isNumber(optionData)) {
-                System.err.println("Error: no USER_ID specified");
-                return showUsage();
-            } else {
-                userId = Integer.parseInt(optionData);
-            }
-        }
-
-        String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified");
-            return 1;
-        }
-        return displayPackageFilePath(pkg, userId);
-    }
-
-    private int runDump() {
-        String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified");
-            return 1;
-        }
-        ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
-        return 0;
-    }
-
     class LocalPackageInstallObserver extends PackageInstallObserver {
         boolean finished;
         int result;
@@ -779,477 +586,6 @@
         }
     }
 
-    // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined}
-    private int runSetAppLink() {
-        int userId = UserHandle.USER_SYSTEM;
-
-        String opt;
-        while ((opt = nextOption()) != null) {
-            if (opt.equals("--user")) {
-                userId = Integer.parseInt(nextOptionData());
-                if (userId < 0) {
-                    System.err.println("Error: user must be >= 0");
-                    return 1;
-                }
-            } else {
-                System.err.println("Error: unknown option: " + opt);
-                return showUsage();
-            }
-        }
-
-        // Package name to act on; required
-        final String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified.");
-            return showUsage();
-        }
-
-        // State to apply; {always|ask|never|undefined}, required
-        final String modeString = nextArg();
-        if (modeString == null) {
-            System.err.println("Error: no app link state specified.");
-            return showUsage();
-        }
-
-        final int newMode;
-        switch (modeString.toLowerCase()) {
-            case "undefined":
-                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-                break;
-
-            case "always":
-                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
-                break;
-
-            case "ask":
-                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
-                break;
-
-            case "always-ask":
-                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
-                break;
-
-            case "never":
-                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
-                break;
-
-            default:
-                System.err.println("Error: unknown app link state '" + modeString + "'");
-                return 1;
-        }
-
-        try {
-            final PackageInfo info = mPm.getPackageInfo(pkg, 0, userId);
-            if (info == null) {
-                System.err.println("Error: package " + pkg + " not found.");
-                return 1;
-            }
-
-            if ((info.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) {
-                System.err.println("Error: package " + pkg + " does not handle web links.");
-                return 1;
-            }
-
-            if (!mPm.updateIntentVerificationStatus(pkg, newMode, userId)) {
-                System.err.println("Error: unable to update app link status for " + pkg);
-                return 1;
-            }
-        } catch (Exception e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-
-        return 0;
-    }
-
-    // pm get-app-link [--user USER_ID] PACKAGE
-    private int runGetAppLink() {
-        int userId = UserHandle.USER_SYSTEM;
-
-        String opt;
-        while ((opt = nextOption()) != null) {
-            if (opt.equals("--user")) {
-                userId = Integer.parseInt(nextOptionData());
-                if (userId < 0) {
-                    System.err.println("Error: user must be >= 0");
-                    return 1;
-                }
-            } else {
-                System.err.println("Error: unknown option: " + opt);
-                return showUsage();
-            }
-        }
-
-        // Package name to act on; required
-        final String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified.");
-            return showUsage();
-        }
-
-        try {
-            final PackageInfo info = mPm.getPackageInfo(pkg, 0, userId);
-            if (info == null) {
-                System.err.println("Error: package " + pkg + " not found.");
-                return 1;
-            }
-
-            if ((info.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) {
-                System.err.println("Error: package " + pkg + " does not handle web links.");
-                return 1;
-            }
-
-            System.out.println(linkStateToString(mPm.getIntentVerificationStatus(pkg, userId)));
-        } catch (Exception e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-
-        return 0;
-    }
-
-    private String linkStateToString(int state) {
-        switch (state) {
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: return "undefined";
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: return "ask";
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: return "always";
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: return "never";
-            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK : return "always ask";
-        }
-        return "Unknown link state: " + state;
-    }
-
-    private int runSetInstallLocation() {
-        int loc;
-
-        String arg = nextArg();
-        if (arg == null) {
-            System.err.println("Error: no install location specified.");
-            return 1;
-        }
-        try {
-            loc = Integer.parseInt(arg);
-        } catch (NumberFormatException e) {
-            System.err.println("Error: install location has to be a number.");
-            return 1;
-        }
-        try {
-            if (!mPm.setInstallLocation(loc)) {
-                System.err.println("Error: install location has to be a number.");
-                return 1;
-            }
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-    }
-
-    private int runGetInstallLocation() {
-        try {
-            int loc = mPm.getInstallLocation();
-            String locStr = "invalid";
-            if (loc == PackageHelper.APP_INSTALL_AUTO) {
-                locStr = "auto";
-            } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) {
-                locStr = "internal";
-            } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
-                locStr = "external";
-            }
-            System.out.println(loc + "[" + locStr + "]");
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-    }
-
-    private int runSetInstaller() throws RemoteException {
-        final String targetPackage = nextArg();
-        final String installerPackageName = nextArg();
-
-        if (targetPackage == null || installerPackageName == null) {
-            throw new IllegalArgumentException(
-                    "must provide both target and installer package names");
-        }
-
-        mPm.setInstallerPackageName(targetPackage, installerPackageName);
-        System.out.println("Success");
-        return 0;
-    }
-
-    public int runCreateUser() {
-        String name;
-        int userId = -1;
-        int flags = 0;
-        String opt;
-        while ((opt = nextOption()) != null) {
-            if ("--profileOf".equals(opt)) {
-                String optionData = nextOptionData();
-                if (optionData == null || !isNumber(optionData)) {
-                    System.err.println("Error: no USER_ID specified");
-                    return showUsage();
-                } else {
-                    userId = Integer.parseInt(optionData);
-                }
-            } else if ("--managed".equals(opt)) {
-                flags |= UserInfo.FLAG_MANAGED_PROFILE;
-            } else if ("--restricted".equals(opt)) {
-                flags |= UserInfo.FLAG_RESTRICTED;
-            } else if ("--ephemeral".equals(opt)) {
-                flags |= UserInfo.FLAG_EPHEMERAL;
-            } else if ("--guest".equals(opt)) {
-                flags |= UserInfo.FLAG_GUEST;
-            } else if ("--demo".equals(opt)) {
-                flags |= UserInfo.FLAG_DEMO;
-            } else {
-                System.err.println("Error: unknown option " + opt);
-                return showUsage();
-            }
-        }
-        String arg = nextArg();
-        if (arg == null) {
-            System.err.println("Error: no user name specified.");
-            return 1;
-        }
-        name = arg;
-        try {
-            UserInfo info;
-            if ((flags & UserInfo.FLAG_RESTRICTED) != 0) {
-                // In non-split user mode, userId can only be SYSTEM
-                int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
-                info = mUm.createRestrictedProfile(name, parentUserId);
-                mAm.addSharedAccountsFromParentUser(parentUserId, userId,
-                        (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell");
-            } else if (userId < 0) {
-                info = mUm.createUser(name, flags);
-            } else {
-                info = mUm.createProfileForUser(name, flags, userId, null);
-            }
-
-            if (info != null) {
-                System.out.println("Success: created user id " + info.id);
-                return 0;
-            } else {
-                System.err.println("Error: couldn't create User.");
-                return 1;
-            }
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-    }
-
-    public int runRemoveUser() {
-        int userId;
-        String arg = nextArg();
-        if (arg == null) {
-            System.err.println("Error: no user id specified.");
-            return 1;
-        }
-        try {
-            userId = Integer.parseInt(arg);
-        } catch (NumberFormatException e) {
-            System.err.println("Error: user id '" + arg + "' is not a number.");
-            return 1;
-        }
-        try {
-            if (mUm.removeUser(userId)) {
-                System.out.println("Success: removed user");
-                return 0;
-            } else {
-                System.err.println("Error: couldn't remove user id " + userId);
-                return 1;
-            }
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-    }
-
-    public int runGetMaxUsers() {
-        System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
-        return 0;
-    }
-
-    public int runForceDexOpt() {
-        final String packageName = nextArg();
-        try {
-            mPm.forceDexOpt(packageName);
-            return 0;
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    public int runMovePackage() {
-        final String packageName = nextArg();
-        String volumeUuid = nextArg();
-        if ("internal".equals(volumeUuid)) {
-            volumeUuid = null;
-        }
-
-        try {
-            final int moveId = mPm.movePackage(packageName, volumeUuid);
-
-            int status = mPm.getMoveStatus(moveId);
-            while (!PackageManager.isMoveStatusFinished(status)) {
-                SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
-                status = mPm.getMoveStatus(moveId);
-            }
-
-            if (status == PackageManager.MOVE_SUCCEEDED) {
-                System.out.println("Success");
-                return 0;
-            } else {
-                System.err.println("Failure [" + status + "]");
-                return 1;
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    public int runMovePrimaryStorage() {
-        String volumeUuid = nextArg();
-        if ("internal".equals(volumeUuid)) {
-            volumeUuid = null;
-        }
-
-        try {
-            final int moveId = mPm.movePrimaryStorage(volumeUuid);
-
-            int status = mPm.getMoveStatus(moveId);
-            while (!PackageManager.isMoveStatusFinished(status)) {
-                SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
-                status = mPm.getMoveStatus(moveId);
-            }
-
-            if (status == PackageManager.MOVE_SUCCEEDED) {
-                System.out.println("Success");
-                return 0;
-            } else {
-                System.err.println("Failure [" + status + "]");
-                return 1;
-            }
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    public int runSetUserRestriction() {
-        int userId = UserHandle.USER_SYSTEM;
-        String opt = nextOption();
-        if (opt != null && "--user".equals(opt)) {
-            String arg = nextArg();
-            if (arg == null || !isNumber(arg)) {
-                System.err.println("Error: valid userId not specified");
-                return 1;
-            }
-            userId = Integer.parseInt(arg);
-        }
-
-        String restriction = nextArg();
-        String arg = nextArg();
-        boolean value;
-        if ("1".equals(arg)) {
-            value = true;
-        } else if ("0".equals(arg)) {
-            value = false;
-        } else {
-            System.err.println("Error: valid value not specified");
-            return 1;
-        }
-        try {
-            mUm.setUserRestriction(restriction, value, userId);
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            return 1;
-        }
-    }
-
-    static class ClearDataObserver extends IPackageDataObserver.Stub {
-        boolean finished;
-        boolean result;
-
-        @Override
-        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
-            synchronized (this) {
-                finished = true;
-                result = succeeded;
-                notifyAll();
-            }
-        }
-    }
-
-    private int runClear() {
-        int userId = UserHandle.USER_SYSTEM;
-        String option = nextOption();
-        if (option != null && option.equals("--user")) {
-            String optionData = nextOptionData();
-            if (optionData == null || !isNumber(optionData)) {
-                System.err.println("Error: no USER_ID specified");
-                return showUsage();
-            } else {
-                userId = Integer.parseInt(optionData);
-            }
-        }
-
-        String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified");
-            return showUsage();
-        }
-
-        ClearDataObserver obs = new ClearDataObserver();
-        try {
-            ActivityManager.getService().clearApplicationUserData(pkg, obs, userId);
-            synchronized (obs) {
-                while (!obs.finished) {
-                    try {
-                        obs.wait();
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-
-            if (obs.result) {
-                System.out.println("Success");
-                return 0;
-            } else {
-                System.err.println("Failed");
-                return 1;
-            }
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-    }
-
-    private static String enabledSettingToString(int state) {
-        switch (state) {
-            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
-                return "default";
-            case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
-                return "enabled";
-            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
-                return "disabled";
-            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
-                return "disabled-user";
-            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
-                return "disabled-until-used";
-        }
-        return "unknown";
-    }
-
     private static boolean isNumber(String s) {
         try {
             Integer.parseInt(s);
@@ -1259,169 +595,6 @@
         return true;
     }
 
-    private int runSetEnabledSetting(int state) {
-        int userId = UserHandle.USER_SYSTEM;
-        String option = nextOption();
-        if (option != null && option.equals("--user")) {
-            String optionData = nextOptionData();
-            if (optionData == null || !isNumber(optionData)) {
-                System.err.println("Error: no USER_ID specified");
-                return showUsage();
-            } else {
-                userId = Integer.parseInt(optionData);
-            }
-        }
-
-        String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package or component specified");
-            return showUsage();
-        }
-        ComponentName cn = ComponentName.unflattenFromString(pkg);
-        if (cn == null) {
-            try {
-                mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
-                        "shell:" + android.os.Process.myUid());
-                System.out.println("Package " + pkg + " new state: "
-                        + enabledSettingToString(
-                        mPm.getApplicationEnabledSetting(pkg, userId)));
-                return 0;
-            } catch (RemoteException e) {
-                System.err.println(e.toString());
-                System.err.println(PM_NOT_RUNNING_ERR);
-                return 1;
-            }
-        } else {
-            try {
-                mPm.setComponentEnabledSetting(cn, state, 0, userId);
-                System.out.println("Component " + cn.toShortString() + " new state: "
-                        + enabledSettingToString(
-                        mPm.getComponentEnabledSetting(cn, userId)));
-                return 0;
-            } catch (RemoteException e) {
-                System.err.println(e.toString());
-                System.err.println(PM_NOT_RUNNING_ERR);
-                return 1;
-            }
-        }
-    }
-
-    private int runSetHiddenSetting(boolean state) {
-        int userId = UserHandle.USER_SYSTEM;
-        String option = nextOption();
-        if (option != null && option.equals("--user")) {
-            String optionData = nextOptionData();
-            if (optionData == null || !isNumber(optionData)) {
-                System.err.println("Error: no USER_ID specified");
-                return showUsage();
-            } else {
-                userId = Integer.parseInt(optionData);
-            }
-        }
-
-        String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package or component specified");
-            return showUsage();
-        }
-        try {
-            mPm.setApplicationHiddenSettingAsUser(pkg, state, userId);
-            System.out.println("Package " + pkg + " new hidden state: "
-                    + mPm.getApplicationHiddenSettingAsUser(pkg, userId));
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        }
-    }
-
-    private int runGrantRevokePermission(boolean grant) {
-        int userId = UserHandle.USER_SYSTEM;
-
-        String opt = null;
-        while ((opt = nextOption()) != null) {
-            if (opt.equals("--user")) {
-                userId = Integer.parseInt(nextArg());
-            }
-        }
-
-        String pkg = nextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified");
-            return showUsage();
-        }
-        String perm = nextArg();
-        if (perm == null) {
-            System.err.println("Error: no permission specified");
-            return showUsage();
-        }
-
-        try {
-            if (grant) {
-                mPm.grantRuntimePermission(pkg, perm, userId);
-            } else {
-                mPm.revokeRuntimePermission(pkg, perm, userId);
-            }
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        } catch (IllegalArgumentException e) {
-            System.err.println("Bad argument: " + e.toString());
-            return showUsage();
-        } catch (SecurityException e) {
-            System.err.println("Operation not allowed: " + e.toString());
-            return 1;
-        }
-    }
-
-    private int runResetPermissions() {
-        try {
-            mPm.resetRuntimePermissions();
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        } catch (IllegalArgumentException e) {
-            System.err.println("Bad argument: " + e.toString());
-            return showUsage();
-        } catch (SecurityException e) {
-            System.err.println("Operation not allowed: " + e.toString());
-            return 1;
-        }
-    }
-
-    private int runSetPermissionEnforced() {
-        final String permission = nextArg();
-        if (permission == null) {
-            System.err.println("Error: no permission specified");
-            return showUsage();
-        }
-        final String enforcedRaw = nextArg();
-        if (enforcedRaw == null) {
-            System.err.println("Error: no enforcement specified");
-            return showUsage();
-        }
-        final boolean enforced = Boolean.parseBoolean(enforcedRaw);
-        try {
-            mPm.setPermissionEnforced(permission, enforced);
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        } catch (IllegalArgumentException e) {
-            System.err.println("Bad argument: " + e.toString());
-            return showUsage();
-        } catch (SecurityException e) {
-            System.err.println("Operation not allowed: " + e.toString());
-            return 1;
-        }
-    }
-
     static class ClearCacheObserver extends IPackageDataObserver.Stub {
         boolean finished;
         boolean result;
@@ -1437,62 +610,17 @@
 
     }
 
-    private int runTrimCaches() {
-        String size = nextArg();
-        if (size == null) {
-            System.err.println("Error: no size specified");
-            return showUsage();
-        }
-        long multiplier = 1;
-        int len = size.length();
-        char c = size.charAt(len - 1);
-        if (c < '0' || c > '9') {
-            if (c == 'K' || c == 'k') {
-                multiplier = 1024L;
-            } else if (c == 'M' || c == 'm') {
-                multiplier = 1024L*1024L;
-            } else if (c == 'G' || c == 'g') {
-                multiplier = 1024L*1024L*1024L;
-            } else {
-                System.err.println("Invalid suffix: " + c);
-                return showUsage();
+    static class ClearDataObserver extends IPackageDataObserver.Stub {
+        boolean finished;
+        boolean result;
+
+        @Override
+        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
+            synchronized (this) {
+                finished = true;
+                result = succeeded;
+                notifyAll();
             }
-            size = size.substring(0, len-1);
-        }
-        long sizeVal;
-        try {
-            sizeVal = Long.parseLong(size) * multiplier;
-        } catch (NumberFormatException e) {
-            System.err.println("Error: expected number at: " + size);
-            return showUsage();
-        }
-        String volumeUuid = nextArg();
-        if ("internal".equals(volumeUuid)) {
-            volumeUuid = null;
-        }
-        ClearDataObserver obs = new ClearDataObserver();
-        try {
-            mPm.freeStorageAndNotify(volumeUuid, sizeVal,
-                    StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs);
-            synchronized (obs) {
-                while (!obs.finished) {
-                    try {
-                        obs.wait();
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-            return 0;
-        } catch (RemoteException e) {
-            System.err.println(e.toString());
-            System.err.println(PM_NOT_RUNNING_ERR);
-            return 1;
-        } catch (IllegalArgumentException e) {
-            System.err.println("Bad argument: " + e.toString());
-            return showUsage();
-        } catch (SecurityException e) {
-            System.err.println("Operation not allowed: " + e.toString());
-            return 1;
         }
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a1eda65..280b1e8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -46,6 +46,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.BatteryStats;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
@@ -3885,21 +3886,36 @@
         IBinder service = ServiceManager.checkService(name);
         if (service == null) {
             pw.println("  (Service not found)");
+            pw.flush();
             return;
         }
-        TransferPipe tp = null;
-        try {
-            pw.flush();
-            tp = new TransferPipe();
-            tp.setBufferPrefix("  ");
-            service.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
-            tp.go(fd, 10000);
-        } catch (Throwable e) {
-            if (tp != null) {
-                tp.kill();
+        pw.flush();
+        if (service instanceof Binder) {
+            // If this is a local object, it doesn't make sense to do an async dump with it,
+            // just directly dump.
+            try {
+                service.dump(fd, args);
+            } catch (Throwable e) {
+                pw.println("Failure dumping service:");
+                e.printStackTrace(pw);
+                pw.flush();
             }
-            pw.println("Failure dumping service:");
-            e.printStackTrace(pw);
+        } else {
+            // Otherwise, it is remote, do the dump asynchronously to avoid blocking.
+            TransferPipe tp = null;
+            try {
+                pw.flush();
+                tp = new TransferPipe();
+                tp.setBufferPrefix("  ");
+                service.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
+                tp.go(fd, 10000);
+            } catch (Throwable e) {
+                if (tp != null) {
+                    tp.kill();
+                }
+                pw.println("Failure dumping service:");
+                e.printStackTrace(pw);
+            }
         }
     }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a8a65e3..a8bd940 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -6453,7 +6453,7 @@
                 pw.println();
             }
         }
-        if (!filtering || (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0) {
+        if (!filtering || (flags & DUMP_DAILY_ONLY) != 0) {
             pw.println("Daily stats:");
             pw.print("  Current start time: ");
             pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index e9e695b..66e1651 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -167,7 +167,7 @@
         try {
             if (binder instanceof BinderProxy) {
                 ((BinderProxy) binder).mWarnOnBlocking = false;
-            } else if (binder != null
+            } else if (binder != null && binder.getInterfaceDescriptor() != null
                     && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
                 Log.w(TAG, "Unable to allow blocking on interface " + binder);
             }
@@ -414,7 +414,7 @@
      * descriptor.
      */
     public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
-        if (mDescriptor.equals(descriptor)) {
+        if (mDescriptor != null && mDescriptor.equals(descriptor)) {
             return mOwner;
         }
         return null;
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index e4a12e8..6223235 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.util.Slog;
+
 import com.android.internal.util.FastPrintWriter;
 
 import java.io.BufferedInputStream;
@@ -118,13 +119,33 @@
                 mErrPrintWriter.flush();
             }
             if (DEBUG) Slog.d(TAG, "Sending command result on " + mTarget);
-            mResultReceiver.send(res, null);
+            if (mResultReceiver != null) {
+                mResultReceiver.send(res, null);
+            }
         }
         if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
         return res;
     }
 
     /**
+     * Adopt the ResultReceiver that was given to this shell command from it, taking
+     * it over.  Primarily used to dispatch to another shell command.  Once called,
+     * this shell command will no longer return its own result when done.
+     */
+    public ResultReceiver adoptResultReceiver() {
+        ResultReceiver rr = mResultReceiver;
+        mResultReceiver = null;
+        return rr;
+    }
+
+    /**
+     * Return the raw FileDescriptor for the output stream.
+     */
+    public FileDescriptor getOutFileDescriptor() {
+        return mOut;
+    }
+
+    /**
      * Return direct raw access (not buffered) to the command's output data stream.
      */
     public OutputStream getRawOutputStream() {
@@ -145,6 +166,13 @@
     }
 
     /**
+     * Return the raw FileDescriptor for the error stream.
+     */
+    public FileDescriptor getErrFileDescriptor() {
+        return mErr;
+    }
+
+    /**
      * Return direct raw access (not buffered) to the command's error output data stream.
      */
     public OutputStream getRawErrorStream() {
@@ -168,6 +196,13 @@
     }
 
     /**
+     * Return the raw FileDescriptor for the input stream.
+     */
+    public FileDescriptor getInFileDescriptor() {
+        return mIn;
+    }
+
+    /**
      * Return direct raw access (not buffered) to the command's input data stream.
      */
     public InputStream getRawInputStream() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d15fc20..a810bbb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15626,7 +15626,8 @@
             }
             pw.println("  mPreviousProcess: " + mPreviousProcess);
         }
-        if (dumpAll) {
+        if (dumpAll && (mPreviousProcess == null || dumpPackage == null
+                || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
             StringBuilder sb = new StringBuilder(128);
             sb.append("  mPreviousProcessVisibleTime: ");
             TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
@@ -15645,7 +15646,9 @@
             mStackSupervisor.dumpDisplayConfigs(pw, "  ");
         }
         if (dumpAll) {
-            pw.println("  mConfigWillChange: " + getFocusedStack().mConfigWillChange);
+            if (dumpPackage == null) {
+                pw.println("  mConfigWillChange: " + getFocusedStack().mConfigWillChange);
+            }
             if (mCompatModePackages.getPackages().size() > 0) {
                 boolean printed = false;
                 for (Map.Entry<String, Integer> entry
@@ -15725,8 +15728,8 @@
                 pw.println("  mRunningVoice=" + mRunningVoice);
                 pw.println("  mVoiceWakeLock" + mVoiceWakeLock);
             }
+            pw.println("  mVrController=" + mVrController);
         }
-        pw.println("  mVrController=" + mVrController);
         if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                 || mOrigWaitForDebugger) {
             if (dumpPackage == null || dumpPackage.equals(mDebugApp)
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1fea003..a2099e6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -16,14 +16,17 @@
 
 package com.android.server.pm;
 
+import android.accounts.IAccountManager;
 import android.app.ActivityManager;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageManager;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
@@ -41,6 +44,7 @@
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -49,15 +53,23 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IUserManager;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.ShellCommand;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.text.TextUtils;
-import android.util.ArrayMap;
+import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.PrintWriterPrinter;
+
 import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.SizedInputStream;
 import com.android.server.SystemConfig;
 
@@ -81,6 +93,12 @@
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+
 class PackageManagerShellCommand extends ShellCommand {
     /** Path for streaming APK content */
     private static final String STDIN_PATH = "-";
@@ -107,6 +125,20 @@
         final PrintWriter pw = getOutPrintWriter();
         try {
             switch(cmd) {
+                case "path":
+                    return runPath();
+                case "dump":
+                    return runDump();
+                case "list":
+                    return runList();
+                case "resolve-activity":
+                    return runResolveActivity();
+                case "query-activities":
+                    return runQueryIntentActivities();
+                case "query-services":
+                    return runQueryIntentServices();
+                case "query-receivers":
+                    return runQueryIntentReceivers();
                 case "install":
                     return runInstall();
                 case "install-abandon":
@@ -122,44 +154,99 @@
                     return runInstallWrite();
                 case "install-existing":
                     return runInstallExisting();
+                case "set-install-location":
+                    return runSetInstallLocation();
+                case "get-install-location":
+                    return runGetInstallLocation();
+                case "move-package":
+                    return runMovePackage();
+                case "move-primary-storage":
+                    return runMovePrimaryStorage();
                 case "compile":
                     return runCompile();
                 case "reconcile-secondary-dex-files":
                     return runreconcileSecondaryDexFiles();
+                case "force-dex-opt":
+                    return runForceDexOpt();
                 case "bg-dexopt-job":
                     return runDexoptJob();
                 case "dump-profiles":
                     return runDumpProfiles();
-                case "list":
-                    return runList();
                 case "uninstall":
                     return runUninstall();
-                case "resolve-activity":
-                    return runResolveActivity();
-                case "query-activities":
-                    return runQueryIntentActivities();
-                case "query-services":
-                    return runQueryIntentServices();
-                case "query-receivers":
-                    return runQueryIntentReceivers();
+                case "clear":
+                    return runClear();
+                case "enable":
+                    return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+                case "disable":
+                    return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+                case "disable-user":
+                    return runSetEnabledSetting(
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
+                case "disable-until-used":
+                    return runSetEnabledSetting(
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+                case "default-state":
+                    return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+                case "hide":
+                    return runSetHiddenSetting(true);
+                case "unhide":
+                    return runSetHiddenSetting(false);
                 case "suspend":
                     return runSuspend(true);
                 case "unsuspend":
                     return runSuspend(false);
-                case "set-home-activity":
-                    return runSetHomeActivity();
+                case "grant":
+                    return runGrantRevokePermission(true);
+                case "revoke":
+                    return runGrantRevokePermission(false);
+                case "reset-permissions":
+                    return runResetPermissions();
+                case "set-permission-enforced":
+                    return runSetPermissionEnforced();
                 case "get-privapp-permissions":
                     return runGetPrivappPermissions();
                 case "get-privapp-deny-permissions":
                     return runGetPrivappDenyPermissions();
                 case "get-oem-permissions":
                     return runGetOemPermissions();
+                case "set-app-link":
+                    return runSetAppLink();
+                case "get-app-link":
+                    return runGetAppLink();
+                case "trim-caches":
+                    return runTrimCaches();
+                case "create-user":
+                    return runCreateUser();
+                case "remove-user":
+                    return runRemoveUser();
+                case "set-user-restriction":
+                    return runSetUserRestriction();
+                case "get-max-users":
+                    return runGetMaxUsers();
+                case "set-home-activity":
+                    return runSetHomeActivity();
+                case "set-installer":
+                    return runSetInstaller();
                 case "get-instantapp-resolver":
                     return runGetInstantAppResolver();
                 case "has-feature":
                     return runHasFeature();
-                default:
+                default: {
+                    String nextArg = getNextArg();
+                    if (nextArg == null) {
+                        if (cmd.equalsIgnoreCase("-l")) {
+                            return runListPackages(false);
+                        } else if (cmd.equalsIgnoreCase("-lf")) {
+                            return runListPackages(true);
+                        }
+                    } else if (getNextArg() == null) {
+                        if (cmd.equalsIgnoreCase("-p")) {
+                            return displayPackageFilePath(nextArg, UserHandle.USER_SYSTEM);
+                        }
+                    }
                     return handleDefaultCommands(cmd);
+                }
             }
         } catch (RemoteException e) {
             pw.println("Remote exception: " + e);
@@ -195,346 +282,40 @@
             }
         }
     }
-
-    private int runInstall() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        final InstallParams params = makeInstallParams();
-        final String inPath = getNextArg();
-
-        setParamsSize(params, inPath);
-        final int sessionId = doCreateSession(params.sessionParams,
-                params.installerPackageName, params.userId);
-        boolean abandonSession = true;
-        try {
-            if (inPath == null && params.sessionParams.sizeBytes == -1) {
-                pw.println("Error: must either specify a package size or an APK file");
-                return 1;
-            }
-            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
-                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
-            }
-            if (doCommitSession(sessionId, false /*logSuccess*/)
-                    != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
-            }
-            abandonSession = false;
-            pw.println("Success");
-            return 0;
-        } finally {
-            if (abandonSession) {
-                try {
-                    doAbandonSession(sessionId, false /*logSuccess*/);
-                } catch (Exception ignore) {
+    /**
+     * Displays the package file for a package.
+     * @param pckg
+     */
+    private int displayPackageFilePath(String pckg, int userId) throws RemoteException {
+        PackageInfo info = mInterface.getPackageInfo(pckg, 0, userId);
+        if (info != null && info.applicationInfo != null) {
+            final PrintWriter pw = getOutPrintWriter();
+            pw.print("package:");
+            pw.println(info.applicationInfo.sourceDir);
+            if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
+                for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
+                    pw.print("package:");
+                    pw.println(splitSourceDir);
                 }
             }
+            return 0;
         }
+        return 1;
     }
 
-    private int runSuspend(boolean suspendedState) {
-        final PrintWriter pw = getOutPrintWriter();
+    private int runPath() throws RemoteException {
         int userId = UserHandle.USER_SYSTEM;
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            switch (opt) {
-                case "--user":
-                    userId = UserHandle.parseUserArg(getNextArgRequired());
-                    break;
-                default:
-                    pw.println("Error: Unknown option: " + opt);
-                    return 1;
-            }
+        String option = getNextOption();
+        if (option != null && option.equals("--user")) {
+            userId = UserHandle.parseUserArg(getNextArgRequired());
         }
 
-        String packageName = getNextArg();
-        if (packageName == null) {
-            pw.println("Error: package name not specified");
+        String pkg = getNextArgRequired();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified");
             return 1;
         }
-
-        try {
-            mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
-                    userId);
-            pw.println("Package " + packageName + " new suspended state: "
-                    + mInterface.isPackageSuspendedForUser(packageName, userId));
-            return 0;
-        } catch (RemoteException | IllegalArgumentException e) {
-            pw.println(e.toString());
-            return 1;
-        }
-    }
-
-    private int runInstallAbandon() throws RemoteException {
-        final int sessionId = Integer.parseInt(getNextArg());
-        return doAbandonSession(sessionId, true /*logSuccess*/);
-    }
-
-    private int runInstallCommit() throws RemoteException {
-        final int sessionId = Integer.parseInt(getNextArg());
-        return doCommitSession(sessionId, true /*logSuccess*/);
-    }
-
-    private int runInstallCreate() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        final InstallParams installParams = makeInstallParams();
-        final int sessionId = doCreateSession(installParams.sessionParams,
-                installParams.installerPackageName, installParams.userId);
-
-        // NOTE: adb depends on parsing this string
-        pw.println("Success: created install session [" + sessionId + "]");
-        return 0;
-    }
-
-    private int runInstallWrite() throws RemoteException {
-        long sizeBytes = -1;
-
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            if (opt.equals("-S")) {
-                sizeBytes = Long.parseLong(getNextArg());
-            } else {
-                throw new IllegalArgumentException("Unknown option: " + opt);
-            }
-        }
-
-        final int sessionId = Integer.parseInt(getNextArg());
-        final String splitName = getNextArg();
-        final String path = getNextArg();
-        return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
-    }
-
-    private int runInstallRemove() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-
-        final int sessionId = Integer.parseInt(getNextArg());
-
-        final String splitName = getNextArg();
-        if (splitName == null) {
-            pw.println("Error: split name not specified");
-            return 1;
-        }
-        return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
-    }
-
-    private int runInstallExisting() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        int userId = UserHandle.USER_SYSTEM;
-        int installFlags = 0;
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            switch (opt) {
-                case "--user":
-                    userId = UserHandle.parseUserArg(getNextArgRequired());
-                    break;
-                case "--ephemeral":
-                case "--instant":
-                    installFlags |= PackageManager.INSTALL_INSTANT_APP;
-                    installFlags &= ~PackageManager.INSTALL_FULL_APP;
-                    break;
-                case "--full":
-                    installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
-                    installFlags |= PackageManager.INSTALL_FULL_APP;
-                    break;
-                default:
-                    pw.println("Error: Unknown option: " + opt);
-                    return 1;
-            }
-        }
-
-        final String packageName = getNextArg();
-        if (packageName == null) {
-            pw.println("Error: package name not specified");
-            return 1;
-        }
-
-        try {
-            final int res = mInterface.installExistingPackageAsUser(packageName, userId,
-                    installFlags, PackageManager.INSTALL_REASON_UNKNOWN);
-            if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
-                throw new NameNotFoundException("Package " + packageName + " doesn't exist");
-            }
-            pw.println("Package " + packageName + " installed for user: " + userId);
-            return 0;
-        } catch (RemoteException | NameNotFoundException e) {
-            pw.println(e.toString());
-            return 1;
-        }
-    }
-
-    private int runCompile() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-        boolean forceCompilation = false;
-        boolean allPackages = false;
-        boolean clearProfileData = false;
-        String compilerFilter = null;
-        String compilationReason = null;
-        String checkProfilesRaw = null;
-        boolean secondaryDex = false;
-        String split = null;
-
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            switch (opt) {
-                case "-a":
-                    allPackages = true;
-                    break;
-                case "-c":
-                    clearProfileData = true;
-                    break;
-                case "-f":
-                    forceCompilation = true;
-                    break;
-                case "-m":
-                    compilerFilter = getNextArgRequired();
-                    break;
-                case "-r":
-                    compilationReason = getNextArgRequired();
-                    break;
-                case "--check-prof":
-                    checkProfilesRaw = getNextArgRequired();
-                    break;
-                case "--reset":
-                    forceCompilation = true;
-                    clearProfileData = true;
-                    compilationReason = "install";
-                    break;
-                case "--secondary-dex":
-                    secondaryDex = true;
-                    break;
-                case "--split":
-                    split = getNextArgRequired();
-                    break;
-                default:
-                    pw.println("Error: Unknown option: " + opt);
-                    return 1;
-            }
-        }
-
-        if (checkProfilesRaw != null) {
-            if ("true".equals(checkProfilesRaw)) {
-                checkProfiles = true;
-            } else if ("false".equals(checkProfilesRaw)) {
-                checkProfiles = false;
-            } else {
-                pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
-                return 1;
-            }
-        }
-
-        if (compilerFilter != null && compilationReason != null) {
-            pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
-                    "at the same time");
-            return 1;
-        }
-        if (compilerFilter == null && compilationReason == null) {
-            pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
-                    "reason (\"-r\") at the same time");
-            return 1;
-        }
-
-        if (allPackages && split != null) {
-            pw.println("-a cannot be specified together with --split");
-            return 1;
-        }
-
-        if (secondaryDex && split != null) {
-            pw.println("--secondary-dex cannot be specified together with --split");
-            return 1;
-        }
-
-        String targetCompilerFilter;
-        if (compilerFilter != null) {
-            if (!DexFile.isValidCompilerFilter(compilerFilter)) {
-                pw.println("Error: \"" + compilerFilter +
-                        "\" is not a valid compilation filter.");
-                return 1;
-            }
-            targetCompilerFilter = compilerFilter;
-        } else {
-            int reason = -1;
-            for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
-                if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
-                        compilationReason)) {
-                    reason = i;
-                    break;
-                }
-            }
-            if (reason == -1) {
-                pw.println("Error: Unknown compilation reason: " + compilationReason);
-                return 1;
-            }
-            targetCompilerFilter =
-                    PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
-        }
-
-
-        List<String> packageNames = null;
-        if (allPackages) {
-            packageNames = mInterface.getAllPackages();
-        } else {
-            String packageName = getNextArg();
-            if (packageName == null) {
-                pw.println("Error: package name not specified");
-                return 1;
-            }
-            packageNames = Collections.singletonList(packageName);
-        }
-
-        List<String> failedPackages = new ArrayList<>();
-        for (String packageName : packageNames) {
-            if (clearProfileData) {
-                mInterface.clearApplicationProfileData(packageName);
-            }
-
-            boolean result = secondaryDex
-                    ? mInterface.performDexOptSecondary(packageName,
-                            targetCompilerFilter, forceCompilation)
-                    : mInterface.performDexOptMode(packageName,
-                            checkProfiles, targetCompilerFilter, forceCompilation,
-                            true /* bootComplete */, split);
-            if (!result) {
-                failedPackages.add(packageName);
-            }
-        }
-
-        if (failedPackages.isEmpty()) {
-            pw.println("Success");
-            return 0;
-        } else if (failedPackages.size() == 1) {
-            pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
-            return 1;
-        } else {
-            pw.print("Failure: the following packages could not be compiled: ");
-            boolean is_first = true;
-            for (String packageName : failedPackages) {
-                if (is_first) {
-                    is_first = false;
-                } else {
-                    pw.print(", ");
-                }
-                pw.print(packageName);
-            }
-            pw.println();
-            return 1;
-        }
-    }
-
-    private int runreconcileSecondaryDexFiles() throws RemoteException {
-        String packageName = getNextArg();
-        mInterface.reconcileSecondaryDexFiles(packageName);
-        return 0;
-    }
-
-    private int runDexoptJob() throws RemoteException {
-        boolean result = mInterface.runBackgroundDexoptJob();
-        return result ? 0 : -1;
-    }
-
-    private int runDumpProfiles() throws RemoteException {
-        String packageName = getNextArg();
-        mInterface.dumpProfiles(packageName);
-        return 0;
+        return displayPackageFilePath(pkg, userId);
     }
 
     private int runList() throws RemoteException {
@@ -558,6 +339,11 @@
                 return runListPermissionGroups();
             case "permissions":
                 return runListPermissions();
+            case "users":
+                ServiceManager.getService("user").shellCommand(
+                        getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(),
+                        new String[] { "list" }, getShellCallback(), adoptResultReceiver());
+                return 0;
         }
         pw.println("Error: unknown list type '" + type + "'");
         return -1;
@@ -590,7 +376,7 @@
                 pw.println();
             } else {
                 pw.println("reqGlEsVersion=0x"
-                    + Integer.toHexString(fi.reqGlEsVersion));
+                        + Integer.toHexString(fi.reqGlEsVersion));
             }
         }
         return 0;
@@ -872,111 +658,6 @@
         return 0;
     }
 
-    private int runUninstall() throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        int flags = 0;
-        int userId = UserHandle.USER_ALL;
-        int versionCode = PackageManager.VERSION_CODE_HIGHEST;
-
-        String opt;
-        while ((opt = getNextOption()) != null) {
-            switch (opt) {
-                case "-k":
-                    flags |= PackageManager.DELETE_KEEP_DATA;
-                    break;
-                case "--user":
-                    userId = UserHandle.parseUserArg(getNextArgRequired());
-                    break;
-                case "--versionCode":
-                    versionCode = Integer.parseInt(getNextArgRequired());
-                    break;
-                default:
-                    pw.println("Error: Unknown option: " + opt);
-                    return 1;
-            }
-        }
-
-        final String packageName = getNextArg();
-        if (packageName == null) {
-            pw.println("Error: package name not specified");
-            return 1;
-        }
-
-        // if a split is specified, just remove it and not the whole package
-        final String splitName = getNextArg();
-        if (splitName != null) {
-            return runRemoveSplit(packageName, splitName);
-        }
-
-        userId = translateUserId(userId, "runUninstall");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-            flags |= PackageManager.DELETE_ALL_USERS;
-        } else {
-            final PackageInfo info = mInterface.getPackageInfo(packageName,
-                    PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
-            if (info == null) {
-                pw.println("Failure [not installed for " + userId + "]");
-                return 1;
-            }
-            final boolean isSystem =
-                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-            // If we are being asked to delete a system app for just one
-            // user set flag so it disables rather than reverting to system
-            // version of the app.
-            if (isSystem) {
-                flags |= PackageManager.DELETE_SYSTEM_APP;
-            }
-        }
-
-        final LocalIntentReceiver receiver = new LocalIntentReceiver();
-        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
-                versionCode), null /*callerPackageName*/, flags,
-                receiver.getIntentSender(), userId);
-
-        final Intent result = receiver.getResult();
-        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                PackageInstaller.STATUS_FAILURE);
-        if (status == PackageInstaller.STATUS_SUCCESS) {
-            pw.println("Success");
-            return 0;
-        } else {
-            pw.println("Failure ["
-                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
-            return 1;
-        }
-    }
-
-    private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
-        final PrintWriter pw = getOutPrintWriter();
-        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
-        sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
-        sessionParams.appPackageName = packageName;
-        final int sessionId =
-                doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
-        boolean abandonSession = true;
-        try {
-            if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
-                    != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
-            }
-            if (doCommitSession(sessionId, false /*logSuccess*/)
-                    != PackageInstaller.STATUS_SUCCESS) {
-                return 1;
-            }
-            abandonSession = false;
-            pw.println("Success");
-            return 0;
-        } finally {
-            if (abandonSession) {
-                try {
-                    doAbandonSession(sessionId, false /*logSuccess*/);
-                } catch (Exception ignore) {
-                }
-            }
-        }
-    }
-
     private Intent parseIntentAndUser() throws URISyntaxException {
         mTargetUser = UserHandle.USER_CURRENT;
         mBrief = false;
@@ -1154,6 +835,1029 @@
         return 0;
     }
 
+    private int runInstall() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final InstallParams params = makeInstallParams();
+        final String inPath = getNextArg();
+
+        setParamsSize(params, inPath);
+        final int sessionId = doCreateSession(params.sessionParams,
+                params.installerPackageName, params.userId);
+        boolean abandonSession = true;
+        try {
+            if (inPath == null && params.sessionParams.sizeBytes == -1) {
+                pw.println("Error: must either specify a package size or an APK file");
+                return 1;
+            }
+            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+                return 1;
+            }
+            if (doCommitSession(sessionId, false /*logSuccess*/)
+                    != PackageInstaller.STATUS_SUCCESS) {
+                return 1;
+            }
+            abandonSession = false;
+            pw.println("Success");
+            return 0;
+        } finally {
+            if (abandonSession) {
+                try {
+                    doAbandonSession(sessionId, false /*logSuccess*/);
+                } catch (Exception ignore) {
+                }
+            }
+        }
+    }
+
+    private int runInstallAbandon() throws RemoteException {
+        final int sessionId = Integer.parseInt(getNextArg());
+        return doAbandonSession(sessionId, true /*logSuccess*/);
+    }
+
+    private int runInstallCommit() throws RemoteException {
+        final int sessionId = Integer.parseInt(getNextArg());
+        return doCommitSession(sessionId, true /*logSuccess*/);
+    }
+
+    private int runInstallCreate() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final InstallParams installParams = makeInstallParams();
+        final int sessionId = doCreateSession(installParams.sessionParams,
+                installParams.installerPackageName, installParams.userId);
+
+        // NOTE: adb depends on parsing this string
+        pw.println("Success: created install session [" + sessionId + "]");
+        return 0;
+    }
+
+    private int runInstallWrite() throws RemoteException {
+        long sizeBytes = -1;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("-S")) {
+                sizeBytes = Long.parseLong(getNextArg());
+            } else {
+                throw new IllegalArgumentException("Unknown option: " + opt);
+            }
+        }
+
+        final int sessionId = Integer.parseInt(getNextArg());
+        final String splitName = getNextArg();
+        final String path = getNextArg();
+        return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
+    }
+
+    private int runInstallRemove() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+
+        final int sessionId = Integer.parseInt(getNextArg());
+
+        final String splitName = getNextArg();
+        if (splitName == null) {
+            pw.println("Error: split name not specified");
+            return 1;
+        }
+        return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
+    }
+
+    private int runInstallExisting() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        int userId = UserHandle.USER_SYSTEM;
+        int installFlags = 0;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                case "--ephemeral":
+                case "--instant":
+                    installFlags |= PackageManager.INSTALL_INSTANT_APP;
+                    installFlags &= ~PackageManager.INSTALL_FULL_APP;
+                    break;
+                case "--full":
+                    installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
+                    installFlags |= PackageManager.INSTALL_FULL_APP;
+                    break;
+                default:
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
+
+        final String packageName = getNextArg();
+        if (packageName == null) {
+            pw.println("Error: package name not specified");
+            return 1;
+        }
+
+        try {
+            final int res = mInterface.installExistingPackageAsUser(packageName, userId,
+                    installFlags, PackageManager.INSTALL_REASON_UNKNOWN);
+            if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
+                throw new NameNotFoundException("Package " + packageName + " doesn't exist");
+            }
+            pw.println("Package " + packageName + " installed for user: " + userId);
+            return 0;
+        } catch (RemoteException | NameNotFoundException e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
+    private int runSetInstallLocation() throws RemoteException {
+        int loc;
+
+        String arg = getNextArg();
+        if (arg == null) {
+            getErrPrintWriter().println("Error: no install location specified.");
+            return 1;
+        }
+        try {
+            loc = Integer.parseInt(arg);
+        } catch (NumberFormatException e) {
+            getErrPrintWriter().println("Error: install location has to be a number.");
+            return 1;
+        }
+        if (!mInterface.setInstallLocation(loc)) {
+            getErrPrintWriter().println("Error: install location has to be a number.");
+            return 1;
+        }
+        return 0;
+    }
+
+    private int runGetInstallLocation() throws RemoteException {
+        int loc = mInterface.getInstallLocation();
+        String locStr = "invalid";
+        if (loc == PackageHelper.APP_INSTALL_AUTO) {
+            locStr = "auto";
+        } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) {
+            locStr = "internal";
+        } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
+            locStr = "external";
+        }
+        getOutPrintWriter().println(loc + "[" + locStr + "]");
+        return 0;
+    }
+
+    public int runMovePackage() throws RemoteException {
+        final String packageName = getNextArg();
+        if (packageName == null) {
+            getErrPrintWriter().println("Error: package name not specified");
+            return 1;
+        }
+        String volumeUuid = getNextArg();
+        if ("internal".equals(volumeUuid)) {
+            volumeUuid = null;
+        }
+
+        final int moveId = mInterface.movePackage(packageName, volumeUuid);
+
+        int status = mInterface.getMoveStatus(moveId);
+        while (!PackageManager.isMoveStatusFinished(status)) {
+            SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
+            status = mInterface.getMoveStatus(moveId);
+        }
+
+        if (status == PackageManager.MOVE_SUCCEEDED) {
+            getOutPrintWriter().println("Success");
+            return 0;
+        } else {
+            getErrPrintWriter().println("Failure [" + status + "]");
+            return 1;
+        }
+    }
+
+    public int runMovePrimaryStorage() throws RemoteException {
+        String volumeUuid = getNextArg();
+        if ("internal".equals(volumeUuid)) {
+            volumeUuid = null;
+        }
+
+        final int moveId = mInterface.movePrimaryStorage(volumeUuid);
+
+        int status = mInterface.getMoveStatus(moveId);
+        while (!PackageManager.isMoveStatusFinished(status)) {
+            SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
+            status = mInterface.getMoveStatus(moveId);
+        }
+
+        if (status == PackageManager.MOVE_SUCCEEDED) {
+            getOutPrintWriter().println("Success");
+            return 0;
+        } else {
+            getErrPrintWriter().println("Failure [" + status + "]");
+            return 1;
+        }
+    }
+
+    private int runCompile() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+        boolean forceCompilation = false;
+        boolean allPackages = false;
+        boolean clearProfileData = false;
+        String compilerFilter = null;
+        String compilationReason = null;
+        String checkProfilesRaw = null;
+        boolean secondaryDex = false;
+        String split = null;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-a":
+                    allPackages = true;
+                    break;
+                case "-c":
+                    clearProfileData = true;
+                    break;
+                case "-f":
+                    forceCompilation = true;
+                    break;
+                case "-m":
+                    compilerFilter = getNextArgRequired();
+                    break;
+                case "-r":
+                    compilationReason = getNextArgRequired();
+                    break;
+                case "--check-prof":
+                    checkProfilesRaw = getNextArgRequired();
+                    break;
+                case "--reset":
+                    forceCompilation = true;
+                    clearProfileData = true;
+                    compilationReason = "install";
+                    break;
+                case "--secondary-dex":
+                    secondaryDex = true;
+                    break;
+                case "--split":
+                    split = getNextArgRequired();
+                    break;
+                default:
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
+
+        if (checkProfilesRaw != null) {
+            if ("true".equals(checkProfilesRaw)) {
+                checkProfiles = true;
+            } else if ("false".equals(checkProfilesRaw)) {
+                checkProfiles = false;
+            } else {
+                pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
+                return 1;
+            }
+        }
+
+        if (compilerFilter != null && compilationReason != null) {
+            pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
+                    "at the same time");
+            return 1;
+        }
+        if (compilerFilter == null && compilationReason == null) {
+            pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
+                    "reason (\"-r\") at the same time");
+            return 1;
+        }
+
+        if (allPackages && split != null) {
+            pw.println("-a cannot be specified together with --split");
+            return 1;
+        }
+
+        if (secondaryDex && split != null) {
+            pw.println("--secondary-dex cannot be specified together with --split");
+            return 1;
+        }
+
+        String targetCompilerFilter;
+        if (compilerFilter != null) {
+            if (!DexFile.isValidCompilerFilter(compilerFilter)) {
+                pw.println("Error: \"" + compilerFilter +
+                        "\" is not a valid compilation filter.");
+                return 1;
+            }
+            targetCompilerFilter = compilerFilter;
+        } else {
+            int reason = -1;
+            for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
+                if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
+                        compilationReason)) {
+                    reason = i;
+                    break;
+                }
+            }
+            if (reason == -1) {
+                pw.println("Error: Unknown compilation reason: " + compilationReason);
+                return 1;
+            }
+            targetCompilerFilter =
+                    PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
+        }
+
+
+        List<String> packageNames = null;
+        if (allPackages) {
+            packageNames = mInterface.getAllPackages();
+        } else {
+            String packageName = getNextArg();
+            if (packageName == null) {
+                pw.println("Error: package name not specified");
+                return 1;
+            }
+            packageNames = Collections.singletonList(packageName);
+        }
+
+        List<String> failedPackages = new ArrayList<>();
+        for (String packageName : packageNames) {
+            if (clearProfileData) {
+                mInterface.clearApplicationProfileData(packageName);
+            }
+
+            boolean result = secondaryDex
+                    ? mInterface.performDexOptSecondary(packageName,
+                            targetCompilerFilter, forceCompilation)
+                    : mInterface.performDexOptMode(packageName,
+                            checkProfiles, targetCompilerFilter, forceCompilation,
+                            true /* bootComplete */, split);
+            if (!result) {
+                failedPackages.add(packageName);
+            }
+        }
+
+        if (failedPackages.isEmpty()) {
+            pw.println("Success");
+            return 0;
+        } else if (failedPackages.size() == 1) {
+            pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
+            return 1;
+        } else {
+            pw.print("Failure: the following packages could not be compiled: ");
+            boolean is_first = true;
+            for (String packageName : failedPackages) {
+                if (is_first) {
+                    is_first = false;
+                } else {
+                    pw.print(", ");
+                }
+                pw.print(packageName);
+            }
+            pw.println();
+            return 1;
+        }
+    }
+
+    private int runreconcileSecondaryDexFiles() throws RemoteException {
+        String packageName = getNextArg();
+        mInterface.reconcileSecondaryDexFiles(packageName);
+        return 0;
+    }
+
+    public int runForceDexOpt() throws RemoteException {
+        mInterface.forceDexOpt(getNextArgRequired());
+        return 0;
+    }
+
+    private int runDexoptJob() throws RemoteException {
+        boolean result = mInterface.runBackgroundDexoptJob();
+        return result ? 0 : -1;
+    }
+
+    private int runDumpProfiles() throws RemoteException {
+        String packageName = getNextArg();
+        mInterface.dumpProfiles(packageName);
+        return 0;
+    }
+
+    private int runUninstall() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        int flags = 0;
+        int userId = UserHandle.USER_ALL;
+        int versionCode = PackageManager.VERSION_CODE_HIGHEST;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-k":
+                    flags |= PackageManager.DELETE_KEEP_DATA;
+                    break;
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                case "--versionCode":
+                    versionCode = Integer.parseInt(getNextArgRequired());
+                    break;
+                default:
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
+
+        final String packageName = getNextArg();
+        if (packageName == null) {
+            pw.println("Error: package name not specified");
+            return 1;
+        }
+
+        // if a split is specified, just remove it and not the whole package
+        final String splitName = getNextArg();
+        if (splitName != null) {
+            return runRemoveSplit(packageName, splitName);
+        }
+
+        userId = translateUserId(userId, "runUninstall");
+        if (userId == UserHandle.USER_ALL) {
+            userId = UserHandle.USER_SYSTEM;
+            flags |= PackageManager.DELETE_ALL_USERS;
+        } else {
+            final PackageInfo info = mInterface.getPackageInfo(packageName,
+                    PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
+            if (info == null) {
+                pw.println("Failure [not installed for " + userId + "]");
+                return 1;
+            }
+            final boolean isSystem =
+                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+            // If we are being asked to delete a system app for just one
+            // user set flag so it disables rather than reverting to system
+            // version of the app.
+            if (isSystem) {
+                flags |= PackageManager.DELETE_SYSTEM_APP;
+            }
+        }
+
+        final LocalIntentReceiver receiver = new LocalIntentReceiver();
+        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
+                versionCode), null /*callerPackageName*/, flags,
+                receiver.getIntentSender(), userId);
+
+        final Intent result = receiver.getResult();
+        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                PackageInstaller.STATUS_FAILURE);
+        if (status == PackageInstaller.STATUS_SUCCESS) {
+            pw.println("Success");
+            return 0;
+        } else {
+            pw.println("Failure ["
+                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+            return 1;
+        }
+    }
+
+    private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
+        sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+        sessionParams.appPackageName = packageName;
+        final int sessionId =
+                doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
+        boolean abandonSession = true;
+        try {
+            if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
+                    != PackageInstaller.STATUS_SUCCESS) {
+                return 1;
+            }
+            if (doCommitSession(sessionId, false /*logSuccess*/)
+                    != PackageInstaller.STATUS_SUCCESS) {
+                return 1;
+            }
+            abandonSession = false;
+            pw.println("Success");
+            return 0;
+        } finally {
+            if (abandonSession) {
+                try {
+                    doAbandonSession(sessionId, false /*logSuccess*/);
+                } catch (Exception ignore) {
+                }
+            }
+        }
+    }
+
+    static class ClearDataObserver extends IPackageDataObserver.Stub {
+        boolean finished;
+        boolean result;
+
+        @Override
+        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
+            synchronized (this) {
+                finished = true;
+                result = succeeded;
+                notifyAll();
+            }
+        }
+    }
+
+    private int runClear() throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+        String option = getNextOption();
+        if (option != null && option.equals("--user")) {
+            userId = UserHandle.parseUserArg(getNextArgRequired());
+        }
+
+        String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified");
+            return 1;
+        }
+
+        ClearDataObserver obs = new ClearDataObserver();
+        ActivityManager.getService().clearApplicationUserData(pkg, obs, userId);
+        synchronized (obs) {
+            while (!obs.finished) {
+                try {
+                    obs.wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
+        if (obs.result) {
+            getOutPrintWriter().println("Success");
+            return 0;
+        } else {
+            getErrPrintWriter().println("Failed");
+            return 1;
+        }
+    }
+
+    private static String enabledSettingToString(int state) {
+        switch (state) {
+            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+                return "default";
+            case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+                return "enabled";
+            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
+                return "disabled";
+            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
+                return "disabled-user";
+            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
+                return "disabled-until-used";
+        }
+        return "unknown";
+    }
+
+    private int runSetEnabledSetting(int state) throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+        String option = getNextOption();
+        if (option != null && option.equals("--user")) {
+            userId = UserHandle.parseUserArg(getNextArgRequired());
+        }
+
+        String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package or component specified");
+            return 1;
+        }
+        ComponentName cn = ComponentName.unflattenFromString(pkg);
+        if (cn == null) {
+            mInterface.setApplicationEnabledSetting(pkg, state, 0, userId,
+                    "shell:" + android.os.Process.myUid());
+            getOutPrintWriter().println("Package " + pkg + " new state: "
+                    + enabledSettingToString(
+                    mInterface.getApplicationEnabledSetting(pkg, userId)));
+            return 0;
+        } else {
+            mInterface.setComponentEnabledSetting(cn, state, 0, userId);
+            getOutPrintWriter().println("Component " + cn.toShortString() + " new state: "
+                    + enabledSettingToString(
+                    mInterface.getComponentEnabledSetting(cn, userId)));
+            return 0;
+        }
+    }
+
+    private int runSetHiddenSetting(boolean state) throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+        String option = getNextOption();
+        if (option != null && option.equals("--user")) {
+            userId = UserHandle.parseUserArg(getNextArgRequired());
+        }
+
+        String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package or component specified");
+            return 1;
+        }
+        mInterface.setApplicationHiddenSettingAsUser(pkg, state, userId);
+        getOutPrintWriter().println("Package " + pkg + " new hidden state: "
+                + mInterface.getApplicationHiddenSettingAsUser(pkg, userId));
+        return 0;
+    }
+
+    private int runSuspend(boolean suspendedState) {
+        final PrintWriter pw = getOutPrintWriter();
+        int userId = UserHandle.USER_SYSTEM;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+                default:
+                    pw.println("Error: Unknown option: " + opt);
+                    return 1;
+            }
+        }
+
+        String packageName = getNextArg();
+        if (packageName == null) {
+            pw.println("Error: package name not specified");
+            return 1;
+        }
+
+        try {
+            mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
+                    userId);
+            pw.println("Package " + packageName + " new suspended state: "
+                    + mInterface.isPackageSuspendedForUser(packageName, userId));
+            return 0;
+        } catch (RemoteException | IllegalArgumentException e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
+    private int runGrantRevokePermission(boolean grant) throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+
+        String opt = null;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            }
+        }
+
+        String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified");
+            return 1;
+        }
+        String perm = getNextArg();
+        if (perm == null) {
+            getErrPrintWriter().println("Error: no permission specified");
+            return 1;
+        }
+
+        if (grant) {
+            mInterface.grantRuntimePermission(pkg, perm, userId);
+        } else {
+            mInterface.revokeRuntimePermission(pkg, perm, userId);
+        }
+        return 0;
+    }
+
+    private int runResetPermissions() throws RemoteException {
+        mInterface.resetRuntimePermissions();
+        return 0;
+    }
+
+    private int runSetPermissionEnforced() throws RemoteException {
+        final String permission = getNextArg();
+        if (permission == null) {
+            getErrPrintWriter().println("Error: no permission specified");
+            return 1;
+        }
+        final String enforcedRaw = getNextArg();
+        if (enforcedRaw == null) {
+            getErrPrintWriter().println("Error: no enforcement specified");
+            return 1;
+        }
+        mInterface.setPermissionEnforced(permission, Boolean.parseBoolean(enforcedRaw));
+        return 0;
+    }
+
+    private int runGetPrivappPermissions() {
+        final String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified.");
+            return 1;
+        }
+        ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
+        getOutPrintWriter().println(privAppPermissions == null
+                ? "{}" : privAppPermissions.toString());
+        return 0;
+    }
+
+    private int runGetPrivappDenyPermissions() {
+        final String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified.");
+            return 1;
+        }
+        ArraySet<String> privAppDenyPermissions =
+                SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+        getOutPrintWriter().println(privAppDenyPermissions == null
+                ? "{}" : privAppDenyPermissions.toString());
+        return 0;
+    }
+
+    private int runGetOemPermissions() {
+        final String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified.");
+            return 1;
+        }
+        final Map<String, Boolean> oemPermissions = SystemConfig.getInstance()
+                .getOemPermissions(pkg);
+        if (oemPermissions == null || oemPermissions.isEmpty()) {
+            getOutPrintWriter().println("{}");
+        } else {
+            oemPermissions.forEach((permission, granted) ->
+                    getOutPrintWriter().println(permission + " granted:" + granted)
+            );
+        }
+        return 0;
+    }
+
+    private String linkStateToString(int state) {
+        switch (state) {
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: return "undefined";
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: return "ask";
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: return "always";
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: return "never";
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK : return "always ask";
+        }
+        return "Unknown link state: " + state;
+    }
+
+    // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined}
+    private int runSetAppLink() throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: unknown option: " + opt);
+                return 1;
+            }
+        }
+
+        // Package name to act on; required
+        final String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified.");
+            return 1;
+        }
+
+        // State to apply; {always|ask|never|undefined}, required
+        final String modeString = getNextArg();
+        if (modeString == null) {
+            getErrPrintWriter().println("Error: no app link state specified.");
+            return 1;
+        }
+
+        final int newMode;
+        switch (modeString.toLowerCase()) {
+            case "undefined":
+                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+                break;
+
+            case "always":
+                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+                break;
+
+            case "ask":
+                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
+                break;
+
+            case "always-ask":
+                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
+                break;
+
+            case "never":
+                newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
+                break;
+
+            default:
+                getErrPrintWriter().println("Error: unknown app link state '" + modeString + "'");
+                return 1;
+        }
+
+        final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId);
+        if (info == null) {
+            getErrPrintWriter().println("Error: package " + pkg + " not found.");
+            return 1;
+        }
+
+        if ((info.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) {
+            getErrPrintWriter().println("Error: package " + pkg + " does not handle web links.");
+            return 1;
+        }
+
+        if (!mInterface.updateIntentVerificationStatus(pkg, newMode, userId)) {
+            getErrPrintWriter().println("Error: unable to update app link status for " + pkg);
+            return 1;
+        }
+
+        return 0;
+    }
+
+    // pm get-app-link [--user USER_ID] PACKAGE
+    private int runGetAppLink() throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else {
+                getErrPrintWriter().println("Error: unknown option: " + opt);
+                return 1;
+            }
+        }
+
+        // Package name to act on; required
+        final String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified.");
+            return 1;
+        }
+
+        final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId);
+        if (info == null) {
+            getErrPrintWriter().println("Error: package " + pkg + " not found.");
+            return 1;
+        }
+
+        if ((info.applicationInfo.privateFlags
+                & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) {
+            getErrPrintWriter().println("Error: package " + pkg + " does not handle web links.");
+            return 1;
+        }
+
+        getOutPrintWriter().println(linkStateToString(
+                mInterface.getIntentVerificationStatus(pkg, userId)));
+
+        return 0;
+    }
+
+    private int runTrimCaches() throws RemoteException {
+        String size = getNextArg();
+        if (size == null) {
+            getErrPrintWriter().println("Error: no size specified");
+            return 1;
+        }
+        long multiplier = 1;
+        int len = size.length();
+        char c = size.charAt(len - 1);
+        if (c < '0' || c > '9') {
+            if (c == 'K' || c == 'k') {
+                multiplier = 1024L;
+            } else if (c == 'M' || c == 'm') {
+                multiplier = 1024L*1024L;
+            } else if (c == 'G' || c == 'g') {
+                multiplier = 1024L*1024L*1024L;
+            } else {
+                getErrPrintWriter().println("Invalid suffix: " + c);
+                return 1;
+            }
+            size = size.substring(0, len-1);
+        }
+        long sizeVal;
+        try {
+            sizeVal = Long.parseLong(size) * multiplier;
+        } catch (NumberFormatException e) {
+            getErrPrintWriter().println("Error: expected number at: " + size);
+            return 1;
+        }
+        String volumeUuid = getNextArg();
+        if ("internal".equals(volumeUuid)) {
+            volumeUuid = null;
+        }
+        ClearDataObserver obs = new ClearDataObserver();
+        mInterface.freeStorageAndNotify(volumeUuid, sizeVal,
+                StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs);
+        synchronized (obs) {
+            while (!obs.finished) {
+                try {
+                    obs.wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        return 0;
+    }
+
+    private static boolean isNumber(String s) {
+        try {
+            Integer.parseInt(s);
+        } catch (NumberFormatException nfe) {
+            return false;
+        }
+        return true;
+    }
+
+    public int runCreateUser() throws RemoteException {
+        String name;
+        int userId = -1;
+        int flags = 0;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if ("--profileOf".equals(opt)) {
+                userId = UserHandle.parseUserArg(getNextArgRequired());
+            } else if ("--managed".equals(opt)) {
+                flags |= UserInfo.FLAG_MANAGED_PROFILE;
+            } else if ("--restricted".equals(opt)) {
+                flags |= UserInfo.FLAG_RESTRICTED;
+            } else if ("--ephemeral".equals(opt)) {
+                flags |= UserInfo.FLAG_EPHEMERAL;
+            } else if ("--guest".equals(opt)) {
+                flags |= UserInfo.FLAG_GUEST;
+            } else if ("--demo".equals(opt)) {
+                flags |= UserInfo.FLAG_DEMO;
+            } else {
+                getErrPrintWriter().println("Error: unknown option " + opt);
+                return 1;
+            }
+        }
+        String arg = getNextArg();
+        if (arg == null) {
+            getErrPrintWriter().println("Error: no user name specified.");
+            return 1;
+        }
+        name = arg;
+        UserInfo info;
+        IUserManager um = IUserManager.Stub.asInterface(
+                ServiceManager.getService(Context.USER_SERVICE));
+        IAccountManager accm = IAccountManager.Stub.asInterface(
+                ServiceManager.getService(Context.ACCOUNT_SERVICE));
+        if ((flags & UserInfo.FLAG_RESTRICTED) != 0) {
+            // In non-split user mode, userId can only be SYSTEM
+            int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
+            info = um.createRestrictedProfile(name, parentUserId);
+            accm.addSharedAccountsFromParentUser(parentUserId, userId,
+                    (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell");
+        } else if (userId < 0) {
+            info = um.createUser(name, flags);
+        } else {
+            info = um.createProfileForUser(name, flags, userId, null);
+        }
+
+        if (info != null) {
+            getOutPrintWriter().println("Success: created user id " + info.id);
+            return 0;
+        } else {
+            getErrPrintWriter().println("Error: couldn't create User.");
+            return 1;
+        }
+    }
+
+    public int runRemoveUser() throws RemoteException {
+        int userId;
+        String arg = getNextArg();
+        if (arg == null) {
+            getErrPrintWriter().println("Error: no user id specified.");
+            return 1;
+        }
+        userId = UserHandle.parseUserArg(arg);
+        IUserManager um = IUserManager.Stub.asInterface(
+                ServiceManager.getService(Context.USER_SERVICE));
+        if (um.removeUser(userId)) {
+            getOutPrintWriter().println("Success: removed user");
+            return 0;
+        } else {
+            getErrPrintWriter().println("Error: couldn't remove user id " + userId);
+            return 1;
+        }
+    }
+
+    public int runSetUserRestriction() throws RemoteException {
+        int userId = UserHandle.USER_SYSTEM;
+        String opt = getNextOption();
+        if (opt != null && "--user".equals(opt)) {
+            userId = UserHandle.parseUserArg(getNextArgRequired());
+        }
+
+        String restriction = getNextArg();
+        String arg = getNextArg();
+        boolean value;
+        if ("1".equals(arg)) {
+            value = true;
+        } else if ("0".equals(arg)) {
+            value = false;
+        } else {
+            getErrPrintWriter().println("Error: valid value not specified");
+            return 1;
+        }
+        IUserManager um = IUserManager.Stub.asInterface(
+                ServiceManager.getService(Context.USER_SERVICE));
+        um.setUserRestriction(restriction, value, userId);
+        return 0;
+    }
+
+    public int runGetMaxUsers() {
+        getOutPrintWriter().println("Maximum supported users: "
+                + UserManager.getMaxSupportedUsers());
+        return 0;
+    }
+
     private static class InstallParams {
         SessionParams sessionParams;
         String installerPackageName;
@@ -1287,46 +1991,17 @@
         }
     }
 
-    private int runGetPrivappPermissions() {
-        final String pkg = getNextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified.");
-            return 1;
-        }
-        ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
-        getOutPrintWriter().println(privAppPermissions == null
-                ? "{}" : privAppPermissions.toString());
-        return 0;
-    }
+    private int runSetInstaller() throws RemoteException {
+        final String targetPackage = getNextArg();
+        final String installerPackageName = getNextArg();
 
-    private int runGetPrivappDenyPermissions() {
-        final String pkg = getNextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified.");
+        if (targetPackage == null || installerPackageName == null) {
+            getErrPrintWriter().println("Must provide both target and installer package names");
             return 1;
         }
-        ArraySet<String> privAppDenyPermissions =
-                SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
-        getOutPrintWriter().println(privAppDenyPermissions == null
-                ? "{}" : privAppDenyPermissions.toString());
-        return 0;
-    }
 
-    private int runGetOemPermissions() {
-        final String pkg = getNextArg();
-        if (pkg == null) {
-            System.err.println("Error: no package specified.");
-            return 1;
-        }
-        final Map<String, Boolean> oemPermissions = SystemConfig.getInstance()
-                .getOemPermissions(pkg);
-        if (oemPermissions == null || oemPermissions.isEmpty()) {
-            getOutPrintWriter().println("{}");
-        } else {
-            oemPermissions.forEach((permission, granted) ->
-                getOutPrintWriter().println(permission + " granted:" + granted)
-            );
-        }
+        mInterface.setInstallerPackageName(targetPackage, installerPackageName);
+        getOutPrintWriter().println("Success");
         return 0;
     }
 
@@ -1367,6 +2042,16 @@
         }
     }
 
+    private int runDump() {
+        String pkg = getNextArg();
+        if (pkg == null) {
+            getErrPrintWriter().println("Error: no package specified");
+            return 1;
+        }
+        ActivityManager.dumpPackageStateStatic(getOutFileDescriptor(), pkg);
+        return 0;
+    }
+
     private static String checkAbiArgument(String abi) {
         if (TextUtils.isEmpty(abi)) {
             throw new IllegalArgumentException("Missing ABI argument");
@@ -1663,10 +2348,203 @@
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.println("");
+        pw.println("  path [--user USER_ID] PACKAGE");
+        pw.println("    Print the path to the .apk of the given PACKAGE.");
+        pw.println("");
+        pw.println("  dump PACKAGE");
+        pw.println("    Print various system state associated with the given PACKAGE.");
+        pw.println("");
+        pw.println("  list features");
+        pw.println("    Prints all features of the system.");
+        pw.println("");
+        pw.println("  has-feature FEATURE_NAME [version]");
+        pw.println("    Prints true and returns exit status 0 when system has a FEATURE_NAME,");
+        pw.println("    otherwise prints false and returns exit status 1");
+        pw.println("");
+        pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
+        pw.println("    Prints all test packages; optionally only those targeting TARGET-PACKAGE");
+        pw.println("    Options:");
+        pw.println("      -f: dump the name of the .apk file containing the test package");
+        pw.println("");
+        pw.println("  list libraries");
+        pw.println("    Prints all system libraries.");
+        pw.println("");
+        pw.println("  list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] ");
+        pw.println("      [--uid UID] [--user USER_ID] [FILTER]");
+        pw.println("    Prints all packages; optionally only those whose name contains");
+        pw.println("    the text in FILTER.  Options are:");
+        pw.println("      -f: see their associated file");
+        pw.println("      -d: filter to only show disabled packages");
+        pw.println("      -e: filter to only show enabled packages");
+        pw.println("      -s: filter to only show system packages");
+        pw.println("      -3: filter to only show third party packages");
+        pw.println("      -i: see the installer for the packages");
+        pw.println("      -l: ignored (used for compatibility with older releases)");
+        pw.println("      -U: also show the package UID");
+        pw.println("      -u: also include uninstalled packages");
+        pw.println("      --uid UID: filter to only show packages with the given UID");
+        pw.println("      --user USER_ID: only list packages belonging to the given user");
+        pw.println("");
+        pw.println("  list permission-groups");
+        pw.println("    Prints all known permission groups.");
+        pw.println("");
+        pw.println("  list permissions [-g] [-f] [-d] [-u] [GROUP]");
+        pw.println("    Prints all known permissions; optionally only those in GROUP.  Options are:");
+        pw.println("      -g: organize by group");
+        pw.println("      -f: print all information");
+        pw.println("      -s: short summary");
+        pw.println("      -d: only list dangerous permissions");
+        pw.println("      -u: list only the permissions users will see");
+        pw.println("");
+        pw.println("  resolve-activity [--brief] [--components] [--user USER_ID] INTENT");
+        pw.println("    Prints the activity that resolves to the given INTENT.");
+        pw.println("");
+        pw.println("  query-activities [--brief] [--components] [--user USER_ID] INTENT");
+        pw.println("    Prints all activities that can handle the given INTENT.");
+        pw.println("");
+        pw.println("  query-services [--brief] [--components] [--user USER_ID] INTENT");
+        pw.println("    Prints all services that can handle the given INTENT.");
+        pw.println("");
+        pw.println("  query-receivers [--brief] [--components] [--user USER_ID] INTENT");
+        pw.println("    Prints all broadcast receivers that can handle the given INTENT.");
+        pw.println("");
+        pw.println("  install [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
+        pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
+        pw.println("       [--originating-uri URI] [---referrer URI]");
+        pw.println("       [--abi ABI_NAME] [--force-sdk]");
+        pw.println("       [--preload] [--instantapp] [--full] [--dont-kill]");
+        pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]");
+        pw.println("    Install an application.  Must provide the apk data to install, either as a");
+        pw.println("    file path or '-' to read from stdin.  Options are:");
+        pw.println("      -l: forward lock application");
+        pw.println("      -r: allow replacement of existing application");
+        pw.println("      -t: allow test packages");
+        pw.println("      -i: specify package name of installer owning the app");
+        pw.println("      -s: install application on sdcard");
+        pw.println("      -f: install application on internal flash");
+        pw.println("      -d: allow version code downgrade (debuggable packages only)");
+        pw.println("      -p: partial application install (new split on top of existing pkg)");
+        pw.println("      -g: grant all runtime permissions");
+        pw.println("      -S: size in bytes of package, required for stdin");
+        pw.println("      --user: install under the given user.");
+        pw.println("      --dont-kill: installing a new feature split, don't kill running app");
+        pw.println("      --originating-uri: set URI where app was downloaded from");
+        pw.println("      --referrer: set URI that instigated the install of the app");
+        pw.println("      --pkg: specify expected package name of app being installed");
+        pw.println("      --abi: override the default ABI of the platform");
+        pw.println("      --instantapp: cause the app to be installed as an ephemeral install app");
+        pw.println("      --full: cause the app to be installed as a non-ephemeral full app");
+        pw.println("      --install-location: force the install location:");
+        pw.println("          0=auto, 1=internal only, 2=prefer external");
+        pw.println("      --force-uuid: force install on to disk volume with given UUID");
+        pw.println("      --force-sdk: allow install even when existing app targets platform");
+        pw.println("          codename but new one targets a final API level");
+        pw.println("");
+        pw.println("  install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
+        pw.println("       [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
+        pw.println("       [--originating-uri URI] [---referrer URI]");
+        pw.println("       [--abi ABI_NAME] [--force-sdk]");
+        pw.println("       [--preload] [--instantapp] [--full] [--dont-kill]");
+        pw.println("       [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+        pw.println("    Like \"install\", but starts an install session.  Use \"install-write\"");
+        pw.println("    to push data into the session, and \"install-commit\" to finish.");
+        pw.println("");
+        pw.println("  install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]");
+        pw.println("    Write an apk into the given install session.  If the path is '-', data");
+        pw.println("    will be read from stdin.  Options are:");
+        pw.println("      -S: size in bytes of package, required for stdin");
+        pw.println("");
+        pw.println("  install-commit SESSION_ID");
+        pw.println("    Commit the given active install session, installing the app.");
+        pw.println("");
+        pw.println("  install-abandon SESSION_ID");
+        pw.println("    Delete the given active install session.");
+        pw.println("");
+        pw.println("  set-install-location LOCATION");
+        pw.println("    Changes the default install location.  NOTE this is only intended for debugging;");
+        pw.println("    using this can cause applications to break and other undersireable behavior.");
+        pw.println("    LOCATION is one of:");
+        pw.println("    0 [auto]: Let system decide the best location");
+        pw.println("    1 [internal]: Install on internal device storage");
+        pw.println("    2 [external]: Install on external media");
+        pw.println("");
+        pw.println("  get-install-location");
+        pw.println("    Returns the current install location: 0, 1 or 2 as per set-install-location.");
+        pw.println("");
+        pw.println("  move-package PACKAGE [internal|UUID]");
+        pw.println("");
+        pw.println("  move-primary-storage [internal|UUID]");
+        pw.println("");
+        pw.println("  pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE [SPLIT]");
+        pw.println("    Remove the given package name from the system.  May remove an entire app");
+        pw.println("    if no SPLIT name is specified, otherwise will remove only the split of the");
+        pw.println("    given app.  Options are:");
+        pw.println("      -k: keep the data and cache directories around after package removal.");
+        pw.println("      --user: remove the app from the given user.");
+        pw.println("      --versionCode: only uninstall if the app has the given version code.");
+        pw.println("");
+        pw.println("  clear [--user USER_ID] PACKAGE");
+        pw.println("    Deletes all data associated with a package.");
+        pw.println("");
+        pw.println("  enable [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("  disable [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("  disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("  disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("  default-state [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("    These commands change the enabled state of a given package or");
+        pw.println("    component (written as \"package/class\").");
+        pw.println("");
+        pw.println("  hide [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("  unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
+        pw.println("");
+        pw.println("  suspend [--user USER_ID] TARGET-PACKAGE");
+        pw.println("    Suspends the specified package (as user).");
+        pw.println("");
+        pw.println("  unsuspend [--user USER_ID] TARGET-PACKAGE");
+        pw.println("    Unsuspends the specified package (as user).");
+        pw.println("");
+        pw.println("  grant [--user USER_ID] PACKAGE PERMISSION");
+        pw.println("  revoke [--user USER_ID] PACKAGE PERMISSION");
+        pw.println("    These commands either grant or revoke permissions to apps.  The permissions");
+        pw.println("    must be declared as used in the app's manifest, be runtime permissions");
+        pw.println("    (protection level dangerous), and the app targeting SDK greater than Lollipop MR1.");
+        pw.println("");
+        pw.println("  reset-permissions");
+        pw.println("    Revert all runtime permissions to their default state.");
+        pw.println("");
+        pw.println("  set-permission-enforced PERMISSION [true|false]");
+        pw.println("");
+        pw.println("  get-privapp-permissions TARGET-PACKAGE");
+        pw.println("    Prints all privileged permissions for a package.");
+        pw.println("");
+        pw.println("  get-privapp-deny-permissions TARGET-PACKAGE");
+        pw.println("    Prints all privileged permissions that are denied for a package.");
+        pw.println("");
+        pw.println("  get-oem-permissions TARGET-PACKAGE");
+        pw.println("    Prints all OEM permissions for a package.");
+        pw.println("");
+        pw.println("  set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}");
+        pw.println("  get-app-link [--user USER_ID] PACKAGE");
+        pw.println("");
+        pw.println("  trim-caches DESIRED_FREE_SPACE [internal|UUID]");
+        pw.println("    Trim cache files to reach the given free space.");
+        pw.println("");
+        pw.println("  create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral]");
+        pw.println("      [--guest] USER_NAME");
+        pw.println("    Create a new user with the given USER_NAME, printing the new user identifier");
+        pw.println("    of the user.");
+        pw.println("");
+        pw.println("  remove-user USER_ID");
+        pw.println("    Remove the user with the given USER_IDENTIFIER, deleting all data");
+        pw.println("    associated with that user");
+        pw.println("");
+        pw.println("  set-user-restriction [--user USER_ID] RESTRICTION VALUE");
+        pw.println("");
+        pw.println("  get-max-users");
+        pw.println("");
         pw.println("  compile [-m MODE | -r REASON] [-f] [-c] [--split SPLIT_NAME]");
         pw.println("          [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)");
-        pw.println("    Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".");
-        pw.println("    Options:");
+        pw.println("    Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".  Options are:");
         pw.println("      -a: compile all packages");
         pw.println("      -c: clear profile data before compiling");
         pw.println("      -f: force compilation even if not needed");
@@ -1690,72 +2568,32 @@
         pw.println("      --check-prof (true | false): look at profiles when doing dexopt?");
         pw.println("      --secondary-dex: compile app secondary dex files");
         pw.println("      --split SPLIT: compile only the given split name");
+        pw.println("");
+        pw.println("  force-dex-opt PACKAGE");
+        pw.println("    Force immediate execution of dex opt for the given PACKAGE.");
+        pw.println("");
         pw.println("  bg-dexopt-job");
         pw.println("    Execute the background optimizations immediately.");
         pw.println("    Note that the command only runs the background optimizer logic. It may");
         pw.println("    overlap with the actual job but the job scheduler will not be able to");
         pw.println("    cancel it. It will also run even if the device is not in the idle");
         pw.println("    maintenance mode.");
-        pw.println("  list features");
-        pw.println("    Prints all features of the system.");
-        pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
-        pw.println("    Prints all test packages; optionally only those targeting TARGET-PACKAGE");
-        pw.println("    Options:");
-        pw.println("      -f: dump the name of the .apk file containing the test package");
-        pw.println("  list libraries");
-        pw.println("    Prints all system libraries.");
-        pw.println("  list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] "
-                + "[--uid UID] [--user USER_ID] [FILTER]");
-        pw.println("    Prints all packages; optionally only those whose name contains");
-        pw.println("    the text in FILTER.");
-        pw.println("    Options:");
-        pw.println("      -f: see their associated file");
-        pw.println("      -d: filter to only show disabled packages");
-        pw.println("      -e: filter to only show enabled packages");
-        pw.println("      -s: filter to only show system packages");
-        pw.println("      -3: filter to only show third party packages");
-        pw.println("      -i: see the installer for the packages");
-        pw.println("      -l: ignored (used for compatibility with older releases)");
-        pw.println("      -U: also show the package UID");
-        pw.println("      -u: also include uninstalled packages");
-        pw.println("      --uid UID: filter to only show packages with the given UID");
-        pw.println("      --user USER_ID: only list packages belonging to the given user");
+        pw.println("");
         pw.println("  reconcile-secondary-dex-files TARGET-PACKAGE");
         pw.println("    Reconciles the package secondary dex files with the generated oat files.");
-        pw.println("  list permission-groups");
-        pw.println("    Prints all known permission groups.");
-        pw.println("  list permissions [-g] [-f] [-d] [-u] [GROUP]");
-        pw.println("    Prints all known permissions; optionally only those in GROUP.");
-        pw.println("    Options:");
-        pw.println("      -g: organize by group");
-        pw.println("      -f: print all information");
-        pw.println("      -s: short summary");
-        pw.println("      -d: only list dangerous permissions");
-        pw.println("      -u: list only the permissions users will see");
+        pw.println("");
         pw.println("  dump-profiles TARGET-PACKAGE");
         pw.println("    Dumps method/class profile files to");
         pw.println("    /data/misc/profman/TARGET-PACKAGE.txt");
-        pw.println("  resolve-activity [--brief] [--components] [--user USER_ID] INTENT");
-        pw.println("    Prints the activity that resolves to the given Intent.");
-        pw.println("  query-activities [--brief] [--components] [--user USER_ID] INTENT");
-        pw.println("    Prints all activities that can handle the given Intent.");
-        pw.println("  query-services [--brief] [--components] [--user USER_ID] INTENT");
-        pw.println("    Prints all services that can handle the given Intent.");
-        pw.println("  query-receivers [--brief] [--components] [--user USER_ID] INTENT");
-        pw.println("    Prints all broadcast receivers that can handle the given Intent.");
-        pw.println("  suspend [--user USER_ID] TARGET-PACKAGE");
-        pw.println("    Suspends the specified package (as user).");
-        pw.println("  unsuspend [--user USER_ID] TARGET-PACKAGE");
-        pw.println("    Unsuspends the specified package (as user).");
+        pw.println("");
         pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
-        pw.println("    set the default home activity (aka launcher).");
-        pw.println("  has-feature FEATURE_NAME [version]");
-        pw.println("   prints true and returns exit status 0 when system has a FEATURE_NAME,");
-        pw.println("   otherwise prints false and returns exit status 1");
-        pw.println("  get-privileged-permissions TARGET-PACKAGE");
-        pw.println("   prints all privileged permissions for a package.");
-        pw.println("  get-oem-permissions TARGET-PACKAGE");
-        pw.println("   prints all OEM permissions for a package.");
+        pw.println("    Set the default home activity (aka launcher).");
+        pw.println("");
+        pw.println("  set-installer PACKAGE INSTALLER");
+        pw.println("    Set installer package name");
+        pw.println("");
+        pw.println("  get-instantapp-resolver");
+        pw.println("    Return the name of the component that is the current instant app installer.");
         pw.println();
         Intent.printIntentArgsHelp(pw , "");
     }
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 6dd9aa4..e5d3915 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -478,7 +478,7 @@
         }
     }
 
-    public void dump(IndentingPrintWriter idpw, int userId) {
+    public void dump(IndentingPrintWriter idpw, int userId, String pkg) {
         idpw.println("Package idle stats:");
         idpw.increaseIndent();
         ArrayMap<String, AppUsageHistory> userHistory = mIdleHistory.get(userId);
@@ -490,6 +490,9 @@
         for (int p = 0; p < P; p++) {
             final String packageName = userHistory.keyAt(p);
             final AppUsageHistory appUsageHistory = userHistory.valueAt(p);
+            if (pkg != null && !pkg.equals(packageName)) {
+                continue;
+            }
             idpw.print("package=" + packageName);
             idpw.print(" lastUsedElapsed=");
             TimeUtils.formatDuration(totalElapsedTime - appUsageHistory.lastUsedElapsedTime, idpw);
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index dad5950..17fde57 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -873,9 +873,9 @@
         }
     }
 
-    void dumpUser(IndentingPrintWriter idpw, int userId) {
+    void dumpUser(IndentingPrintWriter idpw, int userId, String pkg) {
         synchronized (mAppIdleLock) {
-            mAppIdleHistory.dump(idpw, userId);
+            mAppIdleHistory.dump(idpw, userId, pkg);
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 3a958da..44e6a6c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -470,8 +470,32 @@
     void dump(String[] args, PrintWriter pw) {
         synchronized (mLock) {
             IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
-            ArraySet<String> argSet = new ArraySet<>();
-            argSet.addAll(Arrays.asList(args));
+
+            boolean checkin = false;
+            boolean history = false;
+            String pkg = null;
+
+            if (args != null) {
+                for (int i = 0; i < args.length; i++) {
+                    String arg = args[i];
+                    if ("--checkin".equals(arg)) {
+                        checkin = true;
+                    } else if ("--history".equals(arg)) {
+                        history = true;
+                    } else if ("history".equals(arg)) {
+                        history = true;
+                        break;
+                    } else if ("flush".equals(arg)) {
+                        flushToDiskLocked();
+                        pw.println("Flushed stats to disk");
+                        return;
+                    } else {
+                        // Anything else is a pkg to filter
+                        pkg = arg;
+                        break;
+                    }
+                }
+            }
 
             final int userCount = mUserState.size();
             for (int i = 0; i < userCount; i++) {
@@ -479,26 +503,23 @@
                 idpw.printPair("user", userId);
                 idpw.println();
                 idpw.increaseIndent();
-                if (argSet.contains("--checkin")) {
+                if (checkin) {
                     mUserState.valueAt(i).checkin(idpw);
                 } else {
-                    mUserState.valueAt(i).dump(idpw);
+                    mUserState.valueAt(i).dump(idpw, pkg);
                     idpw.println();
-                    if (args.length > 0) {
-                        if ("history".equals(args[0])) {
-                            mAppStandby.dumpHistory(idpw, userId);
-                        } else if ("flush".equals(args[0])) {
-                            flushToDiskLocked();
-                            pw.println("Flushed stats to disk");
-                        }
+                    if (history) {
+                        mAppStandby.dumpHistory(idpw, userId);
                     }
                 }
-                mAppStandby.dumpUser(idpw, userId);
+                mAppStandby.dumpUser(idpw, userId, pkg);
                 idpw.decreaseIndent();
             }
 
-            pw.println();
-            mAppStandby.dumpState(args, pw);
+            if (pkg == null) {
+                pw.println();
+                mAppStandby.dumpState(args, pw);
+            }
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 0abbb82..0b10590 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -474,19 +474,19 @@
         mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
             @Override
             public boolean checkin(IntervalStats stats) {
-                printIntervalStats(pw, stats, false);
+                printIntervalStats(pw, stats, false, null);
                 return true;
             }
         });
     }
 
-    void dump(IndentingPrintWriter pw) {
+    void dump(IndentingPrintWriter pw, String pkg) {
         // This is not a check-in, only dump in-memory stats.
         for (int interval = 0; interval < mCurrentStats.length; interval++) {
             pw.print("In-memory ");
             pw.print(intervalToString(interval));
             pw.println(" stats");
-            printIntervalStats(pw, mCurrentStats[interval], true);
+            printIntervalStats(pw, mCurrentStats[interval], true, pkg);
         }
     }
 
@@ -505,7 +505,7 @@
     }
 
     void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
-            boolean prettyDates) {
+            boolean prettyDates, String pkg) {
         if (prettyDates) {
             pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
                     stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
@@ -521,6 +521,9 @@
         final int pkgCount = pkgStats.size();
         for (int i = 0; i < pkgCount; i++) {
             final UsageStats usageStats = pkgStats.valueAt(i);
+            if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
+                continue;
+            }
             pw.printPair("package", usageStats.mPackageName);
             pw.printPair("totalTime",
                     formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
@@ -533,6 +536,9 @@
         pw.println("ChooserCounts");
         pw.increaseIndent();
         for (UsageStats usageStats : pkgStats.values()) {
+            if (pkg != null && !pkg.equals(usageStats.mPackageName)) {
+                continue;
+            }
             pw.printPair("package", usageStats.mPackageName);
             if (usageStats.mChooserCounts != null) {
                 final int chooserCountSize = usageStats.mChooserCounts.size();
@@ -555,19 +561,22 @@
         }
         pw.decreaseIndent();
 
-        pw.println("configurations");
-        pw.increaseIndent();
-        final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
-        final int configCount = configStats.size();
-        for (int i = 0; i < configCount; i++) {
-            final ConfigurationStats config = configStats.valueAt(i);
-            pw.printPair("config", Configuration.resourceQualifierString(config.mConfiguration));
-            pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
-            pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
-            pw.printPair("count", config.mActivationCount);
-            pw.println();
+        if (pkg == null) {
+            pw.println("configurations");
+            pw.increaseIndent();
+            final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
+            final int configCount = configStats.size();
+            for (int i = 0; i < configCount; i++) {
+                final ConfigurationStats config = configStats.valueAt(i);
+                pw.printPair("config", Configuration.resourceQualifierString(
+                        config.mConfiguration));
+                pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
+                pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
+                pw.printPair("count", config.mActivationCount);
+                pw.println();
+            }
+            pw.decreaseIndent();
         }
-        pw.decreaseIndent();
 
         pw.println("events");
         pw.increaseIndent();
@@ -575,6 +584,9 @@
         final int eventCount = events != null ? events.size() : 0;
         for (int i = 0; i < eventCount; i++) {
             final UsageEvents.Event event = events.valueAt(i);
+            if (pkg != null && !pkg.equals(event.mPackage)) {
+                continue;
+            }
             pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
             pw.printPair("type", eventToString(event.mEventType));
             pw.printPair("package", event.mPackage);