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