Pm.java revision cbfd23ee6f14445c3e17c5169abbc80c216fa137
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.commands.pm;
18
19import android.app.ActivityManager;
20import android.app.ActivityManagerNative;
21import android.content.ComponentName;
22import android.content.pm.ApplicationInfo;
23import android.content.pm.ContainerEncryptionParams;
24import android.content.pm.FeatureInfo;
25import android.content.pm.IPackageDataObserver;
26import android.content.pm.IPackageDeleteObserver;
27import android.content.pm.IPackageInstallObserver;
28import android.content.pm.IPackageManager;
29import android.content.pm.InstrumentationInfo;
30import android.content.pm.PackageInfo;
31import android.content.pm.PackageItemInfo;
32import android.content.pm.PackageManager;
33import android.content.pm.ParceledListSlice;
34import android.content.pm.PermissionGroupInfo;
35import android.content.pm.PermissionInfo;
36import android.content.pm.UserInfo;
37import android.content.pm.VerificationParams;
38import android.content.res.AssetManager;
39import android.content.res.Resources;
40import android.net.Uri;
41import android.os.IUserManager;
42import android.os.RemoteException;
43import android.os.ServiceManager;
44import android.os.UserHandle;
45import android.os.UserManager;
46
47import java.io.File;
48import java.io.FileDescriptor;
49import java.lang.reflect.Field;
50import java.lang.reflect.Modifier;
51import java.security.InvalidAlgorithmParameterException;
52import java.util.ArrayList;
53import java.util.Collections;
54import java.util.Comparator;
55import java.util.List;
56import java.util.WeakHashMap;
57
58import javax.crypto.SecretKey;
59import javax.crypto.spec.IvParameterSpec;
60import javax.crypto.spec.SecretKeySpec;
61
62import com.android.internal.content.PackageHelper;
63
64public final class Pm {
65    IPackageManager mPm;
66    IUserManager mUm;
67
68    private WeakHashMap<String, Resources> mResourceCache
69            = new WeakHashMap<String, Resources>();
70
71    private String[] mArgs;
72    private int mNextArg;
73    private String mCurArgData;
74
75    private static final String PM_NOT_RUNNING_ERR =
76        "Error: Could not access the Package Manager.  Is the system running?";
77
78    public static void main(String[] args) {
79        new Pm().run(args);
80    }
81
82    public void run(String[] args) {
83        boolean validCommand = false;
84        if (args.length < 1) {
85            showUsage();
86            return;
87        }
88
89        mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
90        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
91        if (mPm == null) {
92            System.err.println(PM_NOT_RUNNING_ERR);
93            return;
94        }
95
96        mArgs = args;
97        String op = args[0];
98        mNextArg = 1;
99
100        if ("list".equals(op)) {
101            runList();
102            return;
103        }
104
105        if ("path".equals(op)) {
106            runPath();
107            return;
108        }
109
110        if ("dump".equals(op)) {
111            runDump();
112            return;
113        }
114
115        if ("install".equals(op)) {
116            runInstall();
117            return;
118        }
119
120        if ("uninstall".equals(op)) {
121            runUninstall();
122            return;
123        }
124
125        if ("clear".equals(op)) {
126            runClear();
127            return;
128        }
129
130        if ("enable".equals(op)) {
131            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
132            return;
133        }
134
135        if ("disable".equals(op)) {
136            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
137            return;
138        }
139
140        if ("disable-user".equals(op)) {
141            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
142            return;
143        }
144
145        if ("disable-until-used".equals(op)) {
146            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
147            return;
148        }
149
150        if ("grant".equals(op)) {
151            runGrantRevokePermission(true);
152            return;
153        }
154
155        if ("revoke".equals(op)) {
156            runGrantRevokePermission(false);
157            return;
158        }
159
160        if ("set-permission-enforced".equals(op)) {
161            runSetPermissionEnforced();
162            return;
163        }
164
165        if ("set-install-location".equals(op)) {
166            runSetInstallLocation();
167            return;
168        }
169
170        if ("get-install-location".equals(op)) {
171            runGetInstallLocation();
172            return;
173        }
174
175        if ("trim-caches".equals(op)) {
176            runTrimCaches();
177            return;
178        }
179
180        if ("create-user".equals(op)) {
181            runCreateUser();
182            return;
183        }
184
185        if ("remove-user".equals(op)) {
186            runRemoveUser();
187            return;
188        }
189
190        if ("get-max-users".equals(op)) {
191            runGetMaxUsers();
192            return;
193        }
194
195        try {
196            if (args.length == 1) {
197                if (args[0].equalsIgnoreCase("-l")) {
198                    validCommand = true;
199                    runListPackages(false);
200                } else if (args[0].equalsIgnoreCase("-lf")){
201                    validCommand = true;
202                    runListPackages(true);
203                }
204            } else if (args.length == 2) {
205                if (args[0].equalsIgnoreCase("-p")) {
206                    validCommand = true;
207                    displayPackageFilePath(args[1]);
208                }
209            }
210        } finally {
211            if (validCommand == false) {
212                if (op != null) {
213                    System.err.println("Error: unknown command '" + op + "'");
214                }
215                showUsage();
216            }
217        }
218    }
219
220    /**
221     * Execute the list sub-command.
222     *
223     * pm list [package | packages]
224     * pm list permission-groups
225     * pm list permissions
226     * pm list features
227     * pm list libraries
228     * pm list instrumentation
229     */
230    private void runList() {
231        String type = nextArg();
232        if (type == null) {
233            System.err.println("Error: didn't specify type of data to list");
234            return;
235        }
236        if ("package".equals(type) || "packages".equals(type)) {
237            runListPackages(false);
238        } else if ("permission-groups".equals(type)) {
239            runListPermissionGroups();
240        } else if ("permissions".equals(type)) {
241            runListPermissions();
242        } else if ("features".equals(type)) {
243            runListFeatures();
244        } else if ("libraries".equals(type)) {
245            runListLibraries();
246        } else if ("instrumentation".equals(type)) {
247            runListInstrumentation();
248        } else if ("users".equals(type)) {
249            runListUsers();
250        } else {
251            System.err.println("Error: unknown list type '" + type + "'");
252        }
253    }
254
255    /**
256     * Lists all the installed packages.
257     */
258    private void runListPackages(boolean showApplicationPackage) {
259        int getFlags = 0;
260        boolean listDisabled = false, listEnabled = false;
261        boolean listSystem = false, listThirdParty = false;
262        boolean listInstaller = false;
263        int userId = UserHandle.USER_OWNER;
264        try {
265            String opt;
266            while ((opt=nextOption()) != null) {
267                if (opt.equals("-l")) {
268                    // old compat
269                } else if (opt.equals("-lf")) {
270                    showApplicationPackage = true;
271                } else if (opt.equals("-f")) {
272                    showApplicationPackage = true;
273                } else if (opt.equals("-d")) {
274                    listDisabled = true;
275                } else if (opt.equals("-e")) {
276                    listEnabled = true;
277                } else if (opt.equals("-s")) {
278                    listSystem = true;
279                } else if (opt.equals("-3")) {
280                    listThirdParty = true;
281                } else if (opt.equals("-i")) {
282                    listInstaller = true;
283                } else if (opt.equals("--user")) {
284                    userId = Integer.parseInt(nextArg());
285                } else if (opt.equals("-u")) {
286                    getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
287                } else {
288                    System.err.println("Error: Unknown option: " + opt);
289                    return;
290                }
291            }
292        } catch (RuntimeException ex) {
293            System.err.println("Error: " + ex.toString());
294            return;
295        }
296
297        String filter = nextArg();
298
299        try {
300            final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags, userId);
301
302            int count = packages.size();
303            for (int p = 0 ; p < count ; p++) {
304                PackageInfo info = packages.get(p);
305                if (filter != null && !info.packageName.contains(filter)) {
306                    continue;
307                }
308                final boolean isSystem =
309                        (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0;
310                if ((!listDisabled || !info.applicationInfo.enabled) &&
311                        (!listEnabled || info.applicationInfo.enabled) &&
312                        (!listSystem || isSystem) &&
313                        (!listThirdParty || !isSystem)) {
314                    System.out.print("package:");
315                    if (showApplicationPackage) {
316                        System.out.print(info.applicationInfo.sourceDir);
317                        System.out.print("=");
318                    }
319                    System.out.print(info.packageName);
320                    if (listInstaller) {
321                        System.out.print("  installer=");
322                        System.out.print(mPm.getInstallerPackageName(info.packageName));
323                    }
324                    System.out.println();
325                }
326            }
327        } catch (RemoteException e) {
328            System.err.println(e.toString());
329            System.err.println(PM_NOT_RUNNING_ERR);
330        }
331    }
332
333    @SuppressWarnings("unchecked")
334    private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId)
335            throws RemoteException {
336        ParceledListSlice<PackageInfo> slice = pm.getInstalledPackages(flags, userId);
337        return slice.getList();
338    }
339
340    /**
341     * Lists all of the features supported by the current device.
342     *
343     * pm list features
344     */
345    private void runListFeatures() {
346        try {
347            List<FeatureInfo> list = new ArrayList<FeatureInfo>();
348            FeatureInfo[] rawList = mPm.getSystemAvailableFeatures();
349            for (int i=0; i<rawList.length; i++) {
350                list.add(rawList[i]);
351            }
352
353
354            // Sort by name
355            Collections.sort(list, new Comparator<FeatureInfo>() {
356                public int compare(FeatureInfo o1, FeatureInfo o2) {
357                    if (o1.name == o2.name) return 0;
358                    if (o1.name == null) return -1;
359                    if (o2.name == null) return 1;
360                    return o1.name.compareTo(o2.name);
361                }
362            });
363
364            int count = (list != null) ? list.size() : 0;
365            for (int p = 0; p < count; p++) {
366                FeatureInfo fi = list.get(p);
367                System.out.print("feature:");
368                if (fi.name != null) System.out.println(fi.name);
369                else System.out.println("reqGlEsVersion=0x"
370                        + Integer.toHexString(fi.reqGlEsVersion));
371            }
372        } catch (RemoteException e) {
373            System.err.println(e.toString());
374            System.err.println(PM_NOT_RUNNING_ERR);
375        }
376    }
377
378    /**
379     * Lists all of the libraries supported by the current device.
380     *
381     * pm list libraries
382     */
383    private void runListLibraries() {
384        try {
385            List<String> list = new ArrayList<String>();
386            String[] rawList = mPm.getSystemSharedLibraryNames();
387            for (int i=0; i<rawList.length; i++) {
388                list.add(rawList[i]);
389            }
390
391
392            // Sort by name
393            Collections.sort(list, new Comparator<String>() {
394                public int compare(String o1, String o2) {
395                    if (o1 == o2) return 0;
396                    if (o1 == null) return -1;
397                    if (o2 == null) return 1;
398                    return o1.compareTo(o2);
399                }
400            });
401
402            int count = (list != null) ? list.size() : 0;
403            for (int p = 0; p < count; p++) {
404                String lib = list.get(p);
405                System.out.print("library:");
406                System.out.println(lib);
407            }
408        } catch (RemoteException e) {
409            System.err.println(e.toString());
410            System.err.println(PM_NOT_RUNNING_ERR);
411        }
412    }
413
414    /**
415     * Lists all of the installed instrumentation, or all for a given package
416     *
417     * pm list instrumentation [package] [-f]
418     */
419    private void runListInstrumentation() {
420        int flags = 0;      // flags != 0 is only used to request meta-data
421        boolean showPackage = false;
422        String targetPackage = null;
423
424        try {
425            String opt;
426            while ((opt=nextArg()) != null) {
427                if (opt.equals("-f")) {
428                    showPackage = true;
429                } else if (opt.charAt(0) != '-') {
430                    targetPackage = opt;
431                } else {
432                    System.err.println("Error: Unknown option: " + opt);
433                    return;
434                }
435            }
436        } catch (RuntimeException ex) {
437            System.err.println("Error: " + ex.toString());
438            return;
439        }
440
441        try {
442            List<InstrumentationInfo> list = mPm.queryInstrumentation(targetPackage, flags);
443
444            // Sort by target package
445            Collections.sort(list, new Comparator<InstrumentationInfo>() {
446                public int compare(InstrumentationInfo o1, InstrumentationInfo o2) {
447                    return o1.targetPackage.compareTo(o2.targetPackage);
448                }
449            });
450
451            int count = (list != null) ? list.size() : 0;
452            for (int p = 0; p < count; p++) {
453                InstrumentationInfo ii = list.get(p);
454                System.out.print("instrumentation:");
455                if (showPackage) {
456                    System.out.print(ii.sourceDir);
457                    System.out.print("=");
458                }
459                ComponentName cn = new ComponentName(ii.packageName, ii.name);
460                System.out.print(cn.flattenToShortString());
461                System.out.print(" (target=");
462                System.out.print(ii.targetPackage);
463                System.out.println(")");
464            }
465        } catch (RemoteException e) {
466            System.err.println(e.toString());
467            System.err.println(PM_NOT_RUNNING_ERR);
468        }
469    }
470
471    /**
472     * Lists all the known permission groups.
473     */
474    private void runListPermissionGroups() {
475        try {
476            List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0);
477
478            int count = pgs.size();
479            for (int p = 0 ; p < count ; p++) {
480                PermissionGroupInfo pgi = pgs.get(p);
481                System.out.print("permission group:");
482                System.out.println(pgi.name);
483            }
484        } catch (RemoteException e) {
485            System.err.println(e.toString());
486            System.err.println(PM_NOT_RUNNING_ERR);
487        }
488    }
489
490    private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) {
491        if (nonLocalized != null) {
492            return nonLocalized.toString();
493        }
494        if (res != 0) {
495            Resources r = getResources(pii);
496            if (r != null) {
497                return r.getString(res);
498            }
499        }
500        return null;
501    }
502
503    /**
504     * Lists all the permissions in a group.
505     */
506    private void runListPermissions() {
507        try {
508            boolean labels = false;
509            boolean groups = false;
510            boolean userOnly = false;
511            boolean summary = false;
512            boolean dangerousOnly = false;
513            String opt;
514            while ((opt=nextOption()) != null) {
515                if (opt.equals("-f")) {
516                    labels = true;
517                } else if (opt.equals("-g")) {
518                    groups = true;
519                } else if (opt.equals("-s")) {
520                    groups = true;
521                    labels = true;
522                    summary = true;
523                } else if (opt.equals("-u")) {
524                    userOnly = true;
525                } else if (opt.equals("-d")) {
526                    dangerousOnly = true;
527                } else {
528                    System.err.println("Error: Unknown option: " + opt);
529                    return;
530                }
531            }
532
533            String grp = nextOption();
534            ArrayList<String> groupList = new ArrayList<String>();
535            if (groups) {
536                List<PermissionGroupInfo> infos =
537                        mPm.getAllPermissionGroups(0);
538                for (int i=0; i<infos.size(); i++) {
539                    groupList.add(infos.get(i).name);
540                }
541                groupList.add(null);
542            } else {
543                groupList.add(grp);
544            }
545
546            if (dangerousOnly) {
547                System.out.println("Dangerous Permissions:");
548                System.out.println("");
549                doListPermissions(groupList, groups, labels, summary,
550                        PermissionInfo.PROTECTION_DANGEROUS,
551                        PermissionInfo.PROTECTION_DANGEROUS);
552                if (userOnly) {
553                    System.out.println("Normal Permissions:");
554                    System.out.println("");
555                    doListPermissions(groupList, groups, labels, summary,
556                            PermissionInfo.PROTECTION_NORMAL,
557                            PermissionInfo.PROTECTION_NORMAL);
558                }
559            } else if (userOnly) {
560                System.out.println("Dangerous and Normal Permissions:");
561                System.out.println("");
562                doListPermissions(groupList, groups, labels, summary,
563                        PermissionInfo.PROTECTION_NORMAL,
564                        PermissionInfo.PROTECTION_DANGEROUS);
565            } else {
566                System.out.println("All Permissions:");
567                System.out.println("");
568                doListPermissions(groupList, groups, labels, summary,
569                        -10000, 10000);
570            }
571        } catch (RemoteException e) {
572            System.err.println(e.toString());
573            System.err.println(PM_NOT_RUNNING_ERR);
574        }
575    }
576
577    private void doListPermissions(ArrayList<String> groupList,
578            boolean groups, boolean labels, boolean summary,
579            int startProtectionLevel, int endProtectionLevel)
580            throws RemoteException {
581        for (int i=0; i<groupList.size(); i++) {
582            String groupName = groupList.get(i);
583            String prefix = "";
584            if (groups) {
585                if (i > 0) System.out.println("");
586                if (groupName != null) {
587                    PermissionGroupInfo pgi = mPm.getPermissionGroupInfo(
588                            groupName, 0);
589                    if (summary) {
590                        Resources res = getResources(pgi);
591                        if (res != null) {
592                            System.out.print(loadText(pgi, pgi.labelRes,
593                                    pgi.nonLocalizedLabel) + ": ");
594                        } else {
595                            System.out.print(pgi.name + ": ");
596
597                        }
598                    } else {
599                        System.out.println((labels ? "+ " : "")
600                                + "group:" + pgi.name);
601                        if (labels) {
602                            System.out.println("  package:" + pgi.packageName);
603                            Resources res = getResources(pgi);
604                            if (res != null) {
605                                System.out.println("  label:"
606                                        + loadText(pgi, pgi.labelRes,
607                                                pgi.nonLocalizedLabel));
608                                System.out.println("  description:"
609                                        + loadText(pgi, pgi.descriptionRes,
610                                                pgi.nonLocalizedDescription));
611                            }
612                        }
613                    }
614                } else {
615                    System.out.println(((labels && !summary)
616                            ? "+ " : "") + "ungrouped:");
617                }
618                prefix = "  ";
619            }
620            List<PermissionInfo> ps = mPm.queryPermissionsByGroup(
621                    groupList.get(i), 0);
622            int count = ps.size();
623            boolean first = true;
624            for (int p = 0 ; p < count ; p++) {
625                PermissionInfo pi = ps.get(p);
626                if (groups && groupName == null && pi.group != null) {
627                    continue;
628                }
629                final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
630                if (base < startProtectionLevel
631                        || base > endProtectionLevel) {
632                    continue;
633                }
634                if (summary) {
635                    if (first) {
636                        first = false;
637                    } else {
638                        System.out.print(", ");
639                    }
640                    Resources res = getResources(pi);
641                    if (res != null) {
642                        System.out.print(loadText(pi, pi.labelRes,
643                                pi.nonLocalizedLabel));
644                    } else {
645                        System.out.print(pi.name);
646                    }
647                } else {
648                    System.out.println(prefix + (labels ? "+ " : "")
649                            + "permission:" + pi.name);
650                    if (labels) {
651                        System.out.println(prefix + "  package:" + pi.packageName);
652                        Resources res = getResources(pi);
653                        if (res != null) {
654                            System.out.println(prefix + "  label:"
655                                    + loadText(pi, pi.labelRes,
656                                            pi.nonLocalizedLabel));
657                            System.out.println(prefix + "  description:"
658                                    + loadText(pi, pi.descriptionRes,
659                                            pi.nonLocalizedDescription));
660                        }
661                        System.out.println(prefix + "  protectionLevel:"
662                                + PermissionInfo.protectionToString(pi.protectionLevel));
663                    }
664                }
665            }
666
667            if (summary) {
668                System.out.println("");
669            }
670        }
671    }
672
673    private void runPath() {
674        String pkg = nextArg();
675        if (pkg == null) {
676            System.err.println("Error: no package specified");
677            return;
678        }
679        displayPackageFilePath(pkg);
680    }
681
682    private void runDump() {
683        String pkg = nextArg();
684        if (pkg == null) {
685            System.err.println("Error: no package specified");
686            return;
687        }
688        ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
689    }
690
691    class PackageInstallObserver extends IPackageInstallObserver.Stub {
692        boolean finished;
693        int result;
694
695        public void packageInstalled(String name, int status) {
696            synchronized( this) {
697                finished = true;
698                result = status;
699                notifyAll();
700            }
701        }
702    }
703
704    /**
705     * Converts a failure code into a string by using reflection to find a matching constant
706     * in PackageManager.
707     */
708    private String installFailureToString(int result) {
709        Field[] fields = PackageManager.class.getFields();
710        for (Field f: fields) {
711            if (f.getType() == int.class) {
712                int modifiers = f.getModifiers();
713                // only look at public final static fields.
714                if (((modifiers & Modifier.FINAL) != 0) &&
715                        ((modifiers & Modifier.PUBLIC) != 0) &&
716                        ((modifiers & Modifier.STATIC) != 0)) {
717                    String fieldName = f.getName();
718                    if (fieldName.startsWith("INSTALL_FAILED_") ||
719                            fieldName.startsWith("INSTALL_PARSE_FAILED_")) {
720                        // get the int value and compare it to result.
721                        try {
722                            if (result == f.getInt(null)) {
723                                return fieldName;
724                            }
725                        } catch (IllegalAccessException e) {
726                            // this shouldn't happen since we only look for public static fields.
727                        }
728                    }
729                }
730            }
731        }
732
733        // couldn't find a matching constant? return the value
734        return Integer.toString(result);
735    }
736
737    private void runSetInstallLocation() {
738        int loc;
739
740        String arg = nextArg();
741        if (arg == null) {
742            System.err.println("Error: no install location specified.");
743            return;
744        }
745        try {
746            loc = Integer.parseInt(arg);
747        } catch (NumberFormatException e) {
748            System.err.println("Error: install location has to be a number.");
749            return;
750        }
751        try {
752            if (!mPm.setInstallLocation(loc)) {
753                System.err.println("Error: install location has to be a number.");
754            }
755        } catch (RemoteException e) {
756            System.err.println(e.toString());
757            System.err.println(PM_NOT_RUNNING_ERR);
758        }
759    }
760
761    private void runGetInstallLocation() {
762        try {
763            int loc = mPm.getInstallLocation();
764            String locStr = "invalid";
765            if (loc == PackageHelper.APP_INSTALL_AUTO) {
766                locStr = "auto";
767            } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) {
768                locStr = "internal";
769            } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
770                locStr = "external";
771            }
772            System.out.println(loc + "[" + locStr + "]");
773        } catch (RemoteException e) {
774            System.err.println(e.toString());
775            System.err.println(PM_NOT_RUNNING_ERR);
776        }
777    }
778
779    private void runInstall() {
780        int installFlags = PackageManager.INSTALL_ALL_USERS;
781        String installerPackageName = null;
782
783        String opt;
784
785        String algo = null;
786        byte[] iv = null;
787        byte[] key = null;
788
789        String macAlgo = null;
790        byte[] macKey = null;
791        byte[] tag = null;
792        String originatingUriString = null;
793        String referrer = null;
794
795        while ((opt=nextOption()) != null) {
796            if (opt.equals("-l")) {
797                installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
798            } else if (opt.equals("-r")) {
799                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
800            } else if (opt.equals("-i")) {
801                installerPackageName = nextOptionData();
802                if (installerPackageName == null) {
803                    System.err.println("Error: no value specified for -i");
804                    return;
805                }
806            } else if (opt.equals("-t")) {
807                installFlags |= PackageManager.INSTALL_ALLOW_TEST;
808            } else if (opt.equals("-s")) {
809                // Override if -s option is specified.
810                installFlags |= PackageManager.INSTALL_EXTERNAL;
811            } else if (opt.equals("-f")) {
812                // Override if -s option is specified.
813                installFlags |= PackageManager.INSTALL_INTERNAL;
814            } else if (opt.equals("-d")) {
815                installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
816            } else if (opt.equals("--algo")) {
817                algo = nextOptionData();
818                if (algo == null) {
819                    System.err.println("Error: must supply argument for --algo");
820                    return;
821                }
822            } else if (opt.equals("--iv")) {
823                iv = hexToBytes(nextOptionData());
824                if (iv == null) {
825                    System.err.println("Error: must supply argument for --iv");
826                    return;
827                }
828            } else if (opt.equals("--key")) {
829                key = hexToBytes(nextOptionData());
830                if (key == null) {
831                    System.err.println("Error: must supply argument for --key");
832                    return;
833                }
834            } else if (opt.equals("--macalgo")) {
835                macAlgo = nextOptionData();
836                if (macAlgo == null) {
837                    System.err.println("Error: must supply argument for --macalgo");
838                    return;
839                }
840            } else if (opt.equals("--mackey")) {
841                macKey = hexToBytes(nextOptionData());
842                if (macKey == null) {
843                    System.err.println("Error: must supply argument for --mackey");
844                    return;
845                }
846            } else if (opt.equals("--tag")) {
847                tag = hexToBytes(nextOptionData());
848                if (tag == null) {
849                    System.err.println("Error: must supply argument for --tag");
850                    return;
851                }
852            } else if (opt.equals("--originating-uri")) {
853                originatingUriString = nextOptionData();
854                if (originatingUriString == null) {
855                    System.err.println("Error: must supply argument for --originating-uri");
856                    return;
857                }
858            } else if (opt.equals("--referrer")) {
859                referrer = nextOptionData();
860                if (referrer == null) {
861                    System.err.println("Error: must supply argument for --referrer");
862                    return;
863                }
864            } else {
865                System.err.println("Error: Unknown option: " + opt);
866                return;
867            }
868        }
869
870        final ContainerEncryptionParams encryptionParams;
871        if (algo != null || iv != null || key != null || macAlgo != null || macKey != null
872                || tag != null) {
873            if (algo == null || iv == null || key == null) {
874                System.err.println("Error: all of --algo, --iv, and --key must be specified");
875                return;
876            }
877
878            if (macAlgo != null || macKey != null || tag != null) {
879                if (macAlgo == null || macKey == null || tag == null) {
880                    System.err.println("Error: all of --macalgo, --mackey, and --tag must "
881                            + "be specified");
882                    return;
883                }
884            }
885
886            try {
887                final SecretKey encKey = new SecretKeySpec(key, "RAW");
888
889                final SecretKey macSecretKey;
890                if (macKey == null || macKey.length == 0) {
891                    macSecretKey = null;
892                } else {
893                    macSecretKey = new SecretKeySpec(macKey, "RAW");
894                }
895
896                encryptionParams = new ContainerEncryptionParams(algo, new IvParameterSpec(iv),
897                        encKey, macAlgo, null, macSecretKey, tag, -1, -1, -1);
898            } catch (InvalidAlgorithmParameterException e) {
899                e.printStackTrace();
900                return;
901            }
902        } else {
903            encryptionParams = null;
904        }
905
906        final Uri apkURI;
907        final Uri verificationURI;
908        final Uri originatingURI;
909        final Uri referrerURI;
910
911        if (originatingUriString != null) {
912            originatingURI = Uri.parse(originatingUriString);
913        } else {
914            originatingURI = null;
915        }
916
917        if (referrer != null) {
918            referrerURI = Uri.parse(referrer);
919        } else {
920            referrerURI = null;
921        }
922
923        // Populate apkURI, must be present
924        final String apkFilePath = nextArg();
925        System.err.println("\tpkg: " + apkFilePath);
926        if (apkFilePath != null) {
927            apkURI = Uri.fromFile(new File(apkFilePath));
928        } else {
929            System.err.println("Error: no package specified");
930            return;
931        }
932
933        // Populate verificationURI, optionally present
934        final String verificationFilePath = nextArg();
935        if (verificationFilePath != null) {
936            System.err.println("\tver: " + verificationFilePath);
937            verificationURI = Uri.fromFile(new File(verificationFilePath));
938        } else {
939            verificationURI = null;
940        }
941
942        PackageInstallObserver obs = new PackageInstallObserver();
943        try {
944            VerificationParams verificationParams = new VerificationParams(verificationURI,
945                    originatingURI, referrerURI, VerificationParams.NO_UID, null);
946
947            mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,
948                    installerPackageName, verificationParams, encryptionParams);
949
950            synchronized (obs) {
951                while (!obs.finished) {
952                    try {
953                        obs.wait();
954                    } catch (InterruptedException e) {
955                    }
956                }
957                if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
958                    System.out.println("Success");
959                } else {
960                    System.err.println("Failure ["
961                            + installFailureToString(obs.result)
962                            + "]");
963                }
964            }
965        } catch (RemoteException e) {
966            System.err.println(e.toString());
967            System.err.println(PM_NOT_RUNNING_ERR);
968        }
969    }
970
971    /**
972     * Convert a string containing hex-encoded bytes to a byte array.
973     *
974     * @param input String containing hex-encoded bytes
975     * @return input as an array of bytes
976     */
977    private byte[] hexToBytes(String input) {
978        if (input == null) {
979            return null;
980        }
981
982        final int inputLength = input.length();
983        if ((inputLength % 2) != 0) {
984            System.err.print("Invalid length; must be multiple of 2");
985            return null;
986        }
987
988        final int byteLength = inputLength / 2;
989        final byte[] output = new byte[byteLength];
990
991        int inputIndex = 0;
992        int byteIndex = 0;
993        while (inputIndex < inputLength) {
994            output[byteIndex++] = (byte) Integer.parseInt(
995                    input.substring(inputIndex, inputIndex + 2), 16);
996            inputIndex += 2;
997        }
998
999        return output;
1000    }
1001
1002    public void runCreateUser() {
1003        String name;
1004        String arg = nextArg();
1005        if (arg == null) {
1006            System.err.println("Error: no user name specified.");
1007            return;
1008        }
1009        name = arg;
1010        try {
1011            final UserInfo info = mUm.createUser(name, 0);
1012            if (info != null) {
1013                System.out.println("Success: created user id " + info.id);
1014            } else {
1015                System.err.println("Error: couldn't create User.");
1016            }
1017        } catch (RemoteException e) {
1018            System.err.println(e.toString());
1019            System.err.println(PM_NOT_RUNNING_ERR);
1020        }
1021
1022    }
1023
1024    public void runRemoveUser() {
1025        int userId;
1026        String arg = nextArg();
1027        if (arg == null) {
1028            System.err.println("Error: no user id specified.");
1029            return;
1030        }
1031        try {
1032            userId = Integer.parseInt(arg);
1033        } catch (NumberFormatException e) {
1034            System.err.println("Error: user id '" + arg + "' is not a number.");
1035            return;
1036        }
1037        try {
1038            if (mUm.removeUser(userId)) {
1039                System.out.println("Success: removed user");
1040            } else {
1041                System.err.println("Error: couldn't remove user id " + userId);
1042            }
1043        } catch (RemoteException e) {
1044            System.err.println(e.toString());
1045            System.err.println(PM_NOT_RUNNING_ERR);
1046        }
1047    }
1048
1049    public void runListUsers() {
1050        try {
1051            List<UserInfo> users = mUm.getUsers(false);
1052            if (users == null) {
1053                System.err.println("Error: couldn't get users");
1054            } else {
1055                System.out.println("Users:");
1056                for (int i = 0; i < users.size(); i++) {
1057                    System.out.println("\t" + users.get(i).toString());
1058                }
1059            }
1060        } catch (RemoteException e) {
1061            System.err.println(e.toString());
1062            System.err.println(PM_NOT_RUNNING_ERR);
1063        }
1064    }
1065
1066    public void runGetMaxUsers() {
1067        System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
1068    }
1069
1070    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
1071        boolean finished;
1072        boolean result;
1073
1074        public void packageDeleted(String packageName, int returnCode) {
1075            synchronized (this) {
1076                finished = true;
1077                result = returnCode == PackageManager.DELETE_SUCCEEDED;
1078                notifyAll();
1079            }
1080        }
1081    }
1082
1083    private void runUninstall() {
1084        int unInstallFlags = PackageManager.DELETE_ALL_USERS;
1085
1086        String opt;
1087        while ((opt=nextOption()) != null) {
1088            if (opt.equals("-k")) {
1089                unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
1090            } else {
1091                System.err.println("Error: Unknown option: " + opt);
1092                return;
1093            }
1094        }
1095
1096        String pkg = nextArg();
1097        if (pkg == null) {
1098            System.err.println("Error: no package specified");
1099            showUsage();
1100            return;
1101        }
1102        boolean result = deletePackage(pkg, unInstallFlags);
1103        if (result) {
1104            System.out.println("Success");
1105        } else {
1106            System.out.println("Failure");
1107        }
1108    }
1109
1110    private boolean deletePackage(String pkg, int unInstallFlags) {
1111        PackageDeleteObserver obs = new PackageDeleteObserver();
1112        try {
1113            mPm.deletePackageAsUser(pkg, obs, UserHandle.USER_OWNER, unInstallFlags);
1114
1115            synchronized (obs) {
1116                while (!obs.finished) {
1117                    try {
1118                        obs.wait();
1119                    } catch (InterruptedException e) {
1120                    }
1121                }
1122            }
1123        } catch (RemoteException e) {
1124            System.err.println(e.toString());
1125            System.err.println(PM_NOT_RUNNING_ERR);
1126        }
1127        return obs.result;
1128    }
1129
1130    static class ClearDataObserver extends IPackageDataObserver.Stub {
1131        boolean finished;
1132        boolean result;
1133
1134        @Override
1135        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
1136            synchronized (this) {
1137                finished = true;
1138                result = succeeded;
1139                notifyAll();
1140            }
1141        }
1142
1143    }
1144
1145    private void runClear() {
1146        int userId = 0;
1147        String option = nextOption();
1148        if (option != null && option.equals("--user")) {
1149            String optionData = nextOptionData();
1150            if (optionData == null || !isNumber(optionData)) {
1151                System.err.println("Error: no USER_ID specified");
1152                showUsage();
1153                return;
1154            } else {
1155                userId = Integer.parseInt(optionData);
1156            }
1157        }
1158
1159        String pkg = nextArg();
1160        if (pkg == null) {
1161            System.err.println("Error: no package specified");
1162            showUsage();
1163            return;
1164        }
1165
1166        ClearDataObserver obs = new ClearDataObserver();
1167        try {
1168            ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId);
1169            synchronized (obs) {
1170                while (!obs.finished) {
1171                    try {
1172                        obs.wait();
1173                    } catch (InterruptedException e) {
1174                    }
1175                }
1176            }
1177
1178            if (obs.result) {
1179                System.err.println("Success");
1180            } else {
1181                System.err.println("Failed");
1182            }
1183        } catch (RemoteException e) {
1184            System.err.println(e.toString());
1185            System.err.println(PM_NOT_RUNNING_ERR);
1186        }
1187    }
1188
1189    private static String enabledSettingToString(int state) {
1190        switch (state) {
1191            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
1192                return "default";
1193            case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
1194                return "enabled";
1195            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
1196                return "disabled";
1197            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
1198                return "disabled-user";
1199            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
1200                return "disabled-until-used";
1201        }
1202        return "unknown";
1203    }
1204
1205    private static boolean isNumber(String s) {
1206        try {
1207            Integer.parseInt(s);
1208        } catch (NumberFormatException nfe) {
1209            return false;
1210        }
1211        return true;
1212    }
1213
1214    private void runSetEnabledSetting(int state) {
1215        int userId = 0;
1216        String option = nextOption();
1217        if (option != null && option.equals("--user")) {
1218            String optionData = nextOptionData();
1219            if (optionData == null || !isNumber(optionData)) {
1220                System.err.println("Error: no USER_ID specified");
1221                showUsage();
1222                return;
1223            } else {
1224                userId = Integer.parseInt(optionData);
1225            }
1226        }
1227
1228        String pkg = nextArg();
1229        if (pkg == null) {
1230            System.err.println("Error: no package or component specified");
1231            showUsage();
1232            return;
1233        }
1234        ComponentName cn = ComponentName.unflattenFromString(pkg);
1235        if (cn == null) {
1236            try {
1237                mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
1238                        "shell:" + android.os.Process.myUid());
1239                System.err.println("Package " + pkg + " new state: "
1240                        + enabledSettingToString(
1241                        mPm.getApplicationEnabledSetting(pkg, userId)));
1242            } catch (RemoteException e) {
1243                System.err.println(e.toString());
1244                System.err.println(PM_NOT_RUNNING_ERR);
1245            }
1246        } else {
1247            try {
1248                mPm.setComponentEnabledSetting(cn, state, 0, userId);
1249                System.err.println("Component " + cn.toShortString() + " new state: "
1250                        + enabledSettingToString(
1251                        mPm.getComponentEnabledSetting(cn, userId)));
1252            } catch (RemoteException e) {
1253                System.err.println(e.toString());
1254                System.err.println(PM_NOT_RUNNING_ERR);
1255            }
1256        }
1257    }
1258
1259    private void runGrantRevokePermission(boolean grant) {
1260        String pkg = nextArg();
1261        if (pkg == null) {
1262            System.err.println("Error: no package specified");
1263            showUsage();
1264            return;
1265        }
1266        String perm = nextArg();
1267        if (perm == null) {
1268            System.err.println("Error: no permission specified");
1269            showUsage();
1270            return;
1271        }
1272        try {
1273            if (grant) {
1274                mPm.grantPermission(pkg, perm);
1275            } else {
1276                mPm.revokePermission(pkg, perm);
1277            }
1278        } catch (RemoteException e) {
1279            System.err.println(e.toString());
1280            System.err.println(PM_NOT_RUNNING_ERR);
1281        } catch (IllegalArgumentException e) {
1282            System.err.println("Bad argument: " + e.toString());
1283            showUsage();
1284        } catch (SecurityException e) {
1285            System.err.println("Operation not allowed: " + e.toString());
1286        }
1287    }
1288
1289    private void runSetPermissionEnforced() {
1290        final String permission = nextArg();
1291        if (permission == null) {
1292            System.err.println("Error: no permission specified");
1293            showUsage();
1294            return;
1295        }
1296        final String enforcedRaw = nextArg();
1297        if (enforcedRaw == null) {
1298            System.err.println("Error: no enforcement specified");
1299            showUsage();
1300            return;
1301        }
1302        final boolean enforced = Boolean.parseBoolean(enforcedRaw);
1303        try {
1304            mPm.setPermissionEnforced(permission, enforced);
1305        } catch (RemoteException e) {
1306            System.err.println(e.toString());
1307            System.err.println(PM_NOT_RUNNING_ERR);
1308        } catch (IllegalArgumentException e) {
1309            System.err.println("Bad argument: " + e.toString());
1310            showUsage();
1311        } catch (SecurityException e) {
1312            System.err.println("Operation not allowed: " + e.toString());
1313        }
1314    }
1315
1316    static class ClearCacheObserver extends IPackageDataObserver.Stub {
1317        boolean finished;
1318        boolean result;
1319
1320        @Override
1321        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
1322            synchronized (this) {
1323                finished = true;
1324                result = succeeded;
1325                notifyAll();
1326            }
1327        }
1328
1329    }
1330
1331    private void runTrimCaches() {
1332        String size = nextArg();
1333        if (size == null) {
1334            System.err.println("Error: no size specified");
1335            showUsage();
1336            return;
1337        }
1338        int len = size.length();
1339        long multiplier = 1;
1340        if (len > 1) {
1341            char c = size.charAt(len-1);
1342            if (c == 'K' || c == 'k') {
1343                multiplier = 1024L;
1344            } else if (c == 'M' || c == 'm') {
1345                multiplier = 1024L*1024L;
1346            } else if (c == 'G' || c == 'g') {
1347                multiplier = 1024L*1024L*1024L;
1348            } else {
1349                System.err.println("Invalid suffix: " + c);
1350                showUsage();
1351                return;
1352            }
1353            size = size.substring(0, len-1);
1354        }
1355        long sizeVal;
1356        try {
1357            sizeVal = Long.parseLong(size) * multiplier;
1358        } catch (NumberFormatException e) {
1359            System.err.println("Error: expected number at: " + size);
1360            showUsage();
1361            return;
1362        }
1363        ClearDataObserver obs = new ClearDataObserver();
1364        try {
1365            mPm.freeStorageAndNotify(sizeVal, obs);
1366            synchronized (obs) {
1367                while (!obs.finished) {
1368                    try {
1369                        obs.wait();
1370                    } catch (InterruptedException e) {
1371                    }
1372                }
1373            }
1374        } catch (RemoteException e) {
1375            System.err.println(e.toString());
1376            System.err.println(PM_NOT_RUNNING_ERR);
1377        } catch (IllegalArgumentException e) {
1378            System.err.println("Bad argument: " + e.toString());
1379            showUsage();
1380        } catch (SecurityException e) {
1381            System.err.println("Operation not allowed: " + e.toString());
1382        }
1383    }
1384
1385    /**
1386     * Displays the package file for a package.
1387     * @param pckg
1388     */
1389    private void displayPackageFilePath(String pckg) {
1390        try {
1391            PackageInfo info = mPm.getPackageInfo(pckg, 0, 0);
1392            if (info != null && info.applicationInfo != null) {
1393                System.out.print("package:");
1394                System.out.println(info.applicationInfo.sourceDir);
1395            }
1396        } catch (RemoteException e) {
1397            System.err.println(e.toString());
1398            System.err.println(PM_NOT_RUNNING_ERR);
1399        }
1400    }
1401
1402    private Resources getResources(PackageItemInfo pii) {
1403        Resources res = mResourceCache.get(pii.packageName);
1404        if (res != null) return res;
1405
1406        try {
1407            ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0, 0);
1408            AssetManager am = new AssetManager();
1409            am.addAssetPath(ai.publicSourceDir);
1410            res = new Resources(am, null, null);
1411            mResourceCache.put(pii.packageName, res);
1412            return res;
1413        } catch (RemoteException e) {
1414            System.err.println(e.toString());
1415            System.err.println(PM_NOT_RUNNING_ERR);
1416            return null;
1417        }
1418    }
1419
1420    private String nextOption() {
1421        if (mNextArg >= mArgs.length) {
1422            return null;
1423        }
1424        String arg = mArgs[mNextArg];
1425        if (!arg.startsWith("-")) {
1426            return null;
1427        }
1428        mNextArg++;
1429        if (arg.equals("--")) {
1430            return null;
1431        }
1432        if (arg.length() > 1 && arg.charAt(1) != '-') {
1433            if (arg.length() > 2) {
1434                mCurArgData = arg.substring(2);
1435                return arg.substring(0, 2);
1436            } else {
1437                mCurArgData = null;
1438                return arg;
1439            }
1440        }
1441        mCurArgData = null;
1442        return arg;
1443    }
1444
1445    private String nextOptionData() {
1446        if (mCurArgData != null) {
1447            return mCurArgData;
1448        }
1449        if (mNextArg >= mArgs.length) {
1450            return null;
1451        }
1452        String data = mArgs[mNextArg];
1453        mNextArg++;
1454        return data;
1455    }
1456
1457    private String nextArg() {
1458        if (mNextArg >= mArgs.length) {
1459            return null;
1460        }
1461        String arg = mArgs[mNextArg];
1462        mNextArg++;
1463        return arg;
1464    }
1465
1466    private static void showUsage() {
1467        System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]");
1468        System.err.println("       pm list permission-groups");
1469        System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
1470        System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");
1471        System.err.println("       pm list features");
1472        System.err.println("       pm list libraries");
1473        System.err.println("       pm list users");
1474        System.err.println("       pm path PACKAGE");
1475        System.err.println("       pm dump PACKAGE");
1476        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
1477        System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
1478        System.err.println("                  [--originating-uri <URI>] [--referrer <URI>] PATH");
1479        System.err.println("       pm uninstall [-k] PACKAGE");
1480        System.err.println("       pm clear [--user USER_ID] PACKAGE");
1481        System.err.println("       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
1482        System.err.println("       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
1483        System.err.println("       pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
1484        System.err.println("       pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
1485        System.err.println("       pm grant PACKAGE PERMISSION");
1486        System.err.println("       pm revoke PACKAGE PERMISSION");
1487        System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
1488        System.err.println("       pm get-install-location");
1489        System.err.println("       pm set-permission-enforced PERMISSION [true|false]");
1490        System.err.println("       pm trim-caches DESIRED_FREE_SPACE");
1491        System.err.println("       pm create-user USER_NAME");
1492        System.err.println("       pm remove-user USER_ID");
1493        System.err.println("       pm get-max-users");
1494        System.err.println("");
1495        System.err.println("pm list packages: prints all packages, optionally only");
1496        System.err.println("  those whose package name contains the text in FILTER.  Options:");
1497        System.err.println("    -f: see their associated file.");
1498        System.err.println("    -d: filter to only show disbled packages.");
1499        System.err.println("    -e: filter to only show enabled packages.");
1500        System.err.println("    -s: filter to only show system packages.");
1501        System.err.println("    -3: filter to only show third party packages.");
1502        System.err.println("    -i: see the installer for the packages.");
1503        System.err.println("    -u: also include uninstalled packages.");
1504        System.err.println("");
1505        System.err.println("pm list permission-groups: prints all known permission groups.");
1506        System.err.println("");
1507        System.err.println("pm list permissions: prints all known permissions, optionally only");
1508        System.err.println("  those in GROUP.  Options:");
1509        System.err.println("    -g: organize by group.");
1510        System.err.println("    -f: print all information.");
1511        System.err.println("    -s: short summary.");
1512        System.err.println("    -d: only list dangerous permissions.");
1513        System.err.println("    -u: list only the permissions users will see.");
1514        System.err.println("");
1515        System.err.println("pm list instrumentation: use to list all test packages; optionally");
1516        System.err.println("  supply <TARGET-PACKAGE> to list the test packages for a particular");
1517        System.err.println("  application.  Options:");
1518        System.err.println("    -f: list the .apk file for the test package.");
1519        System.err.println("");
1520        System.err.println("pm list features: prints all features of the system.");
1521        System.err.println("");
1522        System.err.println("pm list users: prints all users on the system.");
1523        System.err.println("");
1524        System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
1525        System.err.println("");
1526        System.err.println("pm dump: print system state associated w ith the given PACKAGE.");
1527        System.err.println("");
1528        System.err.println("pm install: installs a package to the system.  Options:");
1529        System.err.println("    -l: install the package with FORWARD_LOCK.");
1530        System.err.println("    -r: reinstall an exisiting app, keeping its data.");
1531        System.err.println("    -t: allow test .apks to be installed.");
1532        System.err.println("    -i: specify the installer package name.");
1533        System.err.println("    -s: install package on sdcard.");
1534        System.err.println("    -f: install package on internal flash.");
1535        System.err.println("    -d: allow version code downgrade.");
1536        System.err.println("");
1537        System.err.println("pm uninstall: removes a package from the system. Options:");
1538        System.err.println("    -k: keep the data and cache directories around after package removal.");
1539        System.err.println("");
1540        System.err.println("pm clear: deletes all data associated with a package.");
1541        System.err.println("");
1542        System.err.println("pm enable, disable, disable-user, disable-until-used: these commands");
1543        System.err.println("  change the enabled state of a given package or component (written");
1544        System.err.println("  as \"package/class\").");
1545        System.err.println("");
1546        System.err.println("pm grant, revoke: these commands either grant or revoke permissions");
1547        System.err.println("  to applications.  Only optional permissions the application has");
1548        System.err.println("  declared can be granted or revoked.");
1549        System.err.println("");
1550        System.err.println("pm get-install-location: returns the current install location.");
1551        System.err.println("    0 [auto]: Let system decide the best location");
1552        System.err.println("    1 [internal]: Install on internal device storage");
1553        System.err.println("    2 [external]: Install on external media");
1554        System.err.println("");
1555        System.err.println("pm set-install-location: changes the default install location.");
1556        System.err.println("  NOTE: this is only intended for debugging; using this can cause");
1557        System.err.println("  applications to break and other undersireable behavior.");
1558        System.err.println("    0 [auto]: Let system decide the best location");
1559        System.err.println("    1 [internal]: Install on internal device storage");
1560        System.err.println("    2 [external]: Install on external media");
1561        System.err.println("");
1562        System.err.println("pm trim-caches: trim cache files to reach the given free space.");
1563        System.err.println("");
1564        System.err.println("pm create-user: create a new user with the given USER_NAME,");
1565        System.err.println("  printing the new user identifier of the user.");
1566        System.err.println("");
1567        System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
1568        System.err.println("  deleting all data associated with that user");
1569    }
1570}
1571