/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.commands.pm; import com.android.internal.content.PackageHelper; import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.ContainerEncryptionParams; import android.content.pm.FeatureInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.UserInfo; import android.content.pm.VerificationParams; import android.content.res.AssetManager; import android.content.res.Resources; import android.net.Uri; import android.os.IUserManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.security.InvalidAlgorithmParameterException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.WeakHashMap; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public final class Pm { IPackageManager mPm; IUserManager mUm; private WeakHashMap mResourceCache = new WeakHashMap(); private String[] mArgs; private int mNextArg; private String mCurArgData; private static final String PM_NOT_RUNNING_ERR = "Error: Could not access the Package Manager. Is the system running?"; public static void main(String[] args) { new Pm().run(args); } public void run(String[] args) { boolean validCommand = false; if (args.length < 1) { showUsage(); return; } mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); if (mPm == null) { System.err.println(PM_NOT_RUNNING_ERR); return; } mArgs = args; String op = args[0]; mNextArg = 1; if ("list".equals(op)) { runList(); return; } if ("path".equals(op)) { runPath(); return; } if ("install".equals(op)) { runInstall(); return; } if ("uninstall".equals(op)) { runUninstall(); return; } if ("clear".equals(op)) { runClear(); return; } if ("enable".equals(op)) { runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); return; } if ("disable".equals(op)) { runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); return; } if ("disable-user".equals(op)) { runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); return; } if ("grant".equals(op)) { runGrantRevokePermission(true); return; } if ("revoke".equals(op)) { runGrantRevokePermission(false); return; } if ("set-permission-enforced".equals(op)) { runSetPermissionEnforced(); return; } if ("set-install-location".equals(op)) { runSetInstallLocation(); return; } if ("get-install-location".equals(op)) { runGetInstallLocation(); return; } if ("trim-caches".equals(op)) { runTrimCaches(); return; } if ("create-user".equals(op)) { runCreateUser(); return; } if ("remove-user".equals(op)) { runRemoveUser(); return; } if ("get-max-users".equals(op)) { runGetMaxUsers(); return; } try { if (args.length == 1) { if (args[0].equalsIgnoreCase("-l")) { validCommand = true; runListPackages(false); } else if (args[0].equalsIgnoreCase("-lf")){ validCommand = true; runListPackages(true); } } else if (args.length == 2) { if (args[0].equalsIgnoreCase("-p")) { validCommand = true; displayPackageFilePath(args[1]); } } } finally { if (validCommand == false) { if (op != null) { System.err.println("Error: unknown command '" + op + "'"); } showUsage(); } } } /** * 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 void runList() { String type = nextArg(); if (type == null) { System.err.println("Error: didn't specify type of data to list"); return; } if ("package".equals(type) || "packages".equals(type)) { runListPackages(false); } else if ("permission-groups".equals(type)) { runListPermissionGroups(); } else if ("permissions".equals(type)) { runListPermissions(); } else if ("features".equals(type)) { runListFeatures(); } else if ("libraries".equals(type)) { runListLibraries(); } else if ("instrumentation".equals(type)) { runListInstrumentation(); } else if ("users".equals(type)) { runListUsers(); } else { System.err.println("Error: unknown list type '" + type + "'"); } } /** * Lists all the installed packages. */ private void runListPackages(boolean showApplicationPackage) { int getFlags = 0; boolean listDisabled = false, listEnabled = false; boolean listSystem = false, listThirdParty = false; boolean listInstaller = false; int userId = UserHandle.USER_OWNER; try { String opt; while ((opt=nextOption()) != null) { if (opt.equals("-l")) { // old compat } else if (opt.equals("-lf")) { showApplicationPackage = true; } else if (opt.equals("-f")) { showApplicationPackage = true; } else if (opt.equals("-d")) { listDisabled = true; } else if (opt.equals("-e")) { listEnabled = true; } else if (opt.equals("-s")) { listSystem = true; } else if (opt.equals("-3")) { listThirdParty = true; } else if (opt.equals("-i")) { listInstaller = true; } else if (opt.equals("--user")) { userId = Integer.parseInt(nextArg()); } else if (opt.equals("-u")) { getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES; } else { System.err.println("Error: Unknown option: " + opt); return; } } } catch (RuntimeException ex) { System.err.println("Error: " + ex.toString()); return; } String filter = nextArg(); try { final List packages = getInstalledPackages(mPm, getFlags, userId); int count = packages.size(); for (int p = 0 ; p < count ; p++) { PackageInfo info = packages.get(p); if (filter != null && !info.packageName.contains(filter)) { continue; } final boolean isSystem = (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0; if ((!listDisabled || !info.applicationInfo.enabled) && (!listEnabled || info.applicationInfo.enabled) && (!listSystem || isSystem) && (!listThirdParty || !isSystem)) { System.out.print("package:"); if (showApplicationPackage) { System.out.print(info.applicationInfo.sourceDir); System.out.print("="); } System.out.print(info.packageName); if (listInstaller) { System.out.print(" installer="); System.out.print(mPm.getInstallerPackageName(info.packageName)); } System.out.println(); } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } @SuppressWarnings("unchecked") private List getInstalledPackages(IPackageManager pm, int flags, int userId) throws RemoteException { final List packageInfos = new ArrayList(); PackageInfo lastItem = null; ParceledListSlice slice; do { final String lastKey = lastItem != null ? lastItem.packageName : null; slice = pm.getInstalledPackages(flags, lastKey, userId); lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR); } while (!slice.isLastSlice()); return packageInfos; } /** * Lists all of the features supported by the current device. * * pm list features */ private void runListFeatures() { try { List list = new ArrayList(); FeatureInfo[] rawList = mPm.getSystemAvailableFeatures(); for (int i=0; i() { public int compare(FeatureInfo o1, FeatureInfo o2) { if (o1.name == o2.name) return 0; if (o1.name == null) return -1; if (o2.name == null) return 1; return o1.name.compareTo(o2.name); } }); int count = (list != null) ? list.size() : 0; for (int p = 0; p < count; p++) { FeatureInfo fi = list.get(p); System.out.print("feature:"); if (fi.name != null) System.out.println(fi.name); else System.out.println("reqGlEsVersion=0x" + Integer.toHexString(fi.reqGlEsVersion)); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } /** * Lists all of the libraries supported by the current device. * * pm list libraries */ private void runListLibraries() { try { List list = new ArrayList(); String[] rawList = mPm.getSystemSharedLibraryNames(); for (int i=0; i() { public int compare(String o1, String o2) { if (o1 == o2) return 0; if (o1 == null) return -1; if (o2 == null) return 1; return o1.compareTo(o2); } }); int count = (list != null) ? list.size() : 0; for (int p = 0; p < count; p++) { String lib = list.get(p); System.out.print("library:"); System.out.println(lib); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } /** * Lists all of the installed instrumentation, or all for a given package * * pm list instrumentation [package] [-f] */ private void runListInstrumentation() { int flags = 0; // flags != 0 is only used to request meta-data boolean showPackage = false; String targetPackage = null; try { String opt; while ((opt=nextArg()) != null) { if (opt.equals("-f")) { showPackage = true; } else if (opt.charAt(0) != '-') { targetPackage = opt; } else { System.err.println("Error: Unknown option: " + opt); return; } } } catch (RuntimeException ex) { System.err.println("Error: " + ex.toString()); return; } try { List list = mPm.queryInstrumentation(targetPackage, flags); // Sort by target package Collections.sort(list, new Comparator() { public int compare(InstrumentationInfo o1, InstrumentationInfo o2) { return o1.targetPackage.compareTo(o2.targetPackage); } }); int count = (list != null) ? list.size() : 0; for (int p = 0; p < count; p++) { InstrumentationInfo ii = list.get(p); System.out.print("instrumentation:"); if (showPackage) { System.out.print(ii.sourceDir); System.out.print("="); } ComponentName cn = new ComponentName(ii.packageName, ii.name); System.out.print(cn.flattenToShortString()); System.out.print(" (target="); System.out.print(ii.targetPackage); System.out.println(")"); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } /** * Lists all the known permission groups. */ private void runListPermissionGroups() { try { List pgs = mPm.getAllPermissionGroups(0); int count = pgs.size(); for (int p = 0 ; p < count ; p++) { PermissionGroupInfo pgi = pgs.get(p); System.out.print("permission group:"); System.out.println(pgi.name); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) { if (nonLocalized != null) { return nonLocalized.toString(); } if (res != 0) { Resources r = getResources(pii); if (r != null) { return r.getString(res); } } return null; } /** * Lists all the permissions in a group. */ private void runListPermissions() { try { boolean labels = false; boolean groups = false; boolean userOnly = false; boolean summary = false; boolean dangerousOnly = false; String opt; while ((opt=nextOption()) != null) { if (opt.equals("-f")) { labels = true; } else if (opt.equals("-g")) { groups = true; } else if (opt.equals("-s")) { groups = true; labels = true; summary = true; } else if (opt.equals("-u")) { userOnly = true; } else if (opt.equals("-d")) { dangerousOnly = true; } else { System.err.println("Error: Unknown option: " + opt); return; } } String grp = nextOption(); ArrayList groupList = new ArrayList(); if (groups) { List infos = mPm.getAllPermissionGroups(0); for (int i=0; i groupList, boolean groups, boolean labels, boolean summary, int startProtectionLevel, int endProtectionLevel) throws RemoteException { for (int i=0; i 0) System.out.println(""); if (groupName != null) { PermissionGroupInfo pgi = mPm.getPermissionGroupInfo( groupName, 0); if (summary) { Resources res = getResources(pgi); if (res != null) { System.out.print(loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel) + ": "); } else { System.out.print(pgi.name + ": "); } } else { System.out.println((labels ? "+ " : "") + "group:" + pgi.name); if (labels) { System.out.println(" package:" + pgi.packageName); Resources res = getResources(pgi); if (res != null) { System.out.println(" label:" + loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel)); System.out.println(" description:" + loadText(pgi, pgi.descriptionRes, pgi.nonLocalizedDescription)); } } } } else { System.out.println(((labels && !summary) ? "+ " : "") + "ungrouped:"); } prefix = " "; } List ps = mPm.queryPermissionsByGroup( groupList.get(i), 0); int count = ps.size(); boolean first = true; for (int p = 0 ; p < count ; p++) { PermissionInfo pi = ps.get(p); if (groups && groupName == null && pi.group != null) { continue; } final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; if (base < startProtectionLevel || base > endProtectionLevel) { continue; } if (summary) { if (first) { first = false; } else { System.out.print(", "); } Resources res = getResources(pi); if (res != null) { System.out.print(loadText(pi, pi.labelRes, pi.nonLocalizedLabel)); } else { System.out.print(pi.name); } } else { System.out.println(prefix + (labels ? "+ " : "") + "permission:" + pi.name); if (labels) { System.out.println(prefix + " package:" + pi.packageName); Resources res = getResources(pi); if (res != null) { System.out.println(prefix + " label:" + loadText(pi, pi.labelRes, pi.nonLocalizedLabel)); System.out.println(prefix + " description:" + loadText(pi, pi.descriptionRes, pi.nonLocalizedDescription)); } System.out.println(prefix + " protectionLevel:" + PermissionInfo.protectionToString(pi.protectionLevel)); } } } if (summary) { System.out.println(""); } } } private void runPath() { String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package specified"); return; } displayPackageFilePath(pkg); } class PackageInstallObserver extends IPackageInstallObserver.Stub { boolean finished; int result; public void packageInstalled(String name, int status) { synchronized( this) { finished = true; result = status; notifyAll(); } } } /** * Converts a failure code into a string by using reflection to find a matching constant * in PackageManager. */ private String installFailureToString(int result) { Field[] fields = PackageManager.class.getFields(); for (Field f: fields) { if (f.getType() == int.class) { int modifiers = f.getModifiers(); // only look at public final static fields. if (((modifiers & Modifier.FINAL) != 0) && ((modifiers & Modifier.PUBLIC) != 0) && ((modifiers & Modifier.STATIC) != 0)) { String fieldName = f.getName(); if (fieldName.startsWith("INSTALL_FAILED_") || fieldName.startsWith("INSTALL_PARSE_FAILED_")) { // get the int value and compare it to result. try { if (result == f.getInt(null)) { return fieldName; } } catch (IllegalAccessException e) { // this shouldn't happen since we only look for public static fields. } } } } } // couldn't find a matching constant? return the value return Integer.toString(result); } private void runSetInstallLocation() { int loc; String arg = nextArg(); if (arg == null) { System.err.println("Error: no install location specified."); return; } try { loc = Integer.parseInt(arg); } catch (NumberFormatException e) { System.err.println("Error: install location has to be a number."); return; } try { if (!mPm.setInstallLocation(loc)) { System.err.println("Error: install location has to be a number."); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } private void 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 + "]"); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } private void runInstall() { int installFlags = PackageManager.INSTALL_ALL_USERS; String installerPackageName = null; String opt; String algo = null; byte[] iv = null; byte[] key = null; String macAlgo = null; byte[] macKey = null; byte[] tag = null; String originatingUriString = null; String referrer = null; while ((opt=nextOption()) != null) { if (opt.equals("-l")) { installFlags |= PackageManager.INSTALL_FORWARD_LOCK; } else if (opt.equals("-r")) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; } else if (opt.equals("-i")) { installerPackageName = nextOptionData(); if (installerPackageName == null) { System.err.println("Error: no value specified for -i"); return; } } else if (opt.equals("-t")) { installFlags |= PackageManager.INSTALL_ALLOW_TEST; } else if (opt.equals("-s")) { // Override if -s option is specified. installFlags |= PackageManager.INSTALL_EXTERNAL; } else if (opt.equals("-f")) { // Override if -s option is specified. installFlags |= PackageManager.INSTALL_INTERNAL; } else if (opt.equals("-d")) { installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; } else if (opt.equals("--algo")) { algo = nextOptionData(); if (algo == null) { System.err.println("Error: must supply argument for --algo"); return; } } else if (opt.equals("--iv")) { iv = hexToBytes(nextOptionData()); if (iv == null) { System.err.println("Error: must supply argument for --iv"); return; } } else if (opt.equals("--key")) { key = hexToBytes(nextOptionData()); if (key == null) { System.err.println("Error: must supply argument for --key"); return; } } else if (opt.equals("--macalgo")) { macAlgo = nextOptionData(); if (macAlgo == null) { System.err.println("Error: must supply argument for --macalgo"); return; } } else if (opt.equals("--mackey")) { macKey = hexToBytes(nextOptionData()); if (macKey == null) { System.err.println("Error: must supply argument for --mackey"); return; } } else if (opt.equals("--tag")) { tag = hexToBytes(nextOptionData()); if (tag == null) { System.err.println("Error: must supply argument for --tag"); return; } } else if (opt.equals("--originating-uri")) { originatingUriString = nextOptionData(); if (originatingUriString == null) { System.err.println("Error: must supply argument for --originating-uri"); return; } } else if (opt.equals("--referrer")) { referrer = nextOptionData(); if (referrer == null) { System.err.println("Error: must supply argument for --referrer"); return; } } else { System.err.println("Error: Unknown option: " + opt); return; } } final ContainerEncryptionParams encryptionParams; if (algo != null || iv != null || key != null || macAlgo != null || macKey != null || tag != null) { if (algo == null || iv == null || key == null) { System.err.println("Error: all of --algo, --iv, and --key must be specified"); return; } if (macAlgo != null || macKey != null || tag != null) { if (macAlgo == null || macKey == null || tag == null) { System.err.println("Error: all of --macalgo, --mackey, and --tag must " + "be specified"); return; } } try { final SecretKey encKey = new SecretKeySpec(key, "RAW"); final SecretKey macSecretKey; if (macKey == null || macKey.length == 0) { macSecretKey = null; } else { macSecretKey = new SecretKeySpec(macKey, "RAW"); } encryptionParams = new ContainerEncryptionParams(algo, new IvParameterSpec(iv), encKey, macAlgo, null, macSecretKey, tag, -1, -1, -1); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); return; } } else { encryptionParams = null; } final Uri apkURI; final Uri verificationURI; final Uri originatingURI; final Uri referrerURI; if (originatingUriString != null) { originatingURI = Uri.parse(originatingUriString); } else { originatingURI = null; } if (referrer != null) { referrerURI = Uri.parse(referrer); } else { referrerURI = null; } // Populate apkURI, must be present final String apkFilePath = nextArg(); System.err.println("\tpkg: " + apkFilePath); if (apkFilePath != null) { apkURI = Uri.fromFile(new File(apkFilePath)); } else { System.err.println("Error: no package specified"); return; } // Populate verificationURI, optionally present final String verificationFilePath = nextArg(); if (verificationFilePath != null) { System.err.println("\tver: " + verificationFilePath); verificationURI = Uri.fromFile(new File(verificationFilePath)); } else { verificationURI = null; } PackageInstallObserver obs = new PackageInstallObserver(); try { VerificationParams verificationParams = new VerificationParams(verificationURI, originatingURI, referrerURI, VerificationParams.NO_UID, null); mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags, installerPackageName, verificationParams, encryptionParams); synchronized (obs) { while (!obs.finished) { try { obs.wait(); } catch (InterruptedException e) { } } if (obs.result == PackageManager.INSTALL_SUCCEEDED) { System.out.println("Success"); } else { System.err.println("Failure [" + installFailureToString(obs.result) + "]"); } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } /** * Convert a string containing hex-encoded bytes to a byte array. * * @param input String containing hex-encoded bytes * @return input as an array of bytes */ private byte[] hexToBytes(String input) { if (input == null) { return null; } final int inputLength = input.length(); if ((inputLength % 2) != 0) { System.err.print("Invalid length; must be multiple of 2"); return null; } final int byteLength = inputLength / 2; final byte[] output = new byte[byteLength]; int inputIndex = 0; int byteIndex = 0; while (inputIndex < inputLength) { output[byteIndex++] = (byte) Integer.parseInt( input.substring(inputIndex, inputIndex + 2), 16); inputIndex += 2; } return output; } public void runCreateUser() { String name; String arg = nextArg(); if (arg == null) { System.err.println("Error: no user name specified."); return; } name = arg; try { final UserInfo info = mUm.createUser(name, 0); if (info != null) { System.out.println("Success: created user id " + info.id); } else { System.err.println("Error: couldn't create User."); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } public void runRemoveUser() { int userId; String arg = nextArg(); if (arg == null) { System.err.println("Error: no user id specified."); return; } try { userId = Integer.parseInt(arg); } catch (NumberFormatException e) { System.err.println("Error: user id '" + arg + "' is not a number."); return; } try { if (mUm.removeUser(userId)) { System.out.println("Success: removed user"); } else { System.err.println("Error: couldn't remove user id " + userId); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } public void runListUsers() { try { List users = mUm.getUsers(false); if (users == null) { System.err.println("Error: couldn't get users"); } else { System.out.println("Users:"); for (int i = 0; i < users.size(); i++) { System.out.println("\t" + users.get(i).toString()); } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } public void runGetMaxUsers() { System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers()); } class PackageDeleteObserver extends IPackageDeleteObserver.Stub { boolean finished; boolean result; public void packageDeleted(String packageName, int returnCode) { synchronized (this) { finished = true; result = returnCode == PackageManager.DELETE_SUCCEEDED; notifyAll(); } } } private void runUninstall() { int unInstallFlags = PackageManager.DELETE_ALL_USERS; String opt; while ((opt=nextOption()) != null) { if (opt.equals("-k")) { unInstallFlags |= PackageManager.DELETE_KEEP_DATA; } else { System.err.println("Error: Unknown option: " + opt); return; } } String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package specified"); showUsage(); return; } boolean result = deletePackage(pkg, unInstallFlags); if (result) { System.out.println("Success"); } else { System.out.println("Failure"); } } private boolean deletePackage(String pkg, int unInstallFlags) { PackageDeleteObserver obs = new PackageDeleteObserver(); try { mPm.deletePackage(pkg, obs, unInstallFlags); synchronized (obs) { while (!obs.finished) { try { obs.wait(); } catch (InterruptedException e) { } } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } return obs.result; } 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 void runClear() { int userId = 0; 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"); showUsage(); return; } else { userId = Integer.parseInt(optionData); } } String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package specified"); showUsage(); return; } ClearDataObserver obs = new ClearDataObserver(); try { if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId)) { System.err.println("Failed"); } synchronized (obs) { while (!obs.finished) { try { obs.wait(); } catch (InterruptedException e) { } } } if (obs.result) { System.err.println("Success"); } else { System.err.println("Failed"); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } 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"; } return "unknown"; } private static boolean isNumber(String s) { try { Integer.parseInt(s); } catch (NumberFormatException nfe) { return false; } return true; } private void runSetEnabledSetting(int state) { int userId = 0; 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"); showUsage(); return; } else { userId = Integer.parseInt(optionData); } } String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package or component specified"); showUsage(); return; } ComponentName cn = ComponentName.unflattenFromString(pkg); if (cn == null) { try { mPm.setApplicationEnabledSetting(pkg, state, 0, userId); System.err.println("Package " + pkg + " new state: " + enabledSettingToString( mPm.getApplicationEnabledSetting(pkg, userId))); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } else { try { mPm.setComponentEnabledSetting(cn, state, 0, userId); System.err.println("Component " + cn.toShortString() + " new state: " + enabledSettingToString( mPm.getComponentEnabledSetting(cn, userId))); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } } private void runGrantRevokePermission(boolean grant) { String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package specified"); showUsage(); return; } String perm = nextArg(); if (perm == null) { System.err.println("Error: no permission specified"); showUsage(); return; } try { if (grant) { mPm.grantPermission(pkg, perm); } else { mPm.revokePermission(pkg, perm); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } catch (IllegalArgumentException e) { System.err.println("Bad argument: " + e.toString()); showUsage(); } catch (SecurityException e) { System.err.println("Operation not allowed: " + e.toString()); } } private void runSetPermissionEnforced() { final String permission = nextArg(); if (permission == null) { System.err.println("Error: no permission specified"); showUsage(); return; } final String enforcedRaw = nextArg(); if (enforcedRaw == null) { System.err.println("Error: no enforcement specified"); showUsage(); return; } final boolean enforced = Boolean.parseBoolean(enforcedRaw); try { mPm.setPermissionEnforced(permission, enforced); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } catch (IllegalArgumentException e) { System.err.println("Bad argument: " + e.toString()); showUsage(); } catch (SecurityException e) { System.err.println("Operation not allowed: " + e.toString()); } } static class ClearCacheObserver 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 void runTrimCaches() { String size = nextArg(); if (size == null) { System.err.println("Error: no size specified"); showUsage(); return; } int len = size.length(); long multiplier = 1; if (len > 1) { char c = size.charAt(len-1); 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); showUsage(); return; } 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); showUsage(); return; } ClearDataObserver obs = new ClearDataObserver(); try { mPm.freeStorageAndNotify(sizeVal, obs); synchronized (obs) { while (!obs.finished) { try { obs.wait(); } catch (InterruptedException e) { } } } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } catch (IllegalArgumentException e) { System.err.println("Bad argument: " + e.toString()); showUsage(); } catch (SecurityException e) { System.err.println("Operation not allowed: " + e.toString()); } } /** * Displays the package file for a package. * @param pckg */ private void displayPackageFilePath(String pckg) { try { PackageInfo info = mPm.getPackageInfo(pckg, 0, 0); if (info != null && info.applicationInfo != null) { System.out.print("package:"); System.out.println(info.applicationInfo.sourceDir); } } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } private Resources getResources(PackageItemInfo pii) { Resources res = mResourceCache.get(pii.packageName); if (res != null) return res; try { ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0, 0); AssetManager am = new AssetManager(); am.addAssetPath(ai.publicSourceDir); res = new Resources(am, null, null); mResourceCache.put(pii.packageName, res); return res; } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); return null; } } private String nextOption() { if (mNextArg >= mArgs.length) { return null; } String arg = mArgs[mNextArg]; if (!arg.startsWith("-")) { return null; } mNextArg++; if (arg.equals("--")) { return null; } if (arg.length() > 1 && arg.charAt(1) != '-') { if (arg.length() > 2) { mCurArgData = arg.substring(2); return arg.substring(0, 2); } else { mCurArgData = null; return arg; } } mCurArgData = null; return arg; } private String nextOptionData() { if (mCurArgData != null) { return mCurArgData; } if (mNextArg >= mArgs.length) { return null; } String data = mArgs[mNextArg]; mNextArg++; return data; } private String nextArg() { if (mNextArg >= mArgs.length) { return null; } String arg = mArgs[mNextArg]; mNextArg++; return arg; } private static void showUsage() { System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]"); System.err.println(" pm list permission-groups"); System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); System.err.println(" pm list features"); System.err.println(" pm list libraries"); System.err.println(" pm list users"); System.err.println(" pm path PACKAGE"); System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]"); System.err.println(" [--algo --key --iv ]"); System.err.println(" [--originating-uri ] [--referrer ] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); System.err.println(" pm clear [--user USER_ID] PACKAGE"); System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm grant PACKAGE PERMISSION"); System.err.println(" pm revoke PACKAGE PERMISSION"); System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]"); System.err.println(" pm get-install-location"); System.err.println(" pm set-permission-enforced PERMISSION [true|false]"); System.err.println(" pm trim-caches DESIRED_FREE_SPACE"); System.err.println(" pm create-user USER_NAME"); System.err.println(" pm remove-user USER_ID"); System.err.println(" pm get-max-users"); System.err.println(""); System.err.println("pm list packages: prints all packages, optionally only"); System.err.println(" those whose package name contains the text in FILTER. Options:"); System.err.println(" -f: see their associated file."); System.err.println(" -d: filter to only show disbled packages."); System.err.println(" -e: filter to only show enabled packages."); System.err.println(" -s: filter to only show system packages."); System.err.println(" -3: filter to only show third party packages."); System.err.println(" -i: see the installer for the packages."); System.err.println(" -u: also include uninstalled packages."); System.err.println(""); System.err.println("pm list permission-groups: prints all known permission groups."); System.err.println(""); System.err.println("pm list permissions: prints all known permissions, optionally only"); System.err.println(" those in GROUP. Options:"); System.err.println(" -g: organize by group."); System.err.println(" -f: print all information."); System.err.println(" -s: short summary."); System.err.println(" -d: only list dangerous permissions."); System.err.println(" -u: list only the permissions users will see."); System.err.println(""); System.err.println("pm list instrumentation: use to list all test packages; optionally"); System.err.println(" supply to list the test packages for a particular"); System.err.println(" application. Options:"); System.err.println(" -f: list the .apk file for the test package."); System.err.println(""); System.err.println("pm list features: prints all features of the system."); System.err.println(""); System.err.println("pm list users: prints all users on the system."); System.err.println(""); System.err.println("pm path: print the path to the .apk of the given PACKAGE."); System.err.println(""); System.err.println("pm install: installs a package to the system. Options:"); System.err.println(" -l: install the package with FORWARD_LOCK."); System.err.println(" -r: reinstall an exisiting app, keeping its data."); System.err.println(" -t: allow test .apks to be installed."); System.err.println(" -i: specify the installer package name."); System.err.println(" -s: install package on sdcard."); System.err.println(" -f: install package on internal flash."); System.err.println(" -d: allow version code downgrade."); System.err.println(""); System.err.println("pm uninstall: removes a package from the system. Options:"); System.err.println(" -k: keep the data and cache directories around after package removal."); System.err.println(""); System.err.println("pm clear: deletes all data associated with a package."); System.err.println(""); System.err.println("pm enable, disable, disable-user: these commands change the enabled state"); System.err.println(" of a given package or component (written as \"package/class\")."); System.err.println(""); System.err.println("pm grant, revoke: these commands either grant or revoke permissions"); System.err.println(" to applications. Only optional permissions the application has"); System.err.println(" declared can be granted or revoked."); System.err.println(""); System.err.println("pm get-install-location: returns the current install location."); System.err.println(" 0 [auto]: Let system decide the best location"); System.err.println(" 1 [internal]: Install on internal device storage"); System.err.println(" 2 [external]: Install on external media"); System.err.println(""); System.err.println("pm set-install-location: changes the default install location."); System.err.println(" NOTE: this is only intended for debugging; using this can cause"); System.err.println(" applications to break and other undersireable behavior."); System.err.println(" 0 [auto]: Let system decide the best location"); System.err.println(" 1 [internal]: Install on internal device storage"); System.err.println(" 2 [external]: Install on external media"); System.err.println(""); System.err.println("pm trim-caches: trim cache files to reach the given free space."); System.err.println(""); System.err.println("pm create-user: create a new user with the given USER_NAME,"); System.err.println(" printing the new user identifier of the user."); System.err.println(""); System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,"); System.err.println(" deleting all data associated with that user"); } }