PackageManagerShellCommand.java revision 4e8628157ad0c8c52e74b720eb0328086272ffda
1/*
2 * Copyright (C) 2015 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.server.pm;
18
19import android.app.ActivityManager;
20import android.content.ComponentName;
21import android.content.IIntentReceiver;
22import android.content.IIntentSender;
23import android.content.Intent;
24import android.content.IntentSender;
25import android.content.pm.ApplicationInfo;
26import android.content.pm.FeatureInfo;
27import android.content.pm.IPackageManager;
28import android.content.pm.InstrumentationInfo;
29import android.content.pm.PackageInfo;
30import android.content.pm.PackageInstaller;
31import android.content.pm.PackageItemInfo;
32import android.content.pm.PackageManager;
33import android.content.pm.PackageParser;
34import android.content.pm.PackageParser.ApkLite;
35import android.content.pm.PackageParser.PackageLite;
36import android.content.pm.PackageParser.PackageParserException;
37import android.content.pm.ParceledListSlice;
38import android.content.pm.PermissionGroupInfo;
39import android.content.pm.PermissionInfo;
40import android.content.pm.PackageInstaller.SessionInfo;
41import android.content.pm.PackageInstaller.SessionParams;
42import android.content.pm.ResolveInfo;
43import android.content.pm.VersionedPackage;
44import android.content.res.AssetManager;
45import android.content.res.Resources;
46import android.net.Uri;
47import android.os.Binder;
48import android.os.Build;
49import android.os.Bundle;
50import android.os.RemoteException;
51import android.os.ShellCommand;
52import android.os.SystemProperties;
53import android.os.UserHandle;
54import android.text.TextUtils;
55import android.util.ArraySet;
56import android.util.PrintWriterPrinter;
57import com.android.internal.content.PackageHelper;
58import com.android.internal.util.SizedInputStream;
59import com.android.server.SystemConfig;
60
61import dalvik.system.DexFile;
62
63import libcore.io.IoUtils;
64
65import java.io.File;
66import java.io.FileInputStream;
67import java.io.IOException;
68import java.io.InputStream;
69import java.io.OutputStream;
70import java.io.PrintWriter;
71import java.net.URISyntaxException;
72import java.util.ArrayList;
73import java.util.Collections;
74import java.util.Comparator;
75import java.util.List;
76import java.util.WeakHashMap;
77import java.util.concurrent.SynchronousQueue;
78import java.util.concurrent.TimeUnit;
79
80class PackageManagerShellCommand extends ShellCommand {
81    /** Path for streaming APK content */
82    private static final String STDIN_PATH = "-";
83    /** Whether or not APK content must be streamed from stdin */
84    private static final boolean FORCE_STREAM_INSTALL = true;
85
86    final IPackageManager mInterface;
87    final private WeakHashMap<String, Resources> mResourceCache =
88            new WeakHashMap<String, Resources>();
89    int mTargetUser;
90    boolean mBrief;
91    boolean mComponents;
92
93    PackageManagerShellCommand(PackageManagerService service) {
94        mInterface = service;
95    }
96
97    @Override
98    public int onCommand(String cmd) {
99        if (cmd == null) {
100            return handleDefaultCommands(cmd);
101        }
102
103        final PrintWriter pw = getOutPrintWriter();
104        try {
105            switch(cmd) {
106                case "install":
107                    return runInstall();
108                case "install-abandon":
109                case "install-destroy":
110                    return runInstallAbandon();
111                case "install-commit":
112                    return runInstallCommit();
113                case "install-create":
114                    return runInstallCreate();
115                case "install-remove":
116                    return runInstallRemove();
117                case "install-write":
118                    return runInstallWrite();
119                case "compile":
120                    return runCompile();
121                case "dump-profiles":
122                    return runDumpProfiles();
123                case "list":
124                    return runList();
125                case "uninstall":
126                    return runUninstall();
127                case "resolve-activity":
128                    return runResolveActivity();
129                case "query-activities":
130                    return runQueryIntentActivities();
131                case "query-services":
132                    return runQueryIntentServices();
133                case "query-receivers":
134                    return runQueryIntentReceivers();
135                case "suspend":
136                    return runSuspend(true);
137                case "unsuspend":
138                    return runSuspend(false);
139                case "set-home-activity":
140                    return runSetHomeActivity();
141                case "get-privapp-permissions":
142                    return runGetPrivappPermissions();
143                default:
144                    return handleDefaultCommands(cmd);
145            }
146        } catch (RemoteException e) {
147            pw.println("Remote exception: " + e);
148        }
149        return -1;
150    }
151
152    private void setParamsSize(InstallParams params, String inPath) {
153        // If we're forced to stream the package, the params size
154        // must be set via command-line argument. There's nothing
155        // to do here.
156        if (FORCE_STREAM_INSTALL) {
157            return;
158        }
159        final PrintWriter pw = getOutPrintWriter();
160        if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
161            File file = new File(inPath);
162            if (file.isFile()) {
163                try {
164                    ApkLite baseApk = PackageParser.parseApkLite(file, 0);
165                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null);
166                    params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
167                            pkgLite, false, params.sessionParams.abiOverride));
168                } catch (PackageParserException | IOException e) {
169                    pw.println("Error: Failed to parse APK file: " + file);
170                    throw new IllegalArgumentException(
171                            "Error: Failed to parse APK file: " + file, e);
172                }
173            } else {
174                pw.println("Error: Can't open non-file: " + inPath);
175                throw new IllegalArgumentException("Error: Can't open non-file: " + inPath);
176            }
177        }
178    }
179
180    private int runInstall() throws RemoteException {
181        final PrintWriter pw = getOutPrintWriter();
182        final InstallParams params = makeInstallParams();
183        final String inPath = getNextArg();
184
185        setParamsSize(params, inPath);
186        final int sessionId = doCreateSession(params.sessionParams,
187                params.installerPackageName, params.userId);
188        boolean abandonSession = true;
189        try {
190            if (inPath == null && params.sessionParams.sizeBytes == -1) {
191                pw.println("Error: must either specify a package size or an APK file");
192                return 1;
193            }
194            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
195                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
196                return 1;
197            }
198            if (doCommitSession(sessionId, false /*logSuccess*/)
199                    != PackageInstaller.STATUS_SUCCESS) {
200                return 1;
201            }
202            abandonSession = false;
203            pw.println("Success");
204            return 0;
205        } finally {
206            if (abandonSession) {
207                try {
208                    doAbandonSession(sessionId, false /*logSuccess*/);
209                } catch (Exception ignore) {
210                }
211            }
212        }
213    }
214
215    private int runSuspend(boolean suspendedState) {
216        final PrintWriter pw = getOutPrintWriter();
217        int userId = UserHandle.USER_SYSTEM;
218        String opt;
219        while ((opt = getNextOption()) != null) {
220            switch (opt) {
221                case "--user":
222                    userId = UserHandle.parseUserArg(getNextArgRequired());
223                    break;
224                default:
225                    pw.println("Error: Unknown option: " + opt);
226                    return 1;
227            }
228        }
229
230        String packageName = getNextArg();
231        if (packageName == null) {
232            pw.println("Error: package name not specified");
233            return 1;
234        }
235
236        try {
237            mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
238                    userId);
239            pw.println("Package " + packageName + " new suspended state: "
240                    + mInterface.isPackageSuspendedForUser(packageName, userId));
241            return 0;
242        } catch (RemoteException | IllegalArgumentException e) {
243            pw.println(e.toString());
244            return 1;
245        }
246    }
247
248    private int runInstallAbandon() throws RemoteException {
249        final int sessionId = Integer.parseInt(getNextArg());
250        return doAbandonSession(sessionId, true /*logSuccess*/);
251    }
252
253    private int runInstallCommit() throws RemoteException {
254        final int sessionId = Integer.parseInt(getNextArg());
255        return doCommitSession(sessionId, true /*logSuccess*/);
256    }
257
258    private int runInstallCreate() throws RemoteException {
259        final PrintWriter pw = getOutPrintWriter();
260        final InstallParams installParams = makeInstallParams();
261        final int sessionId = doCreateSession(installParams.sessionParams,
262                installParams.installerPackageName, installParams.userId);
263
264        // NOTE: adb depends on parsing this string
265        pw.println("Success: created install session [" + sessionId + "]");
266        return 0;
267    }
268
269    private int runInstallWrite() throws RemoteException {
270        long sizeBytes = -1;
271
272        String opt;
273        while ((opt = getNextOption()) != null) {
274            if (opt.equals("-S")) {
275                sizeBytes = Long.parseLong(getNextArg());
276            } else {
277                throw new IllegalArgumentException("Unknown option: " + opt);
278            }
279        }
280
281        final int sessionId = Integer.parseInt(getNextArg());
282        final String splitName = getNextArg();
283        final String path = getNextArg();
284        return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
285    }
286
287    private int runInstallRemove() throws RemoteException {
288        final PrintWriter pw = getOutPrintWriter();
289
290        final int sessionId = Integer.parseInt(getNextArg());
291
292        final String splitName = getNextArg();
293        if (splitName == null) {
294            pw.println("Error: split name not specified");
295            return 1;
296        }
297        return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
298    }
299
300    private int runCompile() throws RemoteException {
301        final PrintWriter pw = getOutPrintWriter();
302        boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
303        boolean forceCompilation = false;
304        boolean allPackages = false;
305        boolean clearProfileData = false;
306        String compilerFilter = null;
307        String compilationReason = null;
308        String checkProfilesRaw = null;
309
310        String opt;
311        while ((opt = getNextOption()) != null) {
312            switch (opt) {
313                case "-a":
314                    allPackages = true;
315                    break;
316                case "-c":
317                    clearProfileData = true;
318                    break;
319                case "-f":
320                    forceCompilation = true;
321                    break;
322                case "-m":
323                    compilerFilter = getNextArgRequired();
324                    break;
325                case "-r":
326                    compilationReason = getNextArgRequired();
327                    break;
328                case "--check-prof":
329                    checkProfilesRaw = getNextArgRequired();
330                    break;
331                case "--reset":
332                    forceCompilation = true;
333                    clearProfileData = true;
334                    compilationReason = "install";
335                    break;
336                default:
337                    pw.println("Error: Unknown option: " + opt);
338                    return 1;
339            }
340        }
341
342        if (checkProfilesRaw != null) {
343            if ("true".equals(checkProfilesRaw)) {
344                checkProfiles = true;
345            } else if ("false".equals(checkProfilesRaw)) {
346                checkProfiles = false;
347            } else {
348                pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
349                return 1;
350            }
351        }
352
353        if (compilerFilter != null && compilationReason != null) {
354            pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
355                    "at the same time");
356            return 1;
357        }
358        if (compilerFilter == null && compilationReason == null) {
359            pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
360                    "reason (\"-r\") at the same time");
361            return 1;
362        }
363
364        String targetCompilerFilter;
365        if (compilerFilter != null) {
366            if (!DexFile.isValidCompilerFilter(compilerFilter)) {
367                pw.println("Error: \"" + compilerFilter +
368                        "\" is not a valid compilation filter.");
369                return 1;
370            }
371            targetCompilerFilter = compilerFilter;
372        } else {
373            int reason = -1;
374            for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
375                if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
376                        compilationReason)) {
377                    reason = i;
378                    break;
379                }
380            }
381            if (reason == -1) {
382                pw.println("Error: Unknown compilation reason: " + compilationReason);
383                return 1;
384            }
385            targetCompilerFilter =
386                    PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
387        }
388
389
390        List<String> packageNames = null;
391        if (allPackages) {
392            packageNames = mInterface.getAllPackages();
393        } else {
394            String packageName = getNextArg();
395            if (packageName == null) {
396                pw.println("Error: package name not specified");
397                return 1;
398            }
399            packageNames = Collections.singletonList(packageName);
400        }
401
402        List<String> failedPackages = new ArrayList<>();
403        for (String packageName : packageNames) {
404            if (clearProfileData) {
405                mInterface.clearApplicationProfileData(packageName);
406            }
407
408            boolean result = mInterface.performDexOptMode(packageName,
409                    checkProfiles, targetCompilerFilter, forceCompilation);
410            if (!result) {
411                failedPackages.add(packageName);
412            }
413        }
414
415        if (failedPackages.isEmpty()) {
416            pw.println("Success");
417            return 0;
418        } else if (failedPackages.size() == 1) {
419            pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
420            return 1;
421        } else {
422            pw.print("Failure: the following packages could not be compiled: ");
423            boolean is_first = true;
424            for (String packageName : failedPackages) {
425                if (is_first) {
426                    is_first = false;
427                } else {
428                    pw.print(", ");
429                }
430                pw.print(packageName);
431            }
432            pw.println();
433            return 1;
434        }
435    }
436
437    private int runDumpProfiles() throws RemoteException {
438        String packageName = getNextArg();
439        mInterface.dumpProfiles(packageName);
440        return 0;
441    }
442
443    private int runList() throws RemoteException {
444        final PrintWriter pw = getOutPrintWriter();
445        final String type = getNextArg();
446        if (type == null) {
447            pw.println("Error: didn't specify type of data to list");
448            return -1;
449        }
450        switch(type) {
451            case "features":
452                return runListFeatures();
453            case "instrumentation":
454                return runListInstrumentation();
455            case "libraries":
456                return runListLibraries();
457            case "package":
458            case "packages":
459                return runListPackages(false /*showSourceDir*/);
460            case "permission-groups":
461                return runListPermissionGroups();
462            case "permissions":
463                return runListPermissions();
464        }
465        pw.println("Error: unknown list type '" + type + "'");
466        return -1;
467    }
468
469    private int runListFeatures() throws RemoteException {
470        final PrintWriter pw = getOutPrintWriter();
471        final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
472
473        // sort by name
474        Collections.sort(list, new Comparator<FeatureInfo>() {
475            public int compare(FeatureInfo o1, FeatureInfo o2) {
476                if (o1.name == o2.name) return 0;
477                if (o1.name == null) return -1;
478                if (o2.name == null) return 1;
479                return o1.name.compareTo(o2.name);
480            }
481        });
482
483        final int count = (list != null) ? list.size() : 0;
484        for (int p = 0; p < count; p++) {
485            FeatureInfo fi = list.get(p);
486            pw.print("feature:");
487            if (fi.name != null) {
488                pw.print(fi.name);
489                if (fi.version > 0) {
490                    pw.print("=");
491                    pw.print(fi.version);
492                }
493                pw.println();
494            } else {
495                pw.println("reqGlEsVersion=0x"
496                    + Integer.toHexString(fi.reqGlEsVersion));
497            }
498        }
499        return 0;
500    }
501
502    private int runListInstrumentation() throws RemoteException {
503        final PrintWriter pw = getOutPrintWriter();
504        boolean showSourceDir = false;
505        String targetPackage = null;
506
507        try {
508            String opt;
509            while ((opt = getNextArg()) != null) {
510                switch (opt) {
511                    case "-f":
512                        showSourceDir = true;
513                        break;
514                    default:
515                        if (opt.charAt(0) != '-') {
516                            targetPackage = opt;
517                        } else {
518                            pw.println("Error: Unknown option: " + opt);
519                            return -1;
520                        }
521                        break;
522                }
523            }
524        } catch (RuntimeException ex) {
525            pw.println("Error: " + ex.toString());
526            return -1;
527        }
528
529        final List<InstrumentationInfo> list =
530                mInterface.queryInstrumentation(targetPackage, 0 /*flags*/).getList();
531
532        // sort by target package
533        Collections.sort(list, new Comparator<InstrumentationInfo>() {
534            public int compare(InstrumentationInfo o1, InstrumentationInfo o2) {
535                return o1.targetPackage.compareTo(o2.targetPackage);
536            }
537        });
538
539        final int count = (list != null) ? list.size() : 0;
540        for (int p = 0; p < count; p++) {
541            final InstrumentationInfo ii = list.get(p);
542            pw.print("instrumentation:");
543            if (showSourceDir) {
544                pw.print(ii.sourceDir);
545                pw.print("=");
546            }
547            final ComponentName cn = new ComponentName(ii.packageName, ii.name);
548            pw.print(cn.flattenToShortString());
549            pw.print(" (target=");
550            pw.print(ii.targetPackage);
551            pw.println(")");
552        }
553        return 0;
554    }
555
556    private int runListLibraries() throws RemoteException {
557        final PrintWriter pw = getOutPrintWriter();
558        final List<String> list = new ArrayList<String>();
559        final String[] rawList = mInterface.getSystemSharedLibraryNames();
560        for (int i = 0; i < rawList.length; i++) {
561            list.add(rawList[i]);
562        }
563
564        // sort by name
565        Collections.sort(list, new Comparator<String>() {
566            public int compare(String o1, String o2) {
567                if (o1 == o2) return 0;
568                if (o1 == null) return -1;
569                if (o2 == null) return 1;
570                return o1.compareTo(o2);
571            }
572        });
573
574        final int count = (list != null) ? list.size() : 0;
575        for (int p = 0; p < count; p++) {
576            String lib = list.get(p);
577            pw.print("library:");
578            pw.println(lib);
579        }
580        return 0;
581    }
582
583    private int runListPackages(boolean showSourceDir) throws RemoteException {
584        final PrintWriter pw = getOutPrintWriter();
585        int getFlags = 0;
586        boolean listDisabled = false, listEnabled = false;
587        boolean listSystem = false, listThirdParty = false;
588        boolean listInstaller = false;
589        boolean showUid = false;
590        boolean showVersionCode = false;
591        int uid = -1;
592        int userId = UserHandle.USER_SYSTEM;
593        try {
594            String opt;
595            while ((opt = getNextOption()) != null) {
596                switch (opt) {
597                    case "-d":
598                        listDisabled = true;
599                        break;
600                    case "-e":
601                        listEnabled = true;
602                        break;
603                    case "-f":
604                        showSourceDir = true;
605                        break;
606                    case "-i":
607                        listInstaller = true;
608                        break;
609                    case "-l":
610                        // old compat
611                        break;
612                    case "-s":
613                        listSystem = true;
614                        break;
615                    case "-U":
616                        showUid = true;
617                        break;
618                    case "-u":
619                        getFlags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
620                        break;
621                    case "-3":
622                        listThirdParty = true;
623                        break;
624                    case "--show-versioncode":
625                        showVersionCode = true;
626                        break;
627                    case "--user":
628                        userId = UserHandle.parseUserArg(getNextArgRequired());
629                        break;
630                    case "--uid":
631                        showUid = true;
632                        uid = Integer.parseInt(getNextArgRequired());
633                        break;
634                    default:
635                        pw.println("Error: Unknown option: " + opt);
636                        return -1;
637                }
638            }
639        } catch (RuntimeException ex) {
640            pw.println("Error: " + ex.toString());
641            return -1;
642        }
643
644        final String filter = getNextArg();
645
646        @SuppressWarnings("unchecked")
647        final ParceledListSlice<PackageInfo> slice =
648                mInterface.getInstalledPackages(getFlags, userId);
649        final List<PackageInfo> packages = slice.getList();
650
651        final int count = packages.size();
652        for (int p = 0; p < count; p++) {
653            final PackageInfo info = packages.get(p);
654            if (filter != null && !info.packageName.contains(filter)) {
655                continue;
656            }
657            if (uid != -1 && info.applicationInfo.uid != uid) {
658                continue;
659            }
660            final boolean isSystem =
661                    (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0;
662            if ((!listDisabled || !info.applicationInfo.enabled) &&
663                    (!listEnabled || info.applicationInfo.enabled) &&
664                    (!listSystem || isSystem) &&
665                    (!listThirdParty || !isSystem)) {
666                pw.print("package:");
667                if (showSourceDir) {
668                    pw.print(info.applicationInfo.sourceDir);
669                    pw.print("=");
670                }
671                pw.print(info.packageName);
672                if (showVersionCode) {
673                    pw.print(" versionCode:");
674                    pw.print(info.applicationInfo.versionCode);
675                }
676                if (listInstaller) {
677                    pw.print("  installer=");
678                    pw.print(mInterface.getInstallerPackageName(info.packageName));
679                }
680                if (showUid) {
681                    pw.print(" uid:");
682                    pw.print(info.applicationInfo.uid);
683                }
684                pw.println();
685            }
686        }
687        return 0;
688    }
689
690    private int runListPermissionGroups() throws RemoteException {
691        final PrintWriter pw = getOutPrintWriter();
692        final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0).getList();
693
694        final int count = pgs.size();
695        for (int p = 0; p < count ; p++) {
696            final PermissionGroupInfo pgi = pgs.get(p);
697            pw.print("permission group:");
698            pw.println(pgi.name);
699        }
700        return 0;
701    }
702
703    private int runListPermissions() throws RemoteException {
704        final PrintWriter pw = getOutPrintWriter();
705        boolean labels = false;
706        boolean groups = false;
707        boolean userOnly = false;
708        boolean summary = false;
709        boolean dangerousOnly = false;
710        String opt;
711        while ((opt = getNextOption()) != null) {
712            switch (opt) {
713                case "-d":
714                    dangerousOnly = true;
715                    break;
716                case "-f":
717                    labels = true;
718                    break;
719                case "-g":
720                    groups = true;
721                    break;
722                case "-s":
723                    groups = true;
724                    labels = true;
725                    summary = true;
726                    break;
727                case "-u":
728                    userOnly = true;
729                    break;
730                default:
731                    pw.println("Error: Unknown option: " + opt);
732                    return 1;
733            }
734        }
735
736        final ArrayList<String> groupList = new ArrayList<String>();
737        if (groups) {
738            final List<PermissionGroupInfo> infos =
739                    mInterface.getAllPermissionGroups(0 /*flags*/).getList();
740            final int count = infos.size();
741            for (int i = 0; i < count; i++) {
742                groupList.add(infos.get(i).name);
743            }
744            groupList.add(null);
745        } else {
746            final String grp = getNextArg();
747            groupList.add(grp);
748        }
749
750        if (dangerousOnly) {
751            pw.println("Dangerous Permissions:");
752            pw.println("");
753            doListPermissions(groupList, groups, labels, summary,
754                    PermissionInfo.PROTECTION_DANGEROUS,
755                    PermissionInfo.PROTECTION_DANGEROUS);
756            if (userOnly) {
757                pw.println("Normal Permissions:");
758                pw.println("");
759                doListPermissions(groupList, groups, labels, summary,
760                        PermissionInfo.PROTECTION_NORMAL,
761                        PermissionInfo.PROTECTION_NORMAL);
762            }
763        } else if (userOnly) {
764            pw.println("Dangerous and Normal Permissions:");
765            pw.println("");
766            doListPermissions(groupList, groups, labels, summary,
767                    PermissionInfo.PROTECTION_NORMAL,
768                    PermissionInfo.PROTECTION_DANGEROUS);
769        } else {
770            pw.println("All Permissions:");
771            pw.println("");
772            doListPermissions(groupList, groups, labels, summary,
773                    -10000, 10000);
774        }
775        return 0;
776    }
777
778    private int runUninstall() throws RemoteException {
779        final PrintWriter pw = getOutPrintWriter();
780        int flags = 0;
781        int userId = UserHandle.USER_ALL;
782        int versionCode = PackageManager.VERSION_CODE_HIGHEST;
783
784        String opt;
785        while ((opt = getNextOption()) != null) {
786            switch (opt) {
787                case "-k":
788                    flags |= PackageManager.DELETE_KEEP_DATA;
789                    break;
790                case "--user":
791                    userId = UserHandle.parseUserArg(getNextArgRequired());
792                    break;
793                case "--versionCode":
794                    versionCode = Integer.parseInt(getNextArgRequired());
795                    break;
796                default:
797                    pw.println("Error: Unknown option: " + opt);
798                    return 1;
799            }
800        }
801
802        final String packageName = getNextArg();
803        if (packageName == null) {
804            pw.println("Error: package name not specified");
805            return 1;
806        }
807
808        // if a split is specified, just remove it and not the whole package
809        final String splitName = getNextArg();
810        if (splitName != null) {
811            return runRemoveSplit(packageName, splitName);
812        }
813
814        userId = translateUserId(userId, "runUninstall");
815        if (userId == UserHandle.USER_ALL) {
816            userId = UserHandle.USER_SYSTEM;
817            flags |= PackageManager.DELETE_ALL_USERS;
818        } else {
819            final PackageInfo info = mInterface.getPackageInfo(packageName, 0, userId);
820            if (info == null) {
821                pw.println("Failure [not installed for " + userId + "]");
822                return 1;
823            }
824            final boolean isSystem =
825                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
826            // If we are being asked to delete a system app for just one
827            // user set flag so it disables rather than reverting to system
828            // version of the app.
829            if (isSystem) {
830                flags |= PackageManager.DELETE_SYSTEM_APP;
831            }
832        }
833
834        final LocalIntentReceiver receiver = new LocalIntentReceiver();
835        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
836                versionCode), null /*callerPackageName*/, flags,
837                receiver.getIntentSender(), userId);
838
839        final Intent result = receiver.getResult();
840        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
841                PackageInstaller.STATUS_FAILURE);
842        if (status == PackageInstaller.STATUS_SUCCESS) {
843            pw.println("Success");
844            return 0;
845        } else {
846            pw.println("Failure ["
847                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
848            return 1;
849        }
850    }
851
852    private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
853        final PrintWriter pw = getOutPrintWriter();
854        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
855        sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
856        sessionParams.appPackageName = packageName;
857        final int sessionId =
858                doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
859        boolean abandonSession = true;
860        try {
861            if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
862                    != PackageInstaller.STATUS_SUCCESS) {
863                return 1;
864            }
865            if (doCommitSession(sessionId, false /*logSuccess*/)
866                    != PackageInstaller.STATUS_SUCCESS) {
867                return 1;
868            }
869            abandonSession = false;
870            pw.println("Success");
871            return 0;
872        } finally {
873            if (abandonSession) {
874                try {
875                    doAbandonSession(sessionId, false /*logSuccess*/);
876                } catch (Exception ignore) {
877                }
878            }
879        }
880    }
881
882    private Intent parseIntentAndUser() throws URISyntaxException {
883        mTargetUser = UserHandle.USER_CURRENT;
884        mBrief = false;
885        mComponents = false;
886        Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
887            @Override
888            public boolean handleOption(String opt, ShellCommand cmd) {
889                if ("--user".equals(opt)) {
890                    mTargetUser = UserHandle.parseUserArg(cmd.getNextArgRequired());
891                    return true;
892                } else if ("--brief".equals(opt)) {
893                    mBrief = true;
894                    return true;
895                } else if ("--components".equals(opt)) {
896                    mComponents = true;
897                    return true;
898                }
899                return false;
900            }
901        });
902        mTargetUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
903                Binder.getCallingUid(), mTargetUser, false, false, null, null);
904        return intent;
905    }
906
907    private void printResolveInfo(PrintWriterPrinter pr, String prefix, ResolveInfo ri,
908            boolean brief, boolean components) {
909        if (brief || components) {
910            final ComponentName comp;
911            if (ri.activityInfo != null) {
912                comp = new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
913            } else if (ri.serviceInfo != null) {
914                comp = new ComponentName(ri.serviceInfo.packageName, ri.serviceInfo.name);
915            } else if (ri.providerInfo != null) {
916                comp = new ComponentName(ri.providerInfo.packageName, ri.providerInfo.name);
917            } else {
918                comp = null;
919            }
920            if (comp != null) {
921                if (!components) {
922                    pr.println(prefix + "priority=" + ri.priority
923                            + " preferredOrder=" + ri.preferredOrder
924                            + " match=0x" + Integer.toHexString(ri.match)
925                            + " specificIndex=" + ri.specificIndex
926                            + " isDefault=" + ri.isDefault);
927                }
928                pr.println(prefix + comp.flattenToShortString());
929                return;
930            }
931        }
932        ri.dump(pr, prefix);
933    }
934
935    private int runResolveActivity() {
936        Intent intent;
937        try {
938            intent = parseIntentAndUser();
939        } catch (URISyntaxException e) {
940            throw new RuntimeException(e.getMessage(), e);
941        }
942        try {
943            ResolveInfo ri = mInterface.resolveIntent(intent, null, 0, mTargetUser);
944            PrintWriter pw = getOutPrintWriter();
945            if (ri == null) {
946                pw.println("No activity found");
947            } else {
948                PrintWriterPrinter pr = new PrintWriterPrinter(pw);
949                printResolveInfo(pr, "", ri, mBrief, mComponents);
950            }
951        } catch (RemoteException e) {
952            throw new RuntimeException("Failed calling service", e);
953        }
954        return 0;
955    }
956
957    private int runQueryIntentActivities() {
958        Intent intent;
959        try {
960            intent = parseIntentAndUser();
961        } catch (URISyntaxException e) {
962            throw new RuntimeException(e.getMessage(), e);
963        }
964        try {
965            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, null, 0,
966                    mTargetUser).getList();
967            PrintWriter pw = getOutPrintWriter();
968            if (result == null || result.size() <= 0) {
969                pw.println("No activities found");
970            } else {
971                if (!mComponents) {
972                    pw.print(result.size()); pw.println(" activities found:");
973                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
974                    for (int i = 0; i < result.size(); i++) {
975                        pw.print("  Activity #"); pw.print(i); pw.println(":");
976                        printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
977                    }
978                } else {
979                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
980                    for (int i = 0; i < result.size(); i++) {
981                        printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
982                    }
983                }
984            }
985        } catch (RemoteException e) {
986            throw new RuntimeException("Failed calling service", e);
987        }
988        return 0;
989    }
990
991    private int runQueryIntentServices() {
992        Intent intent;
993        try {
994            intent = parseIntentAndUser();
995        } catch (URISyntaxException e) {
996            throw new RuntimeException(e.getMessage(), e);
997        }
998        try {
999            List<ResolveInfo> result = mInterface.queryIntentServices(intent, null, 0,
1000                    mTargetUser).getList();
1001            PrintWriter pw = getOutPrintWriter();
1002            if (result == null || result.size() <= 0) {
1003                pw.println("No services found");
1004            } else {
1005                if (!mComponents) {
1006                    pw.print(result.size()); pw.println(" services found:");
1007                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1008                    for (int i = 0; i < result.size(); i++) {
1009                        pw.print("  Service #"); pw.print(i); pw.println(":");
1010                        printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1011                    }
1012                } else {
1013                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1014                    for (int i = 0; i < result.size(); i++) {
1015                        printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1016                    }
1017                }
1018            }
1019        } catch (RemoteException e) {
1020            throw new RuntimeException("Failed calling service", e);
1021        }
1022        return 0;
1023    }
1024
1025    private int runQueryIntentReceivers() {
1026        Intent intent;
1027        try {
1028            intent = parseIntentAndUser();
1029        } catch (URISyntaxException e) {
1030            throw new RuntimeException(e.getMessage(), e);
1031        }
1032        try {
1033            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, null, 0,
1034                    mTargetUser).getList();
1035            PrintWriter pw = getOutPrintWriter();
1036            if (result == null || result.size() <= 0) {
1037                pw.println("No receivers found");
1038            } else {
1039                if (!mComponents) {
1040                    pw.print(result.size()); pw.println(" receivers found:");
1041                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1042                    for (int i = 0; i < result.size(); i++) {
1043                        pw.print("  Receiver #"); pw.print(i); pw.println(":");
1044                        printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1045                    }
1046                } else {
1047                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1048                    for (int i = 0; i < result.size(); i++) {
1049                        printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1050                    }
1051                }
1052            }
1053        } catch (RemoteException e) {
1054            throw new RuntimeException("Failed calling service", e);
1055        }
1056        return 0;
1057    }
1058
1059    private static class InstallParams {
1060        SessionParams sessionParams;
1061        String installerPackageName;
1062        int userId = UserHandle.USER_ALL;
1063    }
1064
1065    private InstallParams makeInstallParams() {
1066        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
1067        final InstallParams params = new InstallParams();
1068        params.sessionParams = sessionParams;
1069        String opt;
1070        while ((opt = getNextOption()) != null) {
1071            switch (opt) {
1072                case "-l":
1073                    sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
1074                    break;
1075                case "-r":
1076                    sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
1077                    break;
1078                case "-i":
1079                    params.installerPackageName = getNextArg();
1080                    if (params.installerPackageName == null) {
1081                        throw new IllegalArgumentException("Missing installer package");
1082                    }
1083                    break;
1084                case "-t":
1085                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
1086                    break;
1087                case "-s":
1088                    sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL;
1089                    break;
1090                case "-f":
1091                    sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
1092                    break;
1093                case "-d":
1094                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
1095                    break;
1096                case "-g":
1097                    sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
1098                    break;
1099                case "--dont-kill":
1100                    sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
1101                    break;
1102                case "--originating-uri":
1103                    sessionParams.originatingUri = Uri.parse(getNextArg());
1104                    break;
1105                case "--referrer":
1106                    sessionParams.referrerUri = Uri.parse(getNextArg());
1107                    break;
1108                case "-p":
1109                    sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
1110                    sessionParams.appPackageName = getNextArg();
1111                    if (sessionParams.appPackageName == null) {
1112                        throw new IllegalArgumentException("Missing inherit package name");
1113                    }
1114                    break;
1115                case "-S":
1116                    final long sizeBytes = Long.parseLong(getNextArg());
1117                    if (sizeBytes <= 0) {
1118                        throw new IllegalArgumentException("Size must be positive");
1119                    }
1120                    sessionParams.setSize(sizeBytes);
1121                    break;
1122                case "--abi":
1123                    sessionParams.abiOverride = checkAbiArgument(getNextArg());
1124                    break;
1125                case "--ephemeral":
1126                    sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
1127                    break;
1128                case "--user":
1129                    params.userId = UserHandle.parseUserArg(getNextArgRequired());
1130                    break;
1131                case "--install-location":
1132                    sessionParams.installLocation = Integer.parseInt(getNextArg());
1133                    break;
1134                case "--force-uuid":
1135                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
1136                    sessionParams.volumeUuid = getNextArg();
1137                    if ("internal".equals(sessionParams.volumeUuid)) {
1138                        sessionParams.volumeUuid = null;
1139                    }
1140                    break;
1141                case "--force-sdk":
1142                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
1143                    break;
1144                default:
1145                    throw new IllegalArgumentException("Unknown option " + opt);
1146            }
1147        }
1148        return params;
1149    }
1150
1151    private int runSetHomeActivity() {
1152        final PrintWriter pw = getOutPrintWriter();
1153        int userId = UserHandle.USER_SYSTEM;
1154        String opt;
1155        while ((opt = getNextOption()) != null) {
1156            switch (opt) {
1157                case "--user":
1158                    userId = UserHandle.parseUserArg(getNextArgRequired());
1159                    break;
1160                default:
1161                    pw.println("Error: Unknown option: " + opt);
1162                    return 1;
1163            }
1164        }
1165
1166        String component = getNextArg();
1167        ComponentName componentName =
1168                component != null ? ComponentName.unflattenFromString(component) : null;
1169
1170        if (componentName == null) {
1171            pw.println("Error: component name not specified or invalid");
1172            return 1;
1173        }
1174
1175        try {
1176            mInterface.setHomeActivity(componentName, userId);
1177            pw.println("Success");
1178            return 0;
1179        } catch (Exception e) {
1180            pw.println(e.toString());
1181            return 1;
1182        }
1183    }
1184
1185    private int runGetPrivappPermissions() {
1186        final String pkg = getNextArg();
1187        if (pkg == null) {
1188            System.err.println("Error: no package specified.");
1189            return 1;
1190        }
1191        ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
1192        getOutPrintWriter().println(privAppPermissions == null
1193                ? "{}" : privAppPermissions.toString());
1194        return 0;
1195    }
1196
1197    private static String checkAbiArgument(String abi) {
1198        if (TextUtils.isEmpty(abi)) {
1199            throw new IllegalArgumentException("Missing ABI argument");
1200        }
1201
1202        if ("-".equals(abi)) {
1203            return abi;
1204        }
1205
1206        final String[] supportedAbis = Build.SUPPORTED_ABIS;
1207        for (String supportedAbi : supportedAbis) {
1208            if (supportedAbi.equals(abi)) {
1209                return abi;
1210            }
1211        }
1212
1213        throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
1214    }
1215
1216    private int translateUserId(int userId, String logContext) {
1217        return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1218                userId, true, true, logContext, "pm command");
1219    }
1220
1221    private int doCreateSession(SessionParams params, String installerPackageName, int userId)
1222            throws RemoteException {
1223        userId = translateUserId(userId, "runInstallCreate");
1224        if (userId == UserHandle.USER_ALL) {
1225            userId = UserHandle.USER_SYSTEM;
1226            params.installFlags |= PackageManager.INSTALL_ALL_USERS;
1227        }
1228
1229        final int sessionId = mInterface.getPackageInstaller()
1230                .createSession(params, installerPackageName, userId);
1231        return sessionId;
1232    }
1233
1234    private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
1235            boolean logSuccess) throws RemoteException {
1236        final PrintWriter pw = getOutPrintWriter();
1237        if (FORCE_STREAM_INSTALL && inPath != null && !STDIN_PATH.equals(inPath)) {
1238            pw.println("Error: APK content must be streamed");
1239            return 1;
1240        }
1241        if (STDIN_PATH.equals(inPath)) {
1242            inPath = null;
1243        } else if (inPath != null) {
1244            final File file = new File(inPath);
1245            if (file.isFile()) {
1246                sizeBytes = file.length();
1247            }
1248        }
1249        if (sizeBytes <= 0) {
1250            pw.println("Error: must specify a APK size");
1251            return 1;
1252        }
1253
1254        final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
1255
1256        PackageInstaller.Session session = null;
1257        InputStream in = null;
1258        OutputStream out = null;
1259        try {
1260            session = new PackageInstaller.Session(
1261                    mInterface.getPackageInstaller().openSession(sessionId));
1262
1263            if (inPath != null) {
1264                in = new FileInputStream(inPath);
1265            } else {
1266                in = new SizedInputStream(getRawInputStream(), sizeBytes);
1267            }
1268            out = session.openWrite(splitName, 0, sizeBytes);
1269
1270            int total = 0;
1271            byte[] buffer = new byte[65536];
1272            int c;
1273            while ((c = in.read(buffer)) != -1) {
1274                total += c;
1275                out.write(buffer, 0, c);
1276
1277                if (info.sizeBytes > 0) {
1278                    final float fraction = ((float) c / (float) info.sizeBytes);
1279                    session.addProgress(fraction);
1280                }
1281            }
1282            session.fsync(out);
1283
1284            if (logSuccess) {
1285                pw.println("Success: streamed " + total + " bytes");
1286            }
1287            return 0;
1288        } catch (IOException e) {
1289            pw.println("Error: failed to write; " + e.getMessage());
1290            return 1;
1291        } finally {
1292            IoUtils.closeQuietly(out);
1293            IoUtils.closeQuietly(in);
1294            IoUtils.closeQuietly(session);
1295        }
1296    }
1297
1298    private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
1299            throws RemoteException {
1300        final PrintWriter pw = getOutPrintWriter();
1301        PackageInstaller.Session session = null;
1302        try {
1303            session = new PackageInstaller.Session(
1304                    mInterface.getPackageInstaller().openSession(sessionId));
1305            session.removeSplit(splitName);
1306
1307            if (logSuccess) {
1308                pw.println("Success");
1309            }
1310            return 0;
1311        } catch (IOException e) {
1312            pw.println("Error: failed to remove split; " + e.getMessage());
1313            return 1;
1314        } finally {
1315            IoUtils.closeQuietly(session);
1316        }
1317    }
1318
1319    private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
1320        final PrintWriter pw = getOutPrintWriter();
1321        PackageInstaller.Session session = null;
1322        try {
1323            session = new PackageInstaller.Session(
1324                    mInterface.getPackageInstaller().openSession(sessionId));
1325
1326            final LocalIntentReceiver receiver = new LocalIntentReceiver();
1327            session.commit(receiver.getIntentSender());
1328
1329            final Intent result = receiver.getResult();
1330            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
1331                    PackageInstaller.STATUS_FAILURE);
1332            if (status == PackageInstaller.STATUS_SUCCESS) {
1333                if (logSuccess) {
1334                    pw.println("Success");
1335                }
1336            } else {
1337                pw.println("Failure ["
1338                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
1339            }
1340            return status;
1341        } finally {
1342            IoUtils.closeQuietly(session);
1343        }
1344    }
1345
1346    private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
1347        final PrintWriter pw = getOutPrintWriter();
1348        PackageInstaller.Session session = null;
1349        try {
1350            session = new PackageInstaller.Session(
1351                    mInterface.getPackageInstaller().openSession(sessionId));
1352            session.abandon();
1353            if (logSuccess) {
1354                pw.println("Success");
1355            }
1356            return 0;
1357        } finally {
1358            IoUtils.closeQuietly(session);
1359        }
1360    }
1361
1362    private void doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels,
1363            boolean summary, int startProtectionLevel, int endProtectionLevel)
1364                    throws RemoteException {
1365        final PrintWriter pw = getOutPrintWriter();
1366        final int groupCount = groupList.size();
1367        for (int i = 0; i < groupCount; i++) {
1368            String groupName = groupList.get(i);
1369            String prefix = "";
1370            if (groups) {
1371                if (i > 0) {
1372                    pw.println("");
1373                }
1374                if (groupName != null) {
1375                    PermissionGroupInfo pgi =
1376                            mInterface.getPermissionGroupInfo(groupName, 0 /*flags*/);
1377                    if (summary) {
1378                        Resources res = getResources(pgi);
1379                        if (res != null) {
1380                            pw.print(loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel) + ": ");
1381                        } else {
1382                            pw.print(pgi.name + ": ");
1383
1384                        }
1385                    } else {
1386                        pw.println((labels ? "+ " : "") + "group:" + pgi.name);
1387                        if (labels) {
1388                            pw.println("  package:" + pgi.packageName);
1389                            Resources res = getResources(pgi);
1390                            if (res != null) {
1391                                pw.println("  label:"
1392                                        + loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel));
1393                                pw.println("  description:"
1394                                        + loadText(pgi, pgi.descriptionRes,
1395                                                pgi.nonLocalizedDescription));
1396                            }
1397                        }
1398                    }
1399                } else {
1400                    pw.println(((labels && !summary) ? "+ " : "") + "ungrouped:");
1401                }
1402                prefix = "  ";
1403            }
1404            List<PermissionInfo> ps =
1405                    mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
1406            final int count = ps.size();
1407            boolean first = true;
1408            for (int p = 0 ; p < count ; p++) {
1409                PermissionInfo pi = ps.get(p);
1410                if (groups && groupName == null && pi.group != null) {
1411                    continue;
1412                }
1413                final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
1414                if (base < startProtectionLevel
1415                        || base > endProtectionLevel) {
1416                    continue;
1417                }
1418                if (summary) {
1419                    if (first) {
1420                        first = false;
1421                    } else {
1422                        pw.print(", ");
1423                    }
1424                    Resources res = getResources(pi);
1425                    if (res != null) {
1426                        pw.print(loadText(pi, pi.labelRes,
1427                                pi.nonLocalizedLabel));
1428                    } else {
1429                        pw.print(pi.name);
1430                    }
1431                } else {
1432                    pw.println(prefix + (labels ? "+ " : "")
1433                            + "permission:" + pi.name);
1434                    if (labels) {
1435                        pw.println(prefix + "  package:" + pi.packageName);
1436                        Resources res = getResources(pi);
1437                        if (res != null) {
1438                            pw.println(prefix + "  label:"
1439                                    + loadText(pi, pi.labelRes,
1440                                            pi.nonLocalizedLabel));
1441                            pw.println(prefix + "  description:"
1442                                    + loadText(pi, pi.descriptionRes,
1443                                            pi.nonLocalizedDescription));
1444                        }
1445                        pw.println(prefix + "  protectionLevel:"
1446                                + PermissionInfo.protectionToString(pi.protectionLevel));
1447                    }
1448                }
1449            }
1450
1451            if (summary) {
1452                pw.println("");
1453            }
1454        }
1455    }
1456
1457    private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized)
1458            throws RemoteException {
1459        if (nonLocalized != null) {
1460            return nonLocalized.toString();
1461        }
1462        if (res != 0) {
1463            Resources r = getResources(pii);
1464            if (r != null) {
1465                try {
1466                    return r.getString(res);
1467                } catch (Resources.NotFoundException e) {
1468                }
1469            }
1470        }
1471        return null;
1472    }
1473
1474    private Resources getResources(PackageItemInfo pii) throws RemoteException {
1475        Resources res = mResourceCache.get(pii.packageName);
1476        if (res != null) return res;
1477
1478        ApplicationInfo ai = mInterface.getApplicationInfo(pii.packageName, 0, 0);
1479        AssetManager am = new AssetManager();
1480        am.addAssetPath(ai.publicSourceDir);
1481        res = new Resources(am, null, null);
1482        mResourceCache.put(pii.packageName, res);
1483        return res;
1484    }
1485
1486    @Override
1487    public void onHelp() {
1488        final PrintWriter pw = getOutPrintWriter();
1489        pw.println("Package manager (package) commands:");
1490        pw.println("  help");
1491        pw.println("    Print this help text.");
1492        pw.println("");
1493        pw.println("  compile [-m MODE | -r REASON] [-f] [-c]");
1494        pw.println("          [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)");
1495        pw.println("    Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".");
1496        pw.println("    Options:");
1497        pw.println("      -a: compile all packages");
1498        pw.println("      -c: clear profile data before compiling");
1499        pw.println("      -f: force compilation even if not needed");
1500        pw.println("      -m: select compilation mode");
1501        pw.println("          MODE is one of the dex2oat compiler filters:");
1502        pw.println("            verify-none");
1503        pw.println("            verify-at-runtime");
1504        pw.println("            verify-profile");
1505        pw.println("            interpret-only");
1506        pw.println("            space-profile");
1507        pw.println("            space");
1508        pw.println("            speed-profile");
1509        pw.println("            speed");
1510        pw.println("            everything");
1511        pw.println("      -r: select compilation reason");
1512        pw.println("          REASON is one of:");
1513        for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
1514            pw.println("            " + PackageManagerServiceCompilerMapping.REASON_STRINGS[i]);
1515        }
1516        pw.println("      --reset: restore package to its post-install state");
1517        pw.println("      --check-prof (true | false): look at profiles when doing dexopt?");
1518        pw.println("  list features");
1519        pw.println("    Prints all features of the system.");
1520        pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
1521        pw.println("    Prints all test packages; optionally only those targeting TARGET-PACKAGE");
1522        pw.println("    Options:");
1523        pw.println("      -f: dump the name of the .apk file containing the test package");
1524        pw.println("  list libraries");
1525        pw.println("    Prints all system libraries.");
1526        pw.println("  list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] "
1527                + "[--uid UID] [--user USER_ID] [FILTER]");
1528        pw.println("    Prints all packages; optionally only those whose name contains");
1529        pw.println("    the text in FILTER.");
1530        pw.println("    Options:");
1531        pw.println("      -f: see their associated file");
1532        pw.println("      -d: filter to only show disabled packages");
1533        pw.println("      -e: filter to only show enabled packages");
1534        pw.println("      -s: filter to only show system packages");
1535        pw.println("      -3: filter to only show third party packages");
1536        pw.println("      -i: see the installer for the packages");
1537        pw.println("      -l: ignored (used for compatibility with older releases)");
1538        pw.println("      -U: also show the package UID");
1539        pw.println("      -u: also include uninstalled packages");
1540        pw.println("      --uid UID: filter to only show packages with the given UID");
1541        pw.println("      --user USER_ID: only list packages belonging to the given user");
1542        pw.println("  list permission-groups");
1543        pw.println("    Prints all known permission groups.");
1544        pw.println("  list permissions [-g] [-f] [-d] [-u] [GROUP]");
1545        pw.println("    Prints all known permissions; optionally only those in GROUP.");
1546        pw.println("    Options:");
1547        pw.println("      -g: organize by group");
1548        pw.println("      -f: print all information");
1549        pw.println("      -s: short summary");
1550        pw.println("      -d: only list dangerous permissions");
1551        pw.println("      -u: list only the permissions users will see");
1552        pw.println("  dump-profiles TARGET-PACKAGE");
1553        pw.println("    Dumps method/class profile files to");
1554        pw.println("    /data/misc/profman/TARGET-PACKAGE.txt");
1555        pw.println("  resolve-activity [--brief] [--components] [--user USER_ID] INTENT");
1556        pw.println("    Prints the activity that resolves to the given Intent.");
1557        pw.println("  query-activities [--brief] [--components] [--user USER_ID] INTENT");
1558        pw.println("    Prints all activities that can handle the given Intent.");
1559        pw.println("  query-services [--brief] [--components] [--user USER_ID] INTENT");
1560        pw.println("    Prints all services that can handle the given Intent.");
1561        pw.println("  query-receivers [--brief] [--components] [--user USER_ID] INTENT");
1562        pw.println("    Prints all broadcast receivers that can handle the given Intent.");
1563        pw.println("  suspend [--user USER_ID] TARGET-PACKAGE");
1564        pw.println("    Suspends the specified package (as user).");
1565        pw.println("  unsuspend [--user USER_ID] TARGET-PACKAGE");
1566        pw.println("    Unsuspends the specified package (as user).");
1567        pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
1568        pw.println("    set the default home activity (aka launcher).");
1569        pw.println();
1570        Intent.printIntentArgsHelp(pw , "");
1571    }
1572
1573    private static class LocalIntentReceiver {
1574        private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
1575
1576        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1577            @Override
1578            public void send(int code, Intent intent, String resolvedType,
1579                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1580                try {
1581                    mResult.offer(intent, 5, TimeUnit.SECONDS);
1582                } catch (InterruptedException e) {
1583                    throw new RuntimeException(e);
1584                }
1585            }
1586        };
1587
1588        public IntentSender getIntentSender() {
1589            return new IntentSender((IIntentSender) mLocalSender);
1590        }
1591
1592        public Intent getResult() {
1593            try {
1594                return mResult.take();
1595            } catch (InterruptedException e) {
1596                throw new RuntimeException(e);
1597            }
1598        }
1599    }
1600}
1601