Pm.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.commands.pm;
18
19import android.content.pm.ApplicationInfo;
20import android.content.pm.IPackageDeleteObserver;
21import android.content.pm.IPackageInstallObserver;
22import android.content.pm.IPackageManager;
23import android.content.pm.PackageInfo;
24import android.content.pm.PackageItemInfo;
25import android.content.pm.PackageManager;
26import android.content.pm.PackageParser;
27import android.content.pm.PermissionGroupInfo;
28import android.content.pm.PermissionInfo;
29import android.content.res.AssetManager;
30import android.content.res.Resources;
31import android.net.Uri;
32import android.os.RemoteException;
33import android.os.ServiceManager;
34
35import java.io.File;
36import java.lang.ref.WeakReference;
37import java.util.ArrayList;
38import java.util.List;
39import java.util.WeakHashMap;
40
41public final class Pm {
42    IPackageManager mPm;
43
44    private WeakHashMap<String, Resources> mResourceCache
45            = new WeakHashMap<String, Resources>();
46
47    private String[] mArgs;
48    private int mNextArg;
49    private String mCurArgData;
50
51    public static void main(String[] args) {
52        new Pm().run(args);
53    }
54
55    public void run(String[] args) {
56        boolean validCommand = false;
57        if (args.length < 1) {
58            showUsage();
59            return;
60        }
61
62        mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
63        if (mPm == null) {
64            System.err.println("Error Type 1: Could not access the Package Manager!");
65            showUsage();
66            return;
67        }
68
69        mArgs = args;
70        String op = args[0];
71        mNextArg = 1;
72
73        if ("list".equals(op)) {
74            runList();
75            return;
76        }
77
78        if ("path".equals(op)) {
79            runPath();
80            return;
81        }
82
83        if ("install".equals(op)) {
84            runInstall();
85            return;
86        }
87
88        if ("uninstall".equals(op)) {
89            runUninstall();
90            return;
91        }
92
93        try {
94            if (args.length == 1) {
95                if (args[0].equalsIgnoreCase("-l")) {
96                    validCommand = true;
97                    runListPackages(false);
98                } else if (args[0].equalsIgnoreCase("-lf")){
99                    validCommand = true;
100                    runListPackages(true);
101                }
102            } else if (args.length == 2) {
103                if (args[0].equalsIgnoreCase("-p")) {
104                    validCommand = true;
105                    displayPackageFilePath(args[1]);
106                }
107            }
108        } finally {
109            if (validCommand == false) {
110                showUsage();
111            }
112        }
113    }
114
115    /**
116     * Execute the list sub-command.
117     */
118    private void runList() {
119        String type = nextArg();
120        if (type == null) {
121            System.err.println("Error: didn't specify type of data to list");
122            showUsage();
123            return;
124        }
125        if ("package".equals(type) || "packages".equals(type)) {
126            runListPackages(false);
127        } else if ("permission-groups".equals(type)) {
128            runListPermissionGroups();
129        } else if ("permissions".equals(type)) {
130            runListPermissions();
131        } else {
132            System.err.println("Error: unknown list type '" + type + "'");
133            showUsage();
134        }
135    }
136
137    /**
138     * Lists all the installed packages.
139     */
140    private void runListPackages(boolean showApplicationPackage) {
141        try {
142            String opt;
143            while ((opt=nextOption()) != null) {
144                if (opt.equals("-l")) {
145                    // old compat
146                } else if (opt.equals("-lf")) {
147                    showApplicationPackage = true;
148                } else if (opt.equals("-f")) {
149                    showApplicationPackage = true;
150                } else {
151                    System.err.println("Error: Unknown option: " + opt);
152                    showUsage();
153                    return;
154                }
155            }
156        } catch (RuntimeException ex) {
157            System.err.println("Error: " + ex.toString());
158            showUsage();
159            return;
160        }
161
162        try {
163            List<PackageInfo> packages = mPm.getInstalledPackages(0 /* all */);
164
165            int count = packages.size();
166            for (int p = 0 ; p < count ; p++) {
167                PackageInfo info = packages.get(p);
168                System.out.print("package:");
169                if (showApplicationPackage) {
170                    System.out.print(info.applicationInfo.sourceDir);
171                    System.out.print("=");
172                }
173                System.out.println(info.packageName);
174            }
175        } catch (RemoteException e) {
176        }
177    }
178
179    /**
180     * Lists all the known permission groups.
181     */
182    private void runListPermissionGroups() {
183        try {
184            List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0);
185
186            int count = pgs.size();
187            for (int p = 0 ; p < count ; p++) {
188                PermissionGroupInfo pgi = pgs.get(p);
189                System.out.print("permission group:");
190                System.out.println(pgi.name);
191            }
192        } catch (RemoteException e) {
193        }
194    }
195
196    private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) {
197        if (nonLocalized != null) {
198            return nonLocalized.toString();
199        }
200        Resources r = getResources(pii);
201        if (r != null) {
202            return r.getString(res);
203        }
204        return null;
205    }
206
207    /**
208     * Lists all the permissions in a group.
209     */
210    private void runListPermissions() {
211        try {
212            boolean labels = false;
213            boolean groups = false;
214            boolean userOnly = false;
215            boolean summary = false;
216            boolean dangerousOnly = false;
217            String opt;
218            while ((opt=nextOption()) != null) {
219                if (opt.equals("-f")) {
220                    labels = true;
221                } else if (opt.equals("-g")) {
222                    groups = true;
223                } else if (opt.equals("-s")) {
224                    groups = true;
225                    labels = true;
226                    summary = true;
227                } else if (opt.equals("-u")) {
228                    userOnly = true;
229                } else if (opt.equals("-d")) {
230                    dangerousOnly = true;
231                } else {
232                    System.err.println("Error: Unknown option: " + opt);
233                    showUsage();
234                    return;
235                }
236            }
237
238            String grp = nextOption();
239            ArrayList<String> groupList = new ArrayList<String>();
240            if (groups) {
241                List<PermissionGroupInfo> infos =
242                        mPm.getAllPermissionGroups(0);
243                for (int i=0; i<infos.size(); i++) {
244                    groupList.add(infos.get(i).name);
245                }
246                groupList.add(null);
247            } else {
248                groupList.add(grp);
249            }
250
251            if (dangerousOnly) {
252                System.out.println("Dangerous Permissions:");
253                System.out.println("");
254                doListPermissions(groupList, groups, labels, summary,
255                        PermissionInfo.PROTECTION_DANGEROUS,
256                        PermissionInfo.PROTECTION_DANGEROUS);
257                if (userOnly) {
258                    System.out.println("Normal Permissions:");
259                    System.out.println("");
260                    doListPermissions(groupList, groups, labels, summary,
261                            PermissionInfo.PROTECTION_NORMAL,
262                            PermissionInfo.PROTECTION_NORMAL);
263                }
264            } else if (userOnly) {
265                System.out.println("Dangerous and Normal Permissions:");
266                System.out.println("");
267                doListPermissions(groupList, groups, labels, summary,
268                        PermissionInfo.PROTECTION_NORMAL,
269                        PermissionInfo.PROTECTION_DANGEROUS);
270            } else {
271                System.out.println("All Permissions:");
272                System.out.println("");
273                doListPermissions(groupList, groups, labels, summary,
274                        -10000, 10000);
275            }
276        } catch (RemoteException e) {
277        }
278    }
279
280    private void doListPermissions(ArrayList<String> groupList,
281            boolean groups, boolean labels, boolean summary,
282            int startProtectionLevel, int endProtectionLevel)
283            throws RemoteException {
284        for (int i=0; i<groupList.size(); i++) {
285            String groupName = groupList.get(i);
286            String prefix = "";
287            if (groups) {
288                if (i > 0) System.out.println("");
289                if (groupName != null) {
290                    PermissionGroupInfo pgi = mPm.getPermissionGroupInfo(
291                            groupName, 0);
292                    if (summary) {
293                        Resources res = getResources(pgi);
294                        if (res != null) {
295                            System.out.print(loadText(pgi, pgi.labelRes,
296                                    pgi.nonLocalizedLabel) + ": ");
297                        } else {
298                            System.out.print(pgi.name + ": ");
299
300                        }
301                    } else {
302                        System.out.println((labels ? "+ " : "")
303                                + "group:" + pgi.name);
304                        if (labels) {
305                            System.out.println("  package:" + pgi.packageName);
306                            Resources res = getResources(pgi);
307                            if (res != null) {
308                                System.out.println("  label:"
309                                        + loadText(pgi, pgi.labelRes,
310                                                pgi.nonLocalizedLabel));
311                                System.out.println("  description:"
312                                        + loadText(pgi, pgi.descriptionRes,
313                                                pgi.nonLocalizedDescription));
314                            }
315                        }
316                    }
317                } else {
318                    System.out.println(((labels && !summary)
319                            ? "+ " : "") + "ungrouped:");
320                }
321                prefix = "  ";
322            }
323            List<PermissionInfo> ps = mPm.queryPermissionsByGroup(
324                    groupList.get(i), 0);
325            int count = ps.size();
326            boolean first = true;
327            for (int p = 0 ; p < count ; p++) {
328                PermissionInfo pi = ps.get(p);
329                if (groups && groupName == null && pi.group != null) {
330                    continue;
331                }
332                if (pi.protectionLevel < startProtectionLevel
333                        || pi.protectionLevel > endProtectionLevel) {
334                    continue;
335                }
336                if (summary) {
337                    if (first) {
338                        first = false;
339                    } else {
340                        System.out.print(", ");
341                    }
342                    Resources res = getResources(pi);
343                    if (res != null) {
344                        System.out.print(loadText(pi, pi.labelRes,
345                                pi.nonLocalizedLabel));
346                    } else {
347                        System.out.print(pi.name);
348                    }
349                } else {
350                    System.out.println(prefix + (labels ? "+ " : "")
351                            + "permission:" + pi.name);
352                    if (labels) {
353                        System.out.println(prefix + "  package:" + pi.packageName);
354                        Resources res = getResources(pi);
355                        if (res != null) {
356                            System.out.println(prefix + "  label:"
357                                    + loadText(pi, pi.labelRes,
358                                            pi.nonLocalizedLabel));
359                            System.out.println(prefix + "  description:"
360                                    + loadText(pi, pi.descriptionRes,
361                                            pi.nonLocalizedDescription));
362                        }
363                        String protLevel = "unknown";
364                        switch(pi.protectionLevel) {
365                            case PermissionInfo.PROTECTION_DANGEROUS:
366                                protLevel = "dangerous";
367                                break;
368                            case PermissionInfo.PROTECTION_NORMAL:
369                                protLevel = "normal";
370                                break;
371                            case PermissionInfo.PROTECTION_SIGNATURE:
372                                protLevel = "signature";
373                                break;
374                            case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:
375                                protLevel = "signatureOrSystem";
376                                break;
377                        }
378                        System.out.println(prefix + "  protectionLevel:" + protLevel);
379                    }
380                }
381            }
382
383            if (summary) {
384                System.out.println("");
385            }
386        }
387    }
388
389    private void runPath() {
390        String pkg = nextArg();
391        if (pkg == null) {
392            System.err.println("Error: no package specified");
393            showUsage();
394            return;
395        }
396        displayPackageFilePath(pkg);
397    }
398
399    class PackageInstallObserver extends IPackageInstallObserver.Stub {
400        boolean finished;
401        int result;
402
403        public void packageInstalled(String name, int status) {
404            synchronized( this) {
405                finished = true;
406                result = status;
407                notifyAll();
408            }
409        }
410    }
411
412    private String installFailureToString(int result) {
413        String s;
414        switch (result) {
415        case PackageManager.INSTALL_FAILED_ALREADY_EXISTS:
416            s = "INSTALL_FAILED_ALREADY_EXISTS";
417            break;
418        case PackageManager.INSTALL_FAILED_INVALID_APK:
419            s = "INSTALL_FAILED_INVALID_APK";
420            break;
421        case PackageManager.INSTALL_FAILED_INVALID_URI:
422            s = "INSTALL_FAILED_INVALID_URI";
423            break;
424        case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE:
425            s = "INSTALL_FAILED_INSUFFICIENT_STORAGE";
426            break;
427        case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE:
428            s = "INSTALL_FAILED_DUPLICATE_PACKAGE";
429            break;
430        case PackageManager.INSTALL_FAILED_NO_SHARED_USER:
431            s = "INSTALL_FAILED_NO_SHARED_USER";
432            break;
433        case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE:
434            s = "INSTALL_FAILED_UPDATE_INCOMPATIBLE";
435            break;
436        case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE:
437            s = "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE";
438            break;
439        case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY:
440            s = "INSTALL_FAILED_MISSING_SHARED_LIBRARY";
441            break;
442        case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE:
443            s = "INSTALL_FAILED_REPLACE_COULDNT_DELETE";
444            break;
445        case PackageManager.INSTALL_PARSE_FAILED_NOT_APK:
446            s = "INSTALL_PARSE_FAILED_NOT_APK";
447            break;
448        case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST:
449            s = "INSTALL_PARSE_FAILED_BAD_MANIFEST";
450            break;
451        case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION:
452            s = "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION";
453            break;
454        case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES:
455            s = "INSTALL_PARSE_FAILED_NO_CERTIFICATES";
456            break;
457        case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES:
458            s = "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES";
459            break;
460        case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING:
461            s = "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING";
462            break;
463        case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME:
464            s = "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME";
465            break;
466        case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID:
467            s = "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID";
468            break;
469        case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED:
470            s = "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED";
471            break;
472        case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY:
473            s = "INSTALL_PARSE_FAILED_MANIFEST_EMPTY";
474            break;
475        default:
476            s = Integer.toString(result);
477        break;
478        }
479        return s;
480    }
481
482    private void runInstall() {
483        int installFlags = 0;
484
485        String opt;
486        while ((opt=nextOption()) != null) {
487            if (opt.equals("-l")) {
488                installFlags |= PackageManager.FORWARD_LOCK_PACKAGE;
489            } else if (opt.equals("-r")) {
490                installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
491            } else {
492                System.err.println("Error: Unknown option: " + opt);
493                showUsage();
494                return;
495            }
496        }
497
498        String apkFilePath = nextArg();
499        System.err.println("\tpkg: " + apkFilePath);
500        if (apkFilePath == null) {
501            System.err.println("Error: no package specified");
502            showUsage();
503            return;
504        }
505
506        PackageInstallObserver obs = new PackageInstallObserver();
507        try {
508            mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags);
509
510            synchronized (obs) {
511                while (!obs.finished) {
512                    try {
513                        obs.wait();
514                    } catch (InterruptedException e) {
515                    }
516                }
517                if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
518                    System.out.println("Success");
519                } else {
520                    System.err.println("Failure ["
521                            + installFailureToString(obs.result)
522                            + "]");
523                }
524            }
525        } catch (RemoteException e) {
526        }
527    }
528
529    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
530        boolean finished;
531        boolean result;
532
533        public void packageDeleted(boolean succeeded) {
534            synchronized (this) {
535                finished = true;
536                result = succeeded;
537                notifyAll();
538            }
539        }
540    }
541
542    private void runUninstall() {
543        int unInstallFlags = 0;
544
545        String opt = nextOption();
546        if (opt != null && opt.equals("-k")) {
547            unInstallFlags = PackageManager.DONT_DELETE_DATA;
548        }
549
550        String pkg = nextArg();
551        if (pkg == null) {
552            System.err.println("Error: no package specified");
553            showUsage();
554            return;
555        }
556        boolean result = deletePackage(pkg, unInstallFlags);
557        if (result) {
558            System.out.println("Success");
559        } else {
560            System.out.println("Failure");
561        }
562    }
563
564    private boolean deletePackage(String pkg, int unInstallFlags) {
565        PackageDeleteObserver obs = new PackageDeleteObserver();
566        try {
567            mPm.deletePackage(pkg, obs, unInstallFlags);
568
569            synchronized (obs) {
570                while (!obs.finished) {
571                    try {
572                        obs.wait();
573                    } catch (InterruptedException e) {
574                    }
575                }
576            }
577        } catch (RemoteException e) {
578        }
579        return obs.result;
580    }
581
582    /**
583     * Displays the package file for a package.
584     * @param pckg
585     */
586    private void displayPackageFilePath(String pckg) {
587        try {
588            PackageInfo info = mPm.getPackageInfo(pckg, 0);
589            if (info != null && info.applicationInfo != null) {
590                System.out.print("package:");
591                System.out.println(info.applicationInfo.sourceDir);
592            }
593        } catch (RemoteException e) {
594        }
595    }
596
597    private Resources getResources(PackageItemInfo pii) {
598        Resources res = mResourceCache.get(pii.packageName);
599        if (res != null) return res;
600
601        try {
602            ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0);
603            AssetManager am = new AssetManager();
604            am.addAssetPath(ai.publicSourceDir);
605            res = new Resources(am, null, null);
606            mResourceCache.put(pii.packageName, res);
607            return res;
608        } catch (RemoteException e) {
609            System.err.println("Package manager gone!");
610            return null;
611        }
612    }
613
614    private String nextOption() {
615        if (mNextArg >= mArgs.length) {
616            return null;
617        }
618        String arg = mArgs[mNextArg];
619        if (!arg.startsWith("-")) {
620            return null;
621        }
622        mNextArg++;
623        if (arg.equals("--")) {
624            return null;
625        }
626        if (arg.length() > 1 && arg.charAt(1) != '-') {
627            if (arg.length() > 2) {
628                mCurArgData = arg.substring(2);
629                return arg.substring(0, 2);
630            } else {
631                mCurArgData = null;
632                return arg;
633            }
634        }
635        mCurArgData = null;
636        return arg;
637    }
638
639    private String nextOptionData() {
640        if (mCurArgData != null) {
641            return mCurArgData;
642        }
643        if (mNextArg >= mArgs.length) {
644            return null;
645        }
646        String data = mArgs[mNextArg];
647        mNextArg++;
648        return data;
649    }
650
651    private String nextArg() {
652        if (mNextArg >= mArgs.length) {
653            return null;
654        }
655        String arg = mArgs[mNextArg];
656        mNextArg++;
657        return arg;
658    }
659
660    private static void showUsage() {
661        System.err.println("usage: pm [list|path|install|uninstall]");
662        System.err.println("       pm list packages [-f]");
663        System.err.println("       pm list permission-groups");
664        System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
665        System.err.println("       pm path PACKAGE");
666        System.err.println("       pm install [-l] [-r] PATH");
667        System.err.println("       pm uninstall [-k] PACKAGE");
668        System.err.println("");
669        System.err.println("The list packages command prints all packages.  Use");
670        System.err.println("the -f option to see their associated file.");
671        System.err.println("");
672        System.err.println("The list permission-groups command prints all known");
673        System.err.println("permission groups.");
674        System.err.println("");
675        System.err.println("The list permissions command prints all known");
676        System.err.println("permissions, optionally only those in GROUP.  Use");
677        System.err.println("the -g option to organize by group.  Use");
678        System.err.println("the -f option to print all information.  Use");
679        System.err.println("the -s option for a short summary.  Use");
680        System.err.println("the -d option to only list dangerous permissions.  Use");
681        System.err.println("the -u option to list only the permissions users will see.");
682        System.err.println("");
683        System.err.println("The path command prints the path to the .apk of a package.");
684        System.err.println("");
685        System.err.println("The install command installs a package to the system.  Use");
686        System.err.println("the -l option to install the package with FORWARD_LOCK. Use");
687        System.err.println("the -r option to reinstall an exisiting app, keeping its data.");
688        System.err.println("");
689        System.err.println("The uninstall command removes a package from the system. Use");
690        System.err.println("the -k option to keep the data and cache directories around");
691        System.err.println("after the package removal.");
692    }
693}
694