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