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