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