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