Pm.java revision 039c68e75606e837cf021815a0210836724574ad
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.commands.pm;
18
19import android.content.ComponentName;
20import android.content.pm.ApplicationInfo;
21import android.content.pm.FeatureInfo;
22import android.content.pm.IPackageDeleteObserver;
23import android.content.pm.IPackageInstallObserver;
24import android.content.pm.IPackageManager;
25import android.content.pm.InstrumentationInfo;
26import android.content.pm.PackageInfo;
27import android.content.pm.PackageItemInfo;
28import android.content.pm.PackageManager;
29import android.content.pm.PermissionGroupInfo;
30import android.content.pm.PermissionInfo;
31import android.content.res.AssetManager;
32import android.content.res.Resources;
33import android.net.Uri;
34import android.os.RemoteException;
35import android.os.ServiceManager;
36
37import java.io.File;
38import java.lang.reflect.Field;
39import java.lang.reflect.Modifier;
40import java.util.ArrayList;
41import java.util.Collections;
42import java.util.Comparator;
43import java.util.List;
44import java.util.WeakHashMap;
45
46public final class Pm {
47    IPackageManager mPm;
48
49    private WeakHashMap<String, Resources> mResourceCache
50            = new WeakHashMap<String, Resources>();
51
52    private String[] mArgs;
53    private int mNextArg;
54    private String mCurArgData;
55
56    private static final String PM_NOT_RUNNING_ERR =
57        "Error: Could not access the Package Manager.  Is the system running?";
58
59    public static void main(String[] args) {
60        new Pm().run(args);
61    }
62
63    public void run(String[] args) {
64        boolean validCommand = false;
65        if (args.length < 1) {
66            showUsage();
67            return;
68        }
69
70        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
71        if (mPm == null) {
72            System.err.println(PM_NOT_RUNNING_ERR);
73            return;
74        }
75
76        mArgs = args;
77        String op = args[0];
78        mNextArg = 1;
79
80        if ("list".equals(op)) {
81            runList();
82            return;
83        }
84
85        if ("path".equals(op)) {
86            runPath();
87            return;
88        }
89
90        if ("install".equals(op)) {
91            runInstall();
92            return;
93        }
94
95        if ("uninstall".equals(op)) {
96            runUninstall();
97            return;
98        }
99
100        if ("enable".equals(op)) {
101            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
102            return;
103        }
104
105        if ("disable".equals(op)) {
106            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
107            return;
108        }
109
110        try {
111            if (args.length == 1) {
112                if (args[0].equalsIgnoreCase("-l")) {
113                    validCommand = true;
114                    runListPackages(false);
115                } else if (args[0].equalsIgnoreCase("-lf")){
116                    validCommand = true;
117                    runListPackages(true);
118                }
119            } else if (args.length == 2) {
120                if (args[0].equalsIgnoreCase("-p")) {
121                    validCommand = true;
122                    displayPackageFilePath(args[1]);
123                }
124            }
125        } finally {
126            if (validCommand == false) {
127                if (op != null) {
128                    System.err.println("Error: unknown command '" + op + "'");
129                }
130                showUsage();
131            }
132        }
133    }
134
135    /**
136     * Execute the list sub-command.
137     *
138     * pm list [package | packages]
139     * pm list permission-groups
140     * pm list permissions
141     * pm list features
142     * pm list instrumentation
143     */
144    private void runList() {
145        String type = nextArg();
146        if (type == null) {
147            System.err.println("Error: didn't specify type of data to list");
148            showUsage();
149            return;
150        }
151        if ("package".equals(type) || "packages".equals(type)) {
152            runListPackages(false);
153        } else if ("permission-groups".equals(type)) {
154            runListPermissionGroups();
155        } else if ("permissions".equals(type)) {
156            runListPermissions();
157        } else if ("features".equals(type)) {
158            runListFeatures();
159        } else if ("instrumentation".equals(type)) {
160            runListInstrumentation();
161        } else {
162            System.err.println("Error: unknown list type '" + type + "'");
163            showUsage();
164        }
165    }
166
167    /**
168     * Lists all the installed packages.
169     */
170    private void runListPackages(boolean showApplicationPackage) {
171        try {
172            String opt;
173            while ((opt=nextOption()) != null) {
174                if (opt.equals("-l")) {
175                    // old compat
176                } else if (opt.equals("-lf")) {
177                    showApplicationPackage = true;
178                } else if (opt.equals("-f")) {
179                    showApplicationPackage = true;
180                } else {
181                    System.err.println("Error: Unknown option: " + opt);
182                    showUsage();
183                    return;
184                }
185            }
186        } catch (RuntimeException ex) {
187            System.err.println("Error: " + ex.toString());
188            showUsage();
189            return;
190        }
191
192        try {
193            List<PackageInfo> packages = mPm.getInstalledPackages(0 /* all */);
194
195            int count = packages.size();
196            for (int p = 0 ; p < count ; p++) {
197                PackageInfo info = packages.get(p);
198                System.out.print("package:");
199                if (showApplicationPackage) {
200                    System.out.print(info.applicationInfo.sourceDir);
201                    System.out.print("=");
202                }
203                System.out.println(info.packageName);
204            }
205        } catch (RemoteException e) {
206            System.err.println(e.toString());
207            System.err.println(PM_NOT_RUNNING_ERR);
208        }
209    }
210
211    /**
212     * Lists all of the features supported by the current device.
213     *
214     * pm list features
215     */
216    private void runListFeatures() {
217        try {
218            List<FeatureInfo> list = new ArrayList<FeatureInfo>();
219            FeatureInfo[] rawList = mPm.getSystemAvailableFeatures();
220            for (int i=0; i<rawList.length; i++) {
221                list.add(rawList[i]);
222            }
223
224
225            // Sort by name
226            Collections.sort(list, new Comparator<FeatureInfo>() {
227                public int compare(FeatureInfo o1, FeatureInfo o2) {
228                    if (o1.name == o2.name) return 0;
229                    if (o1.name == null) return -1;
230                    if (o2.name == null) return 1;
231                    return o1.name.compareTo(o2.name);
232                }
233            });
234
235            int count = (list != null) ? list.size() : 0;
236            for (int p = 0; p < count; p++) {
237                FeatureInfo fi = list.get(p);
238                System.out.print("feature:");
239                if (fi.name != null) System.out.println(fi.name);
240                else System.out.println("reqGlEsVersion=0x"
241                        + Integer.toHexString(fi.reqGlEsVersion));
242            }
243        } catch (RemoteException e) {
244            System.err.println(e.toString());
245            System.err.println(PM_NOT_RUNNING_ERR);
246        }
247    }
248
249    /**
250     * Lists all of the installed instrumentation, or all for a given package
251     *
252     * pm list instrumentation [package] [-f]
253     */
254    private void runListInstrumentation() {
255        int flags = 0;      // flags != 0 is only used to request meta-data
256        boolean showPackage = false;
257        String targetPackage = null;
258
259        try {
260            String opt;
261            while ((opt=nextArg()) != null) {
262                if (opt.equals("-f")) {
263                    showPackage = true;
264                } else if (opt.charAt(0) != '-') {
265                    targetPackage = opt;
266                } else {
267                    System.err.println("Error: Unknown option: " + opt);
268                    showUsage();
269                    return;
270                }
271            }
272        } catch (RuntimeException ex) {
273            System.err.println("Error: " + ex.toString());
274            showUsage();
275            return;
276        }
277
278        try {
279            List<InstrumentationInfo> list = mPm.queryInstrumentation(targetPackage, flags);
280
281            // Sort by target package
282            Collections.sort(list, new Comparator<InstrumentationInfo>() {
283                public int compare(InstrumentationInfo o1, InstrumentationInfo o2) {
284                    return o1.targetPackage.compareTo(o2.targetPackage);
285                }
286            });
287
288            int count = (list != null) ? list.size() : 0;
289            for (int p = 0; p < count; p++) {
290                InstrumentationInfo ii = list.get(p);
291                System.out.print("instrumentation:");
292                if (showPackage) {
293                    System.out.print(ii.sourceDir);
294                    System.out.print("=");
295                }
296                ComponentName cn = new ComponentName(ii.packageName, ii.name);
297                System.out.print(cn.flattenToShortString());
298                System.out.print(" (target=");
299                System.out.print(ii.targetPackage);
300                System.out.println(")");
301            }
302        } catch (RemoteException e) {
303            System.err.println(e.toString());
304            System.err.println(PM_NOT_RUNNING_ERR);
305        }
306    }
307
308    /**
309     * Lists all the known permission groups.
310     */
311    private void runListPermissionGroups() {
312        try {
313            List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0);
314
315            int count = pgs.size();
316            for (int p = 0 ; p < count ; p++) {
317                PermissionGroupInfo pgi = pgs.get(p);
318                System.out.print("permission group:");
319                System.out.println(pgi.name);
320            }
321        } catch (RemoteException e) {
322            System.err.println(e.toString());
323            System.err.println(PM_NOT_RUNNING_ERR);
324        }
325    }
326
327    private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) {
328        if (nonLocalized != null) {
329            return nonLocalized.toString();
330        }
331        Resources r = getResources(pii);
332        if (r != null) {
333            return r.getString(res);
334        }
335        return null;
336    }
337
338    /**
339     * Lists all the permissions in a group.
340     */
341    private void runListPermissions() {
342        try {
343            boolean labels = false;
344            boolean groups = false;
345            boolean userOnly = false;
346            boolean summary = false;
347            boolean dangerousOnly = false;
348            String opt;
349            while ((opt=nextOption()) != null) {
350                if (opt.equals("-f")) {
351                    labels = true;
352                } else if (opt.equals("-g")) {
353                    groups = true;
354                } else if (opt.equals("-s")) {
355                    groups = true;
356                    labels = true;
357                    summary = true;
358                } else if (opt.equals("-u")) {
359                    userOnly = true;
360                } else if (opt.equals("-d")) {
361                    dangerousOnly = true;
362                } else {
363                    System.err.println("Error: Unknown option: " + opt);
364                    showUsage();
365                    return;
366                }
367            }
368
369            String grp = nextOption();
370            ArrayList<String> groupList = new ArrayList<String>();
371            if (groups) {
372                List<PermissionGroupInfo> infos =
373                        mPm.getAllPermissionGroups(0);
374                for (int i=0; i<infos.size(); i++) {
375                    groupList.add(infos.get(i).name);
376                }
377                groupList.add(null);
378            } else {
379                groupList.add(grp);
380            }
381
382            if (dangerousOnly) {
383                System.out.println("Dangerous Permissions:");
384                System.out.println("");
385                doListPermissions(groupList, groups, labels, summary,
386                        PermissionInfo.PROTECTION_DANGEROUS,
387                        PermissionInfo.PROTECTION_DANGEROUS);
388                if (userOnly) {
389                    System.out.println("Normal Permissions:");
390                    System.out.println("");
391                    doListPermissions(groupList, groups, labels, summary,
392                            PermissionInfo.PROTECTION_NORMAL,
393                            PermissionInfo.PROTECTION_NORMAL);
394                }
395            } else if (userOnly) {
396                System.out.println("Dangerous and Normal Permissions:");
397                System.out.println("");
398                doListPermissions(groupList, groups, labels, summary,
399                        PermissionInfo.PROTECTION_NORMAL,
400                        PermissionInfo.PROTECTION_DANGEROUS);
401            } else {
402                System.out.println("All Permissions:");
403                System.out.println("");
404                doListPermissions(groupList, groups, labels, summary,
405                        -10000, 10000);
406            }
407        } catch (RemoteException e) {
408            System.err.println(e.toString());
409            System.err.println(PM_NOT_RUNNING_ERR);
410        }
411    }
412
413    private void doListPermissions(ArrayList<String> groupList,
414            boolean groups, boolean labels, boolean summary,
415            int startProtectionLevel, int endProtectionLevel)
416            throws RemoteException {
417        for (int i=0; i<groupList.size(); i++) {
418            String groupName = groupList.get(i);
419            String prefix = "";
420            if (groups) {
421                if (i > 0) System.out.println("");
422                if (groupName != null) {
423                    PermissionGroupInfo pgi = mPm.getPermissionGroupInfo(
424                            groupName, 0);
425                    if (summary) {
426                        Resources res = getResources(pgi);
427                        if (res != null) {
428                            System.out.print(loadText(pgi, pgi.labelRes,
429                                    pgi.nonLocalizedLabel) + ": ");
430                        } else {
431                            System.out.print(pgi.name + ": ");
432
433                        }
434                    } else {
435                        System.out.println((labels ? "+ " : "")
436                                + "group:" + pgi.name);
437                        if (labels) {
438                            System.out.println("  package:" + pgi.packageName);
439                            Resources res = getResources(pgi);
440                            if (res != null) {
441                                System.out.println("  label:"
442                                        + loadText(pgi, pgi.labelRes,
443                                                pgi.nonLocalizedLabel));
444                                System.out.println("  description:"
445                                        + loadText(pgi, pgi.descriptionRes,
446                                                pgi.nonLocalizedDescription));
447                            }
448                        }
449                    }
450                } else {
451                    System.out.println(((labels && !summary)
452                            ? "+ " : "") + "ungrouped:");
453                }
454                prefix = "  ";
455            }
456            List<PermissionInfo> ps = mPm.queryPermissionsByGroup(
457                    groupList.get(i), 0);
458            int count = ps.size();
459            boolean first = true;
460            for (int p = 0 ; p < count ; p++) {
461                PermissionInfo pi = ps.get(p);
462                if (groups && groupName == null && pi.group != null) {
463                    continue;
464                }
465                if (pi.protectionLevel < startProtectionLevel
466                        || pi.protectionLevel > endProtectionLevel) {
467                    continue;
468                }
469                if (summary) {
470                    if (first) {
471                        first = false;
472                    } else {
473                        System.out.print(", ");
474                    }
475                    Resources res = getResources(pi);
476                    if (res != null) {
477                        System.out.print(loadText(pi, pi.labelRes,
478                                pi.nonLocalizedLabel));
479                    } else {
480                        System.out.print(pi.name);
481                    }
482                } else {
483                    System.out.println(prefix + (labels ? "+ " : "")
484                            + "permission:" + pi.name);
485                    if (labels) {
486                        System.out.println(prefix + "  package:" + pi.packageName);
487                        Resources res = getResources(pi);
488                        if (res != null) {
489                            System.out.println(prefix + "  label:"
490                                    + loadText(pi, pi.labelRes,
491                                            pi.nonLocalizedLabel));
492                            System.out.println(prefix + "  description:"
493                                    + loadText(pi, pi.descriptionRes,
494                                            pi.nonLocalizedDescription));
495                        }
496                        String protLevel = "unknown";
497                        switch(pi.protectionLevel) {
498                            case PermissionInfo.PROTECTION_DANGEROUS:
499                                protLevel = "dangerous";
500                                break;
501                            case PermissionInfo.PROTECTION_NORMAL:
502                                protLevel = "normal";
503                                break;
504                            case PermissionInfo.PROTECTION_SIGNATURE:
505                                protLevel = "signature";
506                                break;
507                            case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:
508                                protLevel = "signatureOrSystem";
509                                break;
510                        }
511                        System.out.println(prefix + "  protectionLevel:" + protLevel);
512                    }
513                }
514            }
515
516            if (summary) {
517                System.out.println("");
518            }
519        }
520    }
521
522    private void runPath() {
523        String pkg = nextArg();
524        if (pkg == null) {
525            System.err.println("Error: no package specified");
526            showUsage();
527            return;
528        }
529        displayPackageFilePath(pkg);
530    }
531
532    class PackageInstallObserver extends IPackageInstallObserver.Stub {
533        boolean finished;
534        int result;
535
536        public void packageInstalled(String name, int status) {
537            synchronized( this) {
538                finished = true;
539                result = status;
540                notifyAll();
541            }
542        }
543    }
544
545    /**
546     * Converts a failure code into a string by using reflection to find a matching constant
547     * in PackageManager.
548     */
549    private String installFailureToString(int result) {
550        Field[] fields = PackageManager.class.getFields();
551        for (Field f: fields) {
552            if (f.getType() == int.class) {
553                int modifiers = f.getModifiers();
554                // only look at public final static fields.
555                if (((modifiers & Modifier.FINAL) != 0) &&
556                        ((modifiers & Modifier.PUBLIC) != 0) &&
557                        ((modifiers & Modifier.STATIC) != 0)) {
558                    String fieldName = f.getName();
559                    if (fieldName.startsWith("INSTALL_FAILED_") ||
560                            fieldName.startsWith("INSTALL_PARSE_FAILED_")) {
561                        // get the int value and compare it to result.
562                        try {
563                            if (result == f.getInt(null)) {
564                                return fieldName;
565                            }
566                        } catch (IllegalAccessException e) {
567                            // this shouldn't happen since we only look for public static fields.
568                        }
569                    }
570                }
571            }
572        }
573
574        // couldn't find a matching constant? return the value
575        return Integer.toString(result);
576    }
577
578    private void runInstall() {
579        int installFlags = 0;
580        String installerPackageName = null;
581
582        String opt;
583        while ((opt=nextOption()) != null) {
584            if (opt.equals("-l")) {
585                installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
586            } else if (opt.equals("-r")) {
587                installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
588            } else if (opt.equals("-i")) {
589                installerPackageName = nextOptionData();
590                if (installerPackageName == null) {
591                    System.err.println("Error: no value specified for -i");
592                    showUsage();
593                    return;
594                }
595            } else if (opt.equals("-t")) {
596                installFlags |= PackageManager.INSTALL_ALLOW_TEST;
597            } else {
598                System.err.println("Error: Unknown option: " + opt);
599                showUsage();
600                return;
601            }
602        }
603
604        String apkFilePath = nextArg();
605        System.err.println("\tpkg: " + apkFilePath);
606        if (apkFilePath == null) {
607            System.err.println("Error: no package specified");
608            showUsage();
609            return;
610        }
611
612        PackageInstallObserver obs = new PackageInstallObserver();
613        try {
614            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
615                    installerPackageName);
616
617            synchronized (obs) {
618                while (!obs.finished) {
619                    try {
620                        obs.wait();
621                    } catch (InterruptedException e) {
622                    }
623                }
624                if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
625                    System.out.println("Success");
626                } else {
627                    System.err.println("Failure ["
628                            + installFailureToString(obs.result)
629                            + "]");
630                }
631            }
632        } catch (RemoteException e) {
633            System.err.println(e.toString());
634            System.err.println(PM_NOT_RUNNING_ERR);
635        }
636    }
637
638    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
639        boolean finished;
640        boolean result;
641
642        public void packageDeleted(boolean succeeded) {
643            synchronized (this) {
644                finished = true;
645                result = succeeded;
646                notifyAll();
647            }
648        }
649    }
650
651    private void runUninstall() {
652        int unInstallFlags = 0;
653
654        String opt = nextOption();
655        if (opt != null && opt.equals("-k")) {
656            unInstallFlags = PackageManager.DONT_DELETE_DATA;
657        }
658
659        String pkg = nextArg();
660        if (pkg == null) {
661            System.err.println("Error: no package specified");
662            showUsage();
663            return;
664        }
665        boolean result = deletePackage(pkg, unInstallFlags);
666        if (result) {
667            System.out.println("Success");
668        } else {
669            System.out.println("Failure");
670        }
671    }
672
673    private boolean deletePackage(String pkg, int unInstallFlags) {
674        PackageDeleteObserver obs = new PackageDeleteObserver();
675        try {
676            mPm.deletePackage(pkg, obs, unInstallFlags);
677
678            synchronized (obs) {
679                while (!obs.finished) {
680                    try {
681                        obs.wait();
682                    } catch (InterruptedException e) {
683                    }
684                }
685            }
686        } catch (RemoteException e) {
687            System.err.println(e.toString());
688            System.err.println(PM_NOT_RUNNING_ERR);
689        }
690        return obs.result;
691    }
692
693    private static String enabledSettingToString(int state) {
694        switch (state) {
695            case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
696                return "default";
697            case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
698                return "enabled";
699            case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
700                return "disabled";
701        }
702        return "unknown";
703    }
704
705    private void runSetEnabledSetting(int state) {
706        String pkg = nextArg();
707        if (pkg == null) {
708            System.err.println("Error: no package or component specified");
709            showUsage();
710            return;
711        }
712        ComponentName cn = ComponentName.unflattenFromString(pkg);
713        if (cn == null) {
714            try {
715                mPm.setApplicationEnabledSetting(pkg, state, 0);
716                System.err.println("Package " + pkg + " new state: "
717                        + enabledSettingToString(
718                                mPm.getApplicationEnabledSetting(pkg)));
719            } catch (RemoteException e) {
720                System.err.println(e.toString());
721                System.err.println(PM_NOT_RUNNING_ERR);
722            }
723        } else {
724            try {
725                mPm.setComponentEnabledSetting(cn, state, 0);
726                System.err.println("Component " + cn.toShortString() + " new state: "
727                        + enabledSettingToString(
728                                mPm.getComponentEnabledSetting(cn)));
729            } catch (RemoteException e) {
730                System.err.println(e.toString());
731                System.err.println(PM_NOT_RUNNING_ERR);
732            }
733        }
734    }
735
736    /**
737     * Displays the package file for a package.
738     * @param pckg
739     */
740    private void displayPackageFilePath(String pckg) {
741        try {
742            PackageInfo info = mPm.getPackageInfo(pckg, 0);
743            if (info != null && info.applicationInfo != null) {
744                System.out.print("package:");
745                System.out.println(info.applicationInfo.sourceDir);
746            }
747        } catch (RemoteException e) {
748            System.err.println(e.toString());
749            System.err.println(PM_NOT_RUNNING_ERR);
750        }
751    }
752
753    private Resources getResources(PackageItemInfo pii) {
754        Resources res = mResourceCache.get(pii.packageName);
755        if (res != null) return res;
756
757        try {
758            ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0);
759            AssetManager am = new AssetManager();
760            am.addAssetPath(ai.publicSourceDir);
761            res = new Resources(am, null, null);
762            mResourceCache.put(pii.packageName, res);
763            return res;
764        } catch (RemoteException e) {
765            System.err.println(e.toString());
766            System.err.println(PM_NOT_RUNNING_ERR);
767            return null;
768        }
769    }
770
771    private String nextOption() {
772        if (mNextArg >= mArgs.length) {
773            return null;
774        }
775        String arg = mArgs[mNextArg];
776        if (!arg.startsWith("-")) {
777            return null;
778        }
779        mNextArg++;
780        if (arg.equals("--")) {
781            return null;
782        }
783        if (arg.length() > 1 && arg.charAt(1) != '-') {
784            if (arg.length() > 2) {
785                mCurArgData = arg.substring(2);
786                return arg.substring(0, 2);
787            } else {
788                mCurArgData = null;
789                return arg;
790            }
791        }
792        mCurArgData = null;
793        return arg;
794    }
795
796    private String nextOptionData() {
797        if (mCurArgData != null) {
798            return mCurArgData;
799        }
800        if (mNextArg >= mArgs.length) {
801            return null;
802        }
803        String data = mArgs[mNextArg];
804        mNextArg++;
805        return data;
806    }
807
808    private String nextArg() {
809        if (mNextArg >= mArgs.length) {
810            return null;
811        }
812        String arg = mArgs[mNextArg];
813        mNextArg++;
814        return arg;
815    }
816
817    private static void showUsage() {
818        System.err.println("usage: pm [list|path|install|uninstall]");
819        System.err.println("       pm list packages [-f]");
820        System.err.println("       pm list permission-groups");
821        System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
822        System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");
823        System.err.println("       pm list features");
824        System.err.println("       pm path PACKAGE");
825        System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] PATH");
826        System.err.println("       pm uninstall [-k] PACKAGE");
827        System.err.println("       pm enable PACKAGE_OR_COMPONENT");
828        System.err.println("       pm disable PACKAGE_OR_COMPONENT");
829        System.err.println("");
830        System.err.println("The list packages command prints all packages.  Options:");
831        System.err.println("  -f: see their associated file.");
832        System.err.println("");
833        System.err.println("The list permission-groups command prints all known");
834        System.err.println("permission groups.");
835        System.err.println("");
836        System.err.println("The list permissions command prints all known");
837        System.err.println("permissions, optionally only those in GROUP.  Options:");
838        System.err.println("  -g: organize by group.");
839        System.err.println("  -f: print all information.");
840        System.err.println("  -s: short summary.");
841        System.err.println("  -d: only list dangerous permissions.");
842        System.err.println("  -u: list only the permissions users will see.");
843        System.err.println("");
844        System.err.println("The list instrumentation command prints all instrumentations,");
845        System.err.println("or only those that target a specified package.  Options:");
846        System.err.println("  -f: see their associated file.");
847        System.err.println("");
848        System.err.println("The list features command prints all features of the system.");
849        System.err.println("");
850        System.err.println("The path command prints the path to the .apk of a package.");
851        System.err.println("");
852        System.err.println("The install command installs a package to the system.  Options:");
853        System.err.println("  -l: install the package with FORWARD_LOCK.");
854        System.err.println("  -r: reinstall an exisiting app, keeping its data.");
855        System.err.println("  -t: allow test .apks to be installed.");
856        System.err.println("  -i: specify the installer package name.");
857        System.err.println("");
858        System.err.println("The uninstall command removes a package from the system. Options:");
859        System.err.println("  -k: keep the data and cache directories around.");
860        System.err.println("after the package removal.");
861        System.err.println("");
862        System.err.println("The enable and disable commands change the enabled state of");
863        System.err.println("a given package or component (written as \"package/class\").");
864    }
865}
866