auto import from //depot/cupcake/@135843
diff --git a/cmds/pm/Android.mk b/cmds/pm/Android.mk
new file mode 100644
index 0000000..7911d62
--- /dev/null
+++ b/cmds/pm/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2007 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := pm
+include $(BUILD_JAVA_LIBRARY)
+
+
+include $(CLEAR_VARS)
+ALL_PREBUILT += $(TARGET_OUT)/bin/pm
+$(TARGET_OUT)/bin/pm : $(LOCAL_PATH)/pm | $(ACP)
+	$(transform-prebuilt-to-target)
+
diff --git a/cmds/pm/MODULE_LICENSE_APACHE2 b/cmds/pm/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/pm/MODULE_LICENSE_APACHE2
diff --git a/cmds/pm/NOTICE b/cmds/pm/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/pm/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/cmds/pm/pm b/cmds/pm/pm
new file mode 100755
index 0000000..8183838
--- /dev/null
+++ b/cmds/pm/pm
@@ -0,0 +1,7 @@
+# Script to start "pm" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/pm.jar
+exec app_process $base/bin com.android.commands.pm.Pm "$@"
+
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
new file mode 100644
index 0000000..c2d8da5
--- /dev/null
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -0,0 +1,845 @@
+/*
+ * 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 android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+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.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.WeakHashMap;
+
+public final class Pm {
+    IPackageManager mPm;
+    
+    private WeakHashMap<String, Resources> mResourceCache
+            = new WeakHashMap<String, Resources>();
+    
+    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;
+        }
+
+        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 ("enable".equals(op)) {
+            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+            return;
+        }
+        
+        if ("disable".equals(op)) {
+            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+            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 instrumentation
+     */
+    private void runList() {
+        String type = nextArg();
+        if (type == null) {
+            System.err.println("Error: didn't specify type of data to list");
+            showUsage();
+            return;
+        }
+        if ("package".equals(type) || "packages".equals(type)) {
+            runListPackages(false);
+        } else if ("permission-groups".equals(type)) {
+            runListPermissionGroups();
+        } else if ("permissions".equals(type)) {
+            runListPermissions();
+        } else if ("instrumentation".equals(type)) {
+            runListInstrumentation();
+        } else {
+            System.err.println("Error: unknown list type '" + type + "'");
+            showUsage();
+        }
+    }
+    
+    /**
+     * Lists all the installed packages.
+     */
+    private void runListPackages(boolean showApplicationPackage) {
+        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 {
+                    System.err.println("Error: Unknown option: " + opt);
+                    showUsage();
+                    return;
+                }
+            }
+        } catch (RuntimeException ex) {
+            System.err.println("Error: " + ex.toString());
+            showUsage();
+            return;
+        }
+        
+        try {
+            List<PackageInfo> packages = mPm.getInstalledPackages(0 /* all */);
+            
+            int count = packages.size();
+            for (int p = 0 ; p < count ; p++) {
+                PackageInfo info = packages.get(p);
+                System.out.print("package:");
+                if (showApplicationPackage) {
+                    System.out.print(info.applicationInfo.sourceDir);
+                    System.out.print("=");
+                }
+                System.out.println(info.packageName);
+            }
+        } 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);
+                    showUsage();
+                    return;
+                }
+            }
+        } catch (RuntimeException ex) {
+            System.err.println("Error: " + ex.toString());
+            showUsage();
+            return;
+        }
+
+        try {
+            List<InstrumentationInfo> list = mPm.queryInstrumentation(targetPackage, flags);
+
+            // Sort by target package
+            Collections.sort(list, new Comparator<InstrumentationInfo>() {
+                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<PermissionGroupInfo> 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();
+        }
+        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);
+                    showUsage();
+                    return;
+                }
+            }
+            
+            String grp = nextOption();
+            ArrayList<String> groupList = new ArrayList<String>();
+            if (groups) {
+                List<PermissionGroupInfo> infos =
+                        mPm.getAllPermissionGroups(0);
+                for (int i=0; i<infos.size(); i++) {
+                    groupList.add(infos.get(i).name);
+                }
+                groupList.add(null);
+            } else {
+                groupList.add(grp);
+            }
+            
+            if (dangerousOnly) {
+                System.out.println("Dangerous Permissions:");
+                System.out.println("");
+                doListPermissions(groupList, groups, labels, summary,
+                        PermissionInfo.PROTECTION_DANGEROUS,
+                        PermissionInfo.PROTECTION_DANGEROUS);
+                if (userOnly) {
+                    System.out.println("Normal Permissions:");
+                    System.out.println("");
+                    doListPermissions(groupList, groups, labels, summary,
+                            PermissionInfo.PROTECTION_NORMAL,
+                            PermissionInfo.PROTECTION_NORMAL);
+                }
+            } else if (userOnly) {
+                System.out.println("Dangerous and Normal Permissions:");
+                System.out.println("");
+                doListPermissions(groupList, groups, labels, summary,
+                        PermissionInfo.PROTECTION_NORMAL,
+                        PermissionInfo.PROTECTION_DANGEROUS);
+            } else {
+                System.out.println("All Permissions:");
+                System.out.println("");
+                doListPermissions(groupList, groups, labels, summary,
+                        -10000, 10000);
+            }
+        } catch (RemoteException e) {
+            System.err.println(e.toString());
+            System.err.println(PM_NOT_RUNNING_ERR);
+        }
+    }
+    
+    private void doListPermissions(ArrayList<String> groupList,
+            boolean groups, boolean labels, boolean summary,
+            int startProtectionLevel, int endProtectionLevel)
+            throws RemoteException {
+        for (int i=0; i<groupList.size(); i++) {
+            String groupName = groupList.get(i);
+            String prefix = "";
+            if (groups) {
+                if (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<PermissionInfo> 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;
+                }
+                if (pi.protectionLevel < startProtectionLevel
+                        || pi.protectionLevel > 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));
+                        }
+                        String protLevel = "unknown";
+                        switch(pi.protectionLevel) {
+                            case PermissionInfo.PROTECTION_DANGEROUS:
+                                protLevel = "dangerous";
+                                break;
+                            case PermissionInfo.PROTECTION_NORMAL:
+                                protLevel = "normal";
+                                break;
+                            case PermissionInfo.PROTECTION_SIGNATURE:
+                                protLevel = "signature";
+                                break;
+                            case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:
+                                protLevel = "signatureOrSystem";
+                                break;
+                        }
+                        System.out.println(prefix + "  protectionLevel:" + protLevel);
+                    }
+                }
+            }
+            
+            if (summary) {
+                System.out.println("");
+            }
+        }
+    }
+    
+    private void runPath() {
+        String pkg = nextArg();
+        if (pkg == null) {
+            System.err.println("Error: no package specified");
+            showUsage();
+            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();
+            }
+        }
+    }
+    
+    private String installFailureToString(int result) {
+        String s;
+        switch (result) {
+        case PackageManager.INSTALL_FAILED_ALREADY_EXISTS:
+            s = "INSTALL_FAILED_ALREADY_EXISTS";
+            break;
+        case PackageManager.INSTALL_FAILED_INVALID_APK:
+            s = "INSTALL_FAILED_INVALID_APK";
+            break;
+        case PackageManager.INSTALL_FAILED_INVALID_URI:
+            s = "INSTALL_FAILED_INVALID_URI";
+            break;
+        case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE:
+            s = "INSTALL_FAILED_INSUFFICIENT_STORAGE";
+            break;
+        case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE:
+            s = "INSTALL_FAILED_DUPLICATE_PACKAGE";
+            break;
+        case PackageManager.INSTALL_FAILED_NO_SHARED_USER:
+            s = "INSTALL_FAILED_NO_SHARED_USER";
+            break;
+        case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE:
+            s = "INSTALL_FAILED_UPDATE_INCOMPATIBLE";
+            break;
+        case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE:
+            s = "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE";
+            break;
+        case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY:
+            s = "INSTALL_FAILED_MISSING_SHARED_LIBRARY";
+            break;
+        case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE:
+            s = "INSTALL_FAILED_REPLACE_COULDNT_DELETE";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_NOT_APK:
+            s = "INSTALL_PARSE_FAILED_NOT_APK";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST:
+            s = "INSTALL_PARSE_FAILED_BAD_MANIFEST";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION:
+            s = "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES:
+            s = "INSTALL_PARSE_FAILED_NO_CERTIFICATES";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES:
+            s = "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING:
+            s = "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME:
+            s = "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID:
+            s = "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED:
+            s = "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED";
+            break;
+        case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY:
+            s = "INSTALL_PARSE_FAILED_MANIFEST_EMPTY";
+            break;
+        case PackageManager.INSTALL_FAILED_OLDER_SDK:
+            s = "INSTALL_FAILED_OLDER_SDK";
+            break;
+        default:
+            s = Integer.toString(result);
+        break;
+        }
+        return s;
+    }
+    
+    private void runInstall() {
+        int installFlags = 0;
+
+        String opt;
+        while ((opt=nextOption()) != null) {
+            if (opt.equals("-l")) {
+                installFlags |= PackageManager.FORWARD_LOCK_PACKAGE;
+            } else if (opt.equals("-r")) {
+                installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
+            } else {
+                System.err.println("Error: Unknown option: " + opt);
+                showUsage();
+                return;
+            }
+        }
+
+        String apkFilePath = nextArg();
+        System.err.println("\tpkg: " + apkFilePath);
+        if (apkFilePath == null) {
+            System.err.println("Error: no package specified");
+            showUsage();
+            return;
+        }
+
+        PackageInstallObserver obs = new PackageInstallObserver();
+        try {
+            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags);
+            
+            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);
+        }
+    }
+    
+    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
+        boolean finished;
+        boolean result;
+        
+        public void packageDeleted(boolean succeeded) {
+            synchronized (this) {
+                finished = true;
+                result = succeeded;
+                notifyAll();
+            }
+        }
+    }
+    
+    private void runUninstall() {
+        int unInstallFlags = 0;
+
+        String opt = nextOption();
+        if (opt != null && opt.equals("-k")) {
+            unInstallFlags = PackageManager.DONT_DELETE_DATA;
+        }
+
+        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;
+    }
+
+    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";
+        }
+        return "unknown";
+    }
+    
+    private void runSetEnabledSetting(int state) {
+        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);
+                System.err.println("Package " + pkg + " new state: "
+                        + enabledSettingToString(
+                                mPm.getApplicationEnabledSetting(pkg)));
+            } catch (RemoteException e) {
+                System.err.println(e.toString());
+                System.err.println(PM_NOT_RUNNING_ERR);
+            }
+        } else {
+            try {
+                mPm.setComponentEnabledSetting(cn, state, 0);
+                System.err.println("Component " + cn.toShortString() + " new state: "
+                        + enabledSettingToString(
+                                mPm.getComponentEnabledSetting(cn)));
+            } catch (RemoteException e) {
+                System.err.println(e.toString());
+                System.err.println(PM_NOT_RUNNING_ERR);
+            }
+        }
+    }
+
+    /**
+     * Displays the package file for a package.
+     * @param pckg
+     */
+    private void displayPackageFilePath(String pckg) {
+        try {
+            PackageInfo info = mPm.getPackageInfo(pckg, 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);
+            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|path|install|uninstall]");
+        System.err.println("       pm list packages [-f]");
+        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 path PACKAGE");
+        System.err.println("       pm install [-l] [-r] PATH");
+        System.err.println("       pm uninstall [-k] PACKAGE");
+        System.err.println("       pm enable PACKAGE_OR_COMPONENT");
+        System.err.println("       pm disable PACKAGE_OR_COMPONENT");
+        System.err.println("");
+        System.err.println("The list packages command prints all packages.  Use");
+        System.err.println("the -f option to see their associated file.");
+        System.err.println("");
+        System.err.println("The list permission-groups command prints all known");
+        System.err.println("permission groups.");
+        System.err.println("");
+        System.err.println("The list permissions command prints all known");
+        System.err.println("permissions, optionally only those in GROUP.  Use");
+        System.err.println("the -g option to organize by group.  Use");
+        System.err.println("the -f option to print all information.  Use");
+        System.err.println("the -s option for a short summary.  Use");
+        System.err.println("the -d option to only list dangerous permissions.  Use");
+        System.err.println("the -u option to list only the permissions users will see.");
+        System.err.println("");
+        System.err.println("The list instrumentation command prints all instrumentations,");
+        System.err.println("or only those that target a specified package.  Use the -f option");
+        System.err.println("to see their associated file.");
+        System.err.println("");
+        System.err.println("The path command prints the path to the .apk of a package.");
+        System.err.println("");
+        System.err.println("The install command installs a package to the system.  Use");
+        System.err.println("the -l option to install the package with FORWARD_LOCK. Use");
+        System.err.println("the -r option to reinstall an exisiting app, keeping its data.");
+        System.err.println("");
+        System.err.println("The uninstall command removes a package from the system. Use");
+        System.err.println("the -k option to keep the data and cache directories around");
+        System.err.println("after the package removal.");
+        System.err.println("");
+        System.err.println("The enable and disable commands change the enabled state of");
+        System.err.println("a given package or component (written as \"package/class\").");
+    }
+}