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