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