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