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