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