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