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