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