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