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