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