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.PackageParser;
34import android.content.pm.PackageParser.ApkLite;
35import android.content.pm.PackageParser.PackageLite;
36import android.content.pm.PackageParser.PackageParserException;
37import android.content.pm.ParceledListSlice;
38import android.content.pm.PermissionGroupInfo;
39import android.content.pm.PermissionInfo;
40import android.content.pm.PackageInstaller.SessionInfo;
41import android.content.pm.PackageInstaller.SessionParams;
42import android.content.pm.PackageManager.NameNotFoundException;
43import android.content.pm.ResolveInfo;
44import android.content.pm.VersionedPackage;
45import android.content.res.AssetManager;
46import android.content.res.Resources;
47import android.net.Uri;
48import android.os.Binder;
49import android.os.Build;
50import android.os.Bundle;
51import android.os.IBinder;
52import android.os.RemoteException;
53import android.os.ShellCommand;
54import android.os.SystemProperties;
55import android.os.UserHandle;
56import android.text.TextUtils;
57import android.util.ArraySet;
58import android.util.PrintWriterPrinter;
59import com.android.internal.content.PackageHelper;
60import com.android.internal.util.SizedInputStream;
61import com.android.server.SystemConfig;
62
63import dalvik.system.DexFile;
64
65import libcore.io.IoUtils;
66
67import java.io.File;
68import java.io.FileInputStream;
69import java.io.IOException;
70import java.io.InputStream;
71import java.io.OutputStream;
72import java.io.PrintWriter;
73import java.net.URISyntaxException;
74import java.util.ArrayList;
75import java.util.Collections;
76import java.util.Comparator;
77import java.util.List;
78import java.util.WeakHashMap;
79import java.util.concurrent.SynchronousQueue;
80import java.util.concurrent.TimeUnit;
81
82class PackageManagerShellCommand extends ShellCommand {
83    /** Path for streaming APK content */
84    private static final String STDIN_PATH = "-";
85    /** Whether or not APK content must be streamed from stdin */
86    private static final boolean FORCE_STREAM_INSTALL = true;
87
88    final IPackageManager mInterface;
89    final private WeakHashMap<String, Resources> mResourceCache =
90            new WeakHashMap<String, Resources>();
91    int mTargetUser;
92    boolean mBrief;
93    boolean mComponents;
94
95    PackageManagerShellCommand(PackageManagerService service) {
96        mInterface = service;
97    }
98
99    @Override
100    public int onCommand(String cmd) {
101        if (cmd == null) {
102            return handleDefaultCommands(cmd);
103        }
104
105        final PrintWriter pw = getOutPrintWriter();
106        try {
107            switch(cmd) {
108                case "install":
109                    return runInstall();
110                case "install-abandon":
111                case "install-destroy":
112                    return runInstallAbandon();
113                case "install-commit":
114                    return runInstallCommit();
115                case "install-create":
116                    return runInstallCreate();
117                case "install-remove":
118                    return runInstallRemove();
119                case "install-write":
120                    return runInstallWrite();
121                case "install-existing":
122                    return runInstallExisting();
123                case "compile":
124                    return runCompile();
125                case "reconcile-secondary-dex-files":
126                    return runreconcileSecondaryDexFiles();
127                case "bg-dexopt-job":
128                    return runDexoptJob();
129                case "dump-profiles":
130                    return runDumpProfiles();
131                case "list":
132                    return runList();
133                case "uninstall":
134                    return runUninstall();
135                case "resolve-activity":
136                    return runResolveActivity();
137                case "query-activities":
138                    return runQueryIntentActivities();
139                case "query-services":
140                    return runQueryIntentServices();
141                case "query-receivers":
142                    return runQueryIntentReceivers();
143                case "suspend":
144                    return runSuspend(true);
145                case "unsuspend":
146                    return runSuspend(false);
147                case "set-home-activity":
148                    return runSetHomeActivity();
149                case "get-privapp-permissions":
150                    return runGetPrivappPermissions();
151                case "get-instantapp-resolver":
152                    return runGetInstantAppResolver();
153                case "has-feature":
154                    return runHasFeature();
155                default:
156                    return handleDefaultCommands(cmd);
157            }
158        } catch (RemoteException e) {
159            pw.println("Remote exception: " + e);
160        }
161        return -1;
162    }
163
164    private void setParamsSize(InstallParams params, String inPath) {
165        // If we're forced to stream the package, the params size
166        // must be set via command-line argument. There's nothing
167        // to do here.
168        if (FORCE_STREAM_INSTALL) {
169            return;
170        }
171        final PrintWriter pw = getOutPrintWriter();
172        if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
173            File file = new File(inPath);
174            if (file.isFile()) {
175                try {
176                    ApkLite baseApk = PackageParser.parseApkLite(file, 0);
177                    PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
178                            null, null);
179                    params.sessionParams.setSize(PackageHelper.calculateInstalledSize(
180                            pkgLite, false, params.sessionParams.abiOverride));
181                } catch (PackageParserException | IOException e) {
182                    pw.println("Error: Failed to parse APK file: " + file);
183                    throw new IllegalArgumentException(
184                            "Error: Failed to parse APK file: " + file, e);
185                }
186            } else {
187                pw.println("Error: Can't open non-file: " + inPath);
188                throw new IllegalArgumentException("Error: Can't open non-file: " + inPath);
189            }
190        }
191    }
192
193    private int runInstall() throws RemoteException {
194        final PrintWriter pw = getOutPrintWriter();
195        final InstallParams params = makeInstallParams();
196        final String inPath = getNextArg();
197
198        setParamsSize(params, inPath);
199        final int sessionId = doCreateSession(params.sessionParams,
200                params.installerPackageName, params.userId);
201        boolean abandonSession = true;
202        try {
203            if (inPath == null && params.sessionParams.sizeBytes == -1) {
204                pw.println("Error: must either specify a package size or an APK file");
205                return 1;
206            }
207            if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
208                    false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
209                return 1;
210            }
211            if (doCommitSession(sessionId, false /*logSuccess*/)
212                    != PackageInstaller.STATUS_SUCCESS) {
213                return 1;
214            }
215            abandonSession = false;
216            pw.println("Success");
217            return 0;
218        } finally {
219            if (abandonSession) {
220                try {
221                    doAbandonSession(sessionId, false /*logSuccess*/);
222                } catch (Exception ignore) {
223                }
224            }
225        }
226    }
227
228    private int runSuspend(boolean suspendedState) {
229        final PrintWriter pw = getOutPrintWriter();
230        int userId = UserHandle.USER_SYSTEM;
231        String opt;
232        while ((opt = getNextOption()) != null) {
233            switch (opt) {
234                case "--user":
235                    userId = UserHandle.parseUserArg(getNextArgRequired());
236                    break;
237                default:
238                    pw.println("Error: Unknown option: " + opt);
239                    return 1;
240            }
241        }
242
243        String packageName = getNextArg();
244        if (packageName == null) {
245            pw.println("Error: package name not specified");
246            return 1;
247        }
248
249        try {
250            mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
251                    userId);
252            pw.println("Package " + packageName + " new suspended state: "
253                    + mInterface.isPackageSuspendedForUser(packageName, userId));
254            return 0;
255        } catch (RemoteException | IllegalArgumentException e) {
256            pw.println(e.toString());
257            return 1;
258        }
259    }
260
261    private int runInstallAbandon() throws RemoteException {
262        final int sessionId = Integer.parseInt(getNextArg());
263        return doAbandonSession(sessionId, true /*logSuccess*/);
264    }
265
266    private int runInstallCommit() throws RemoteException {
267        final int sessionId = Integer.parseInt(getNextArg());
268        return doCommitSession(sessionId, true /*logSuccess*/);
269    }
270
271    private int runInstallCreate() throws RemoteException {
272        final PrintWriter pw = getOutPrintWriter();
273        final InstallParams installParams = makeInstallParams();
274        final int sessionId = doCreateSession(installParams.sessionParams,
275                installParams.installerPackageName, installParams.userId);
276
277        // NOTE: adb depends on parsing this string
278        pw.println("Success: created install session [" + sessionId + "]");
279        return 0;
280    }
281
282    private int runInstallWrite() throws RemoteException {
283        long sizeBytes = -1;
284
285        String opt;
286        while ((opt = getNextOption()) != null) {
287            if (opt.equals("-S")) {
288                sizeBytes = Long.parseLong(getNextArg());
289            } else {
290                throw new IllegalArgumentException("Unknown option: " + opt);
291            }
292        }
293
294        final int sessionId = Integer.parseInt(getNextArg());
295        final String splitName = getNextArg();
296        final String path = getNextArg();
297        return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
298    }
299
300    private int runInstallRemove() throws RemoteException {
301        final PrintWriter pw = getOutPrintWriter();
302
303        final int sessionId = Integer.parseInt(getNextArg());
304
305        final String splitName = getNextArg();
306        if (splitName == null) {
307            pw.println("Error: split name not specified");
308            return 1;
309        }
310        return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
311    }
312
313    private int runInstallExisting() throws RemoteException {
314        final PrintWriter pw = getOutPrintWriter();
315        int userId = UserHandle.USER_SYSTEM;
316        int installFlags = 0;
317        String opt;
318        while ((opt = getNextOption()) != null) {
319            switch (opt) {
320                case "--user":
321                    userId = UserHandle.parseUserArg(getNextArgRequired());
322                    break;
323                case "--ephemeral":
324                case "--instant":
325                    installFlags |= PackageManager.INSTALL_INSTANT_APP;
326                    installFlags &= ~PackageManager.INSTALL_FULL_APP;
327                    break;
328                case "--full":
329                    installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
330                    installFlags |= PackageManager.INSTALL_FULL_APP;
331                    break;
332                default:
333                    pw.println("Error: Unknown option: " + opt);
334                    return 1;
335            }
336        }
337
338        final String packageName = getNextArg();
339        if (packageName == null) {
340            pw.println("Error: package name not specified");
341            return 1;
342        }
343
344        try {
345            final int res = mInterface.installExistingPackageAsUser(packageName, userId,
346                    installFlags, PackageManager.INSTALL_REASON_UNKNOWN);
347            if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
348                throw new NameNotFoundException("Package " + packageName + " doesn't exist");
349            }
350            pw.println("Package " + packageName + " installed for user: " + userId);
351            return 0;
352        } catch (RemoteException | NameNotFoundException e) {
353            pw.println(e.toString());
354            return 1;
355        }
356    }
357
358    private int runCompile() throws RemoteException {
359        final PrintWriter pw = getOutPrintWriter();
360        boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
361        boolean forceCompilation = false;
362        boolean allPackages = false;
363        boolean clearProfileData = false;
364        String compilerFilter = null;
365        String compilationReason = null;
366        String checkProfilesRaw = null;
367        boolean secondaryDex = false;
368
369        String opt;
370        while ((opt = getNextOption()) != null) {
371            switch (opt) {
372                case "-a":
373                    allPackages = true;
374                    break;
375                case "-c":
376                    clearProfileData = true;
377                    break;
378                case "-f":
379                    forceCompilation = true;
380                    break;
381                case "-m":
382                    compilerFilter = getNextArgRequired();
383                    break;
384                case "-r":
385                    compilationReason = getNextArgRequired();
386                    break;
387                case "--check-prof":
388                    checkProfilesRaw = getNextArgRequired();
389                    break;
390                case "--reset":
391                    forceCompilation = true;
392                    clearProfileData = true;
393                    compilationReason = "install";
394                    break;
395                case "--secondary-dex":
396                    secondaryDex = true;
397                    break;
398                default:
399                    pw.println("Error: Unknown option: " + opt);
400                    return 1;
401            }
402        }
403
404        if (checkProfilesRaw != null) {
405            if ("true".equals(checkProfilesRaw)) {
406                checkProfiles = true;
407            } else if ("false".equals(checkProfilesRaw)) {
408                checkProfiles = false;
409            } else {
410                pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
411                return 1;
412            }
413        }
414
415        if (compilerFilter != null && compilationReason != null) {
416            pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
417                    "at the same time");
418            return 1;
419        }
420        if (compilerFilter == null && compilationReason == null) {
421            pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
422                    "reason (\"-r\") at the same time");
423            return 1;
424        }
425
426        String targetCompilerFilter;
427        if (compilerFilter != null) {
428            if (!DexFile.isValidCompilerFilter(compilerFilter)) {
429                pw.println("Error: \"" + compilerFilter +
430                        "\" is not a valid compilation filter.");
431                return 1;
432            }
433            targetCompilerFilter = compilerFilter;
434        } else {
435            int reason = -1;
436            for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
437                if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
438                        compilationReason)) {
439                    reason = i;
440                    break;
441                }
442            }
443            if (reason == -1) {
444                pw.println("Error: Unknown compilation reason: " + compilationReason);
445                return 1;
446            }
447            targetCompilerFilter =
448                    PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
449        }
450
451
452        List<String> packageNames = null;
453        if (allPackages) {
454            packageNames = mInterface.getAllPackages();
455        } else {
456            String packageName = getNextArg();
457            if (packageName == null) {
458                pw.println("Error: package name not specified");
459                return 1;
460            }
461            packageNames = Collections.singletonList(packageName);
462        }
463
464        List<String> failedPackages = new ArrayList<>();
465        for (String packageName : packageNames) {
466            if (clearProfileData) {
467                mInterface.clearApplicationProfileData(packageName);
468            }
469
470            boolean result = secondaryDex
471                    ? mInterface.performDexOptSecondary(packageName,
472                            targetCompilerFilter, forceCompilation)
473                    : mInterface.performDexOptMode(packageName,
474                            checkProfiles, targetCompilerFilter, forceCompilation);
475            if (!result) {
476                failedPackages.add(packageName);
477            }
478        }
479
480        if (failedPackages.isEmpty()) {
481            pw.println("Success");
482            return 0;
483        } else if (failedPackages.size() == 1) {
484            pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
485            return 1;
486        } else {
487            pw.print("Failure: the following packages could not be compiled: ");
488            boolean is_first = true;
489            for (String packageName : failedPackages) {
490                if (is_first) {
491                    is_first = false;
492                } else {
493                    pw.print(", ");
494                }
495                pw.print(packageName);
496            }
497            pw.println();
498            return 1;
499        }
500    }
501
502    private int runreconcileSecondaryDexFiles() throws RemoteException {
503        String packageName = getNextArg();
504        mInterface.reconcileSecondaryDexFiles(packageName);
505        return 0;
506    }
507
508    private int runDexoptJob() throws RemoteException {
509        boolean result = mInterface.runBackgroundDexoptJob();
510        return result ? 0 : -1;
511    }
512
513    private int runDumpProfiles() throws RemoteException {
514        String packageName = getNextArg();
515        mInterface.dumpProfiles(packageName);
516        return 0;
517    }
518
519    private int runList() throws RemoteException {
520        final PrintWriter pw = getOutPrintWriter();
521        final String type = getNextArg();
522        if (type == null) {
523            pw.println("Error: didn't specify type of data to list");
524            return -1;
525        }
526        switch(type) {
527            case "features":
528                return runListFeatures();
529            case "instrumentation":
530                return runListInstrumentation();
531            case "libraries":
532                return runListLibraries();
533            case "package":
534            case "packages":
535                return runListPackages(false /*showSourceDir*/);
536            case "permission-groups":
537                return runListPermissionGroups();
538            case "permissions":
539                return runListPermissions();
540        }
541        pw.println("Error: unknown list type '" + type + "'");
542        return -1;
543    }
544
545    private int runListFeatures() throws RemoteException {
546        final PrintWriter pw = getOutPrintWriter();
547        final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
548
549        // sort by name
550        Collections.sort(list, new Comparator<FeatureInfo>() {
551            public int compare(FeatureInfo o1, FeatureInfo o2) {
552                if (o1.name == o2.name) return 0;
553                if (o1.name == null) return -1;
554                if (o2.name == null) return 1;
555                return o1.name.compareTo(o2.name);
556            }
557        });
558
559        final int count = (list != null) ? list.size() : 0;
560        for (int p = 0; p < count; p++) {
561            FeatureInfo fi = list.get(p);
562            pw.print("feature:");
563            if (fi.name != null) {
564                pw.print(fi.name);
565                if (fi.version > 0) {
566                    pw.print("=");
567                    pw.print(fi.version);
568                }
569                pw.println();
570            } else {
571                pw.println("reqGlEsVersion=0x"
572                    + Integer.toHexString(fi.reqGlEsVersion));
573            }
574        }
575        return 0;
576    }
577
578    private int runListInstrumentation() throws RemoteException {
579        final PrintWriter pw = getOutPrintWriter();
580        boolean showSourceDir = false;
581        String targetPackage = null;
582
583        try {
584            String opt;
585            while ((opt = getNextArg()) != null) {
586                switch (opt) {
587                    case "-f":
588                        showSourceDir = true;
589                        break;
590                    default:
591                        if (opt.charAt(0) != '-') {
592                            targetPackage = opt;
593                        } else {
594                            pw.println("Error: Unknown option: " + opt);
595                            return -1;
596                        }
597                        break;
598                }
599            }
600        } catch (RuntimeException ex) {
601            pw.println("Error: " + ex.toString());
602            return -1;
603        }
604
605        final List<InstrumentationInfo> list =
606                mInterface.queryInstrumentation(targetPackage, 0 /*flags*/).getList();
607
608        // sort by target package
609        Collections.sort(list, new Comparator<InstrumentationInfo>() {
610            public int compare(InstrumentationInfo o1, InstrumentationInfo o2) {
611                return o1.targetPackage.compareTo(o2.targetPackage);
612            }
613        });
614
615        final int count = (list != null) ? list.size() : 0;
616        for (int p = 0; p < count; p++) {
617            final InstrumentationInfo ii = list.get(p);
618            pw.print("instrumentation:");
619            if (showSourceDir) {
620                pw.print(ii.sourceDir);
621                pw.print("=");
622            }
623            final ComponentName cn = new ComponentName(ii.packageName, ii.name);
624            pw.print(cn.flattenToShortString());
625            pw.print(" (target=");
626            pw.print(ii.targetPackage);
627            pw.println(")");
628        }
629        return 0;
630    }
631
632    private int runListLibraries() throws RemoteException {
633        final PrintWriter pw = getOutPrintWriter();
634        final List<String> list = new ArrayList<String>();
635        final String[] rawList = mInterface.getSystemSharedLibraryNames();
636        for (int i = 0; i < rawList.length; i++) {
637            list.add(rawList[i]);
638        }
639
640        // sort by name
641        Collections.sort(list, new Comparator<String>() {
642            public int compare(String o1, String o2) {
643                if (o1 == o2) return 0;
644                if (o1 == null) return -1;
645                if (o2 == null) return 1;
646                return o1.compareTo(o2);
647            }
648        });
649
650        final int count = (list != null) ? list.size() : 0;
651        for (int p = 0; p < count; p++) {
652            String lib = list.get(p);
653            pw.print("library:");
654            pw.println(lib);
655        }
656        return 0;
657    }
658
659    private int runListPackages(boolean showSourceDir) throws RemoteException {
660        final PrintWriter pw = getOutPrintWriter();
661        int getFlags = 0;
662        boolean listDisabled = false, listEnabled = false;
663        boolean listSystem = false, listThirdParty = false;
664        boolean listInstaller = false;
665        boolean showUid = false;
666        boolean showVersionCode = false;
667        int uid = -1;
668        int userId = UserHandle.USER_SYSTEM;
669        try {
670            String opt;
671            while ((opt = getNextOption()) != null) {
672                switch (opt) {
673                    case "-d":
674                        listDisabled = true;
675                        break;
676                    case "-e":
677                        listEnabled = true;
678                        break;
679                    case "-f":
680                        showSourceDir = true;
681                        break;
682                    case "-i":
683                        listInstaller = true;
684                        break;
685                    case "-l":
686                        // old compat
687                        break;
688                    case "-s":
689                        listSystem = true;
690                        break;
691                    case "-U":
692                        showUid = true;
693                        break;
694                    case "-u":
695                        getFlags |= PackageManager.MATCH_UNINSTALLED_PACKAGES;
696                        break;
697                    case "-3":
698                        listThirdParty = true;
699                        break;
700                    case "--show-versioncode":
701                        showVersionCode = true;
702                        break;
703                    case "--user":
704                        userId = UserHandle.parseUserArg(getNextArgRequired());
705                        break;
706                    case "--uid":
707                        showUid = true;
708                        uid = Integer.parseInt(getNextArgRequired());
709                        break;
710                    default:
711                        pw.println("Error: Unknown option: " + opt);
712                        return -1;
713                }
714            }
715        } catch (RuntimeException ex) {
716            pw.println("Error: " + ex.toString());
717            return -1;
718        }
719
720        final String filter = getNextArg();
721
722        @SuppressWarnings("unchecked")
723        final ParceledListSlice<PackageInfo> slice =
724                mInterface.getInstalledPackages(getFlags, userId);
725        final List<PackageInfo> packages = slice.getList();
726
727        final int count = packages.size();
728        for (int p = 0; p < count; p++) {
729            final PackageInfo info = packages.get(p);
730            if (filter != null && !info.packageName.contains(filter)) {
731                continue;
732            }
733            if (uid != -1 && info.applicationInfo.uid != uid) {
734                continue;
735            }
736            final boolean isSystem =
737                    (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0;
738            if ((!listDisabled || !info.applicationInfo.enabled) &&
739                    (!listEnabled || info.applicationInfo.enabled) &&
740                    (!listSystem || isSystem) &&
741                    (!listThirdParty || !isSystem)) {
742                pw.print("package:");
743                if (showSourceDir) {
744                    pw.print(info.applicationInfo.sourceDir);
745                    pw.print("=");
746                }
747                pw.print(info.packageName);
748                if (showVersionCode) {
749                    pw.print(" versionCode:");
750                    pw.print(info.applicationInfo.versionCode);
751                }
752                if (listInstaller) {
753                    pw.print("  installer=");
754                    pw.print(mInterface.getInstallerPackageName(info.packageName));
755                }
756                if (showUid) {
757                    pw.print(" uid:");
758                    pw.print(info.applicationInfo.uid);
759                }
760                pw.println();
761            }
762        }
763        return 0;
764    }
765
766    private int runListPermissionGroups() throws RemoteException {
767        final PrintWriter pw = getOutPrintWriter();
768        final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0).getList();
769
770        final int count = pgs.size();
771        for (int p = 0; p < count ; p++) {
772            final PermissionGroupInfo pgi = pgs.get(p);
773            pw.print("permission group:");
774            pw.println(pgi.name);
775        }
776        return 0;
777    }
778
779    private int runListPermissions() throws RemoteException {
780        final PrintWriter pw = getOutPrintWriter();
781        boolean labels = false;
782        boolean groups = false;
783        boolean userOnly = false;
784        boolean summary = false;
785        boolean dangerousOnly = false;
786        String opt;
787        while ((opt = getNextOption()) != null) {
788            switch (opt) {
789                case "-d":
790                    dangerousOnly = true;
791                    break;
792                case "-f":
793                    labels = true;
794                    break;
795                case "-g":
796                    groups = true;
797                    break;
798                case "-s":
799                    groups = true;
800                    labels = true;
801                    summary = true;
802                    break;
803                case "-u":
804                    userOnly = true;
805                    break;
806                default:
807                    pw.println("Error: Unknown option: " + opt);
808                    return 1;
809            }
810        }
811
812        final ArrayList<String> groupList = new ArrayList<String>();
813        if (groups) {
814            final List<PermissionGroupInfo> infos =
815                    mInterface.getAllPermissionGroups(0 /*flags*/).getList();
816            final int count = infos.size();
817            for (int i = 0; i < count; i++) {
818                groupList.add(infos.get(i).name);
819            }
820            groupList.add(null);
821        } else {
822            final String grp = getNextArg();
823            groupList.add(grp);
824        }
825
826        if (dangerousOnly) {
827            pw.println("Dangerous Permissions:");
828            pw.println("");
829            doListPermissions(groupList, groups, labels, summary,
830                    PermissionInfo.PROTECTION_DANGEROUS,
831                    PermissionInfo.PROTECTION_DANGEROUS);
832            if (userOnly) {
833                pw.println("Normal Permissions:");
834                pw.println("");
835                doListPermissions(groupList, groups, labels, summary,
836                        PermissionInfo.PROTECTION_NORMAL,
837                        PermissionInfo.PROTECTION_NORMAL);
838            }
839        } else if (userOnly) {
840            pw.println("Dangerous and Normal Permissions:");
841            pw.println("");
842            doListPermissions(groupList, groups, labels, summary,
843                    PermissionInfo.PROTECTION_NORMAL,
844                    PermissionInfo.PROTECTION_DANGEROUS);
845        } else {
846            pw.println("All Permissions:");
847            pw.println("");
848            doListPermissions(groupList, groups, labels, summary,
849                    -10000, 10000);
850        }
851        return 0;
852    }
853
854    private int runUninstall() throws RemoteException {
855        final PrintWriter pw = getOutPrintWriter();
856        int flags = 0;
857        int userId = UserHandle.USER_ALL;
858        int versionCode = PackageManager.VERSION_CODE_HIGHEST;
859
860        String opt;
861        while ((opt = getNextOption()) != null) {
862            switch (opt) {
863                case "-k":
864                    flags |= PackageManager.DELETE_KEEP_DATA;
865                    break;
866                case "--user":
867                    userId = UserHandle.parseUserArg(getNextArgRequired());
868                    break;
869                case "--versionCode":
870                    versionCode = Integer.parseInt(getNextArgRequired());
871                    break;
872                default:
873                    pw.println("Error: Unknown option: " + opt);
874                    return 1;
875            }
876        }
877
878        final String packageName = getNextArg();
879        if (packageName == null) {
880            pw.println("Error: package name not specified");
881            return 1;
882        }
883
884        // if a split is specified, just remove it and not the whole package
885        final String splitName = getNextArg();
886        if (splitName != null) {
887            return runRemoveSplit(packageName, splitName);
888        }
889
890        userId = translateUserId(userId, "runUninstall");
891        if (userId == UserHandle.USER_ALL) {
892            userId = UserHandle.USER_SYSTEM;
893            flags |= PackageManager.DELETE_ALL_USERS;
894        } else {
895            final PackageInfo info = mInterface.getPackageInfo(packageName,
896                    PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
897            if (info == null) {
898                pw.println("Failure [not installed for " + userId + "]");
899                return 1;
900            }
901            final boolean isSystem =
902                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
903            // If we are being asked to delete a system app for just one
904            // user set flag so it disables rather than reverting to system
905            // version of the app.
906            if (isSystem) {
907                flags |= PackageManager.DELETE_SYSTEM_APP;
908            }
909        }
910
911        final LocalIntentReceiver receiver = new LocalIntentReceiver();
912        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
913                versionCode), null /*callerPackageName*/, flags,
914                receiver.getIntentSender(), userId);
915
916        final Intent result = receiver.getResult();
917        final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
918                PackageInstaller.STATUS_FAILURE);
919        if (status == PackageInstaller.STATUS_SUCCESS) {
920            pw.println("Success");
921            return 0;
922        } else {
923            pw.println("Failure ["
924                    + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
925            return 1;
926        }
927    }
928
929    private int runRemoveSplit(String packageName, String splitName) throws RemoteException {
930        final PrintWriter pw = getOutPrintWriter();
931        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
932        sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
933        sessionParams.appPackageName = packageName;
934        final int sessionId =
935                doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
936        boolean abandonSession = true;
937        try {
938            if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
939                    != PackageInstaller.STATUS_SUCCESS) {
940                return 1;
941            }
942            if (doCommitSession(sessionId, false /*logSuccess*/)
943                    != PackageInstaller.STATUS_SUCCESS) {
944                return 1;
945            }
946            abandonSession = false;
947            pw.println("Success");
948            return 0;
949        } finally {
950            if (abandonSession) {
951                try {
952                    doAbandonSession(sessionId, false /*logSuccess*/);
953                } catch (Exception ignore) {
954                }
955            }
956        }
957    }
958
959    private Intent parseIntentAndUser() throws URISyntaxException {
960        mTargetUser = UserHandle.USER_CURRENT;
961        mBrief = false;
962        mComponents = false;
963        Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
964            @Override
965            public boolean handleOption(String opt, ShellCommand cmd) {
966                if ("--user".equals(opt)) {
967                    mTargetUser = UserHandle.parseUserArg(cmd.getNextArgRequired());
968                    return true;
969                } else if ("--brief".equals(opt)) {
970                    mBrief = true;
971                    return true;
972                } else if ("--components".equals(opt)) {
973                    mComponents = true;
974                    return true;
975                }
976                return false;
977            }
978        });
979        mTargetUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
980                Binder.getCallingUid(), mTargetUser, false, false, null, null);
981        return intent;
982    }
983
984    private void printResolveInfo(PrintWriterPrinter pr, String prefix, ResolveInfo ri,
985            boolean brief, boolean components) {
986        if (brief || components) {
987            final ComponentName comp;
988            if (ri.activityInfo != null) {
989                comp = new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
990            } else if (ri.serviceInfo != null) {
991                comp = new ComponentName(ri.serviceInfo.packageName, ri.serviceInfo.name);
992            } else if (ri.providerInfo != null) {
993                comp = new ComponentName(ri.providerInfo.packageName, ri.providerInfo.name);
994            } else {
995                comp = null;
996            }
997            if (comp != null) {
998                if (!components) {
999                    pr.println(prefix + "priority=" + ri.priority
1000                            + " preferredOrder=" + ri.preferredOrder
1001                            + " match=0x" + Integer.toHexString(ri.match)
1002                            + " specificIndex=" + ri.specificIndex
1003                            + " isDefault=" + ri.isDefault);
1004                }
1005                pr.println(prefix + comp.flattenToShortString());
1006                return;
1007            }
1008        }
1009        ri.dump(pr, prefix);
1010    }
1011
1012    private int runResolveActivity() {
1013        Intent intent;
1014        try {
1015            intent = parseIntentAndUser();
1016        } catch (URISyntaxException e) {
1017            throw new RuntimeException(e.getMessage(), e);
1018        }
1019        try {
1020            ResolveInfo ri = mInterface.resolveIntent(intent, intent.getType(), 0, mTargetUser);
1021            PrintWriter pw = getOutPrintWriter();
1022            if (ri == null) {
1023                pw.println("No activity found");
1024            } else {
1025                PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1026                printResolveInfo(pr, "", ri, mBrief, mComponents);
1027            }
1028        } catch (RemoteException e) {
1029            throw new RuntimeException("Failed calling service", e);
1030        }
1031        return 0;
1032    }
1033
1034    private int runQueryIntentActivities() {
1035        Intent intent;
1036        try {
1037            intent = parseIntentAndUser();
1038        } catch (URISyntaxException e) {
1039            throw new RuntimeException(e.getMessage(), e);
1040        }
1041        try {
1042            List<ResolveInfo> result = mInterface.queryIntentActivities(intent, intent.getType(), 0,
1043                    mTargetUser).getList();
1044            PrintWriter pw = getOutPrintWriter();
1045            if (result == null || result.size() <= 0) {
1046                pw.println("No activities found");
1047            } else {
1048                if (!mComponents) {
1049                    pw.print(result.size()); pw.println(" activities found:");
1050                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1051                    for (int i = 0; i < result.size(); i++) {
1052                        pw.print("  Activity #"); pw.print(i); pw.println(":");
1053                        printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1054                    }
1055                } else {
1056                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1057                    for (int i = 0; i < result.size(); i++) {
1058                        printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1059                    }
1060                }
1061            }
1062        } catch (RemoteException e) {
1063            throw new RuntimeException("Failed calling service", e);
1064        }
1065        return 0;
1066    }
1067
1068    private int runQueryIntentServices() {
1069        Intent intent;
1070        try {
1071            intent = parseIntentAndUser();
1072        } catch (URISyntaxException e) {
1073            throw new RuntimeException(e.getMessage(), e);
1074        }
1075        try {
1076            List<ResolveInfo> result = mInterface.queryIntentServices(intent, intent.getType(), 0,
1077                    mTargetUser).getList();
1078            PrintWriter pw = getOutPrintWriter();
1079            if (result == null || result.size() <= 0) {
1080                pw.println("No services found");
1081            } else {
1082                if (!mComponents) {
1083                    pw.print(result.size()); pw.println(" services found:");
1084                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1085                    for (int i = 0; i < result.size(); i++) {
1086                        pw.print("  Service #"); pw.print(i); pw.println(":");
1087                        printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1088                    }
1089                } else {
1090                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1091                    for (int i = 0; i < result.size(); i++) {
1092                        printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1093                    }
1094                }
1095            }
1096        } catch (RemoteException e) {
1097            throw new RuntimeException("Failed calling service", e);
1098        }
1099        return 0;
1100    }
1101
1102    private int runQueryIntentReceivers() {
1103        Intent intent;
1104        try {
1105            intent = parseIntentAndUser();
1106        } catch (URISyntaxException e) {
1107            throw new RuntimeException(e.getMessage(), e);
1108        }
1109        try {
1110            List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, intent.getType(), 0,
1111                    mTargetUser).getList();
1112            PrintWriter pw = getOutPrintWriter();
1113            if (result == null || result.size() <= 0) {
1114                pw.println("No receivers found");
1115            } else {
1116                if (!mComponents) {
1117                    pw.print(result.size()); pw.println(" receivers found:");
1118                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1119                    for (int i = 0; i < result.size(); i++) {
1120                        pw.print("  Receiver #"); pw.print(i); pw.println(":");
1121                        printResolveInfo(pr, "    ", result.get(i), mBrief, mComponents);
1122                    }
1123                } else {
1124                    PrintWriterPrinter pr = new PrintWriterPrinter(pw);
1125                    for (int i = 0; i < result.size(); i++) {
1126                        printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
1127                    }
1128                }
1129            }
1130        } catch (RemoteException e) {
1131            throw new RuntimeException("Failed calling service", e);
1132        }
1133        return 0;
1134    }
1135
1136    private static class InstallParams {
1137        SessionParams sessionParams;
1138        String installerPackageName;
1139        int userId = UserHandle.USER_ALL;
1140    }
1141
1142    private InstallParams makeInstallParams() {
1143        final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
1144        final InstallParams params = new InstallParams();
1145        params.sessionParams = sessionParams;
1146        String opt;
1147        while ((opt = getNextOption()) != null) {
1148            switch (opt) {
1149                case "-l":
1150                    sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
1151                    break;
1152                case "-r":
1153                    sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
1154                    break;
1155                case "-i":
1156                    params.installerPackageName = getNextArg();
1157                    if (params.installerPackageName == null) {
1158                        throw new IllegalArgumentException("Missing installer package");
1159                    }
1160                    break;
1161                case "-t":
1162                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
1163                    break;
1164                case "-s":
1165                    sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL;
1166                    break;
1167                case "-f":
1168                    sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
1169                    break;
1170                case "-d":
1171                    sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
1172                    break;
1173                case "-g":
1174                    sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
1175                    break;
1176                case "--dont-kill":
1177                    sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
1178                    break;
1179                case "--originating-uri":
1180                    sessionParams.originatingUri = Uri.parse(getNextArg());
1181                    break;
1182                case "--referrer":
1183                    sessionParams.referrerUri = Uri.parse(getNextArg());
1184                    break;
1185                case "-p":
1186                    sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
1187                    sessionParams.appPackageName = getNextArg();
1188                    if (sessionParams.appPackageName == null) {
1189                        throw new IllegalArgumentException("Missing inherit package name");
1190                    }
1191                    break;
1192                case "-S":
1193                    final long sizeBytes = Long.parseLong(getNextArg());
1194                    if (sizeBytes <= 0) {
1195                        throw new IllegalArgumentException("Size must be positive");
1196                    }
1197                    sessionParams.setSize(sizeBytes);
1198                    break;
1199                case "--abi":
1200                    sessionParams.abiOverride = checkAbiArgument(getNextArg());
1201                    break;
1202                case "--ephemeral":
1203                case "--instantapp":
1204                    sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
1205                    break;
1206                case "--full":
1207                    sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
1208                    break;
1209                case "--user":
1210                    params.userId = UserHandle.parseUserArg(getNextArgRequired());
1211                    break;
1212                case "--install-location":
1213                    sessionParams.installLocation = Integer.parseInt(getNextArg());
1214                    break;
1215                case "--force-uuid":
1216                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
1217                    sessionParams.volumeUuid = getNextArg();
1218                    if ("internal".equals(sessionParams.volumeUuid)) {
1219                        sessionParams.volumeUuid = null;
1220                    }
1221                    break;
1222                case "--force-sdk":
1223                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
1224                    break;
1225                default:
1226                    throw new IllegalArgumentException("Unknown option " + opt);
1227            }
1228        }
1229        return params;
1230    }
1231
1232    private int runSetHomeActivity() {
1233        final PrintWriter pw = getOutPrintWriter();
1234        int userId = UserHandle.USER_SYSTEM;
1235        String opt;
1236        while ((opt = getNextOption()) != null) {
1237            switch (opt) {
1238                case "--user":
1239                    userId = UserHandle.parseUserArg(getNextArgRequired());
1240                    break;
1241                default:
1242                    pw.println("Error: Unknown option: " + opt);
1243                    return 1;
1244            }
1245        }
1246
1247        String component = getNextArg();
1248        ComponentName componentName =
1249                component != null ? ComponentName.unflattenFromString(component) : null;
1250
1251        if (componentName == null) {
1252            pw.println("Error: component name not specified or invalid");
1253            return 1;
1254        }
1255
1256        try {
1257            mInterface.setHomeActivity(componentName, userId);
1258            pw.println("Success");
1259            return 0;
1260        } catch (Exception e) {
1261            pw.println(e.toString());
1262            return 1;
1263        }
1264    }
1265
1266    private int runGetPrivappPermissions() {
1267        final String pkg = getNextArg();
1268        if (pkg == null) {
1269            System.err.println("Error: no package specified.");
1270            return 1;
1271        }
1272        ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
1273        getOutPrintWriter().println(privAppPermissions == null
1274                ? "{}" : privAppPermissions.toString());
1275        return 0;
1276    }
1277
1278    private int runGetInstantAppResolver() {
1279        final PrintWriter pw = getOutPrintWriter();
1280        try {
1281            final ComponentName instantAppsResolver = mInterface.getInstantAppResolverComponent();
1282            if (instantAppsResolver == null) {
1283                return 1;
1284            }
1285            pw.println(instantAppsResolver.flattenToString());
1286            return 0;
1287        } catch (Exception e) {
1288            pw.println(e.toString());
1289            return 1;
1290        }
1291    }
1292
1293    private int runHasFeature() {
1294        final PrintWriter err = getErrPrintWriter();
1295        final String featureName = getNextArg();
1296        if (featureName == null) {
1297            err.println("Error: expected FEATURE name");
1298            return 1;
1299        }
1300        final String versionString = getNextArg();
1301        try {
1302            final int version = (versionString == null) ? 0 : Integer.parseInt(versionString);
1303            final boolean hasFeature = mInterface.hasSystemFeature(featureName, version);
1304            getOutPrintWriter().println(hasFeature);
1305            return hasFeature ? 0 : 1;
1306        } catch (NumberFormatException e) {
1307            err.println("Error: illegal version number " + versionString);
1308            return 1;
1309        } catch (RemoteException e) {
1310            err.println(e.toString());
1311            return 1;
1312        }
1313    }
1314
1315    private static String checkAbiArgument(String abi) {
1316        if (TextUtils.isEmpty(abi)) {
1317            throw new IllegalArgumentException("Missing ABI argument");
1318        }
1319
1320        if ("-".equals(abi)) {
1321            return abi;
1322        }
1323
1324        final String[] supportedAbis = Build.SUPPORTED_ABIS;
1325        for (String supportedAbi : supportedAbis) {
1326            if (supportedAbi.equals(abi)) {
1327                return abi;
1328            }
1329        }
1330
1331        throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
1332    }
1333
1334    private int translateUserId(int userId, String logContext) {
1335        return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
1336                userId, true, true, logContext, "pm command");
1337    }
1338
1339    private int doCreateSession(SessionParams params, String installerPackageName, int userId)
1340            throws RemoteException {
1341        userId = translateUserId(userId, "runInstallCreate");
1342        if (userId == UserHandle.USER_ALL) {
1343            userId = UserHandle.USER_SYSTEM;
1344            params.installFlags |= PackageManager.INSTALL_ALL_USERS;
1345        }
1346
1347        final int sessionId = mInterface.getPackageInstaller()
1348                .createSession(params, installerPackageName, userId);
1349        return sessionId;
1350    }
1351
1352    private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
1353            boolean logSuccess) throws RemoteException {
1354        final PrintWriter pw = getOutPrintWriter();
1355        if (FORCE_STREAM_INSTALL && inPath != null && !STDIN_PATH.equals(inPath)) {
1356            pw.println("Error: APK content must be streamed");
1357            return 1;
1358        }
1359        if (STDIN_PATH.equals(inPath)) {
1360            inPath = null;
1361        } else if (inPath != null) {
1362            final File file = new File(inPath);
1363            if (file.isFile()) {
1364                sizeBytes = file.length();
1365            }
1366        }
1367        if (sizeBytes <= 0) {
1368            pw.println("Error: must specify a APK size");
1369            return 1;
1370        }
1371
1372        final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
1373
1374        PackageInstaller.Session session = null;
1375        InputStream in = null;
1376        OutputStream out = null;
1377        try {
1378            session = new PackageInstaller.Session(
1379                    mInterface.getPackageInstaller().openSession(sessionId));
1380
1381            if (inPath != null) {
1382                in = new FileInputStream(inPath);
1383            } else {
1384                in = new SizedInputStream(getRawInputStream(), sizeBytes);
1385            }
1386            out = session.openWrite(splitName, 0, sizeBytes);
1387
1388            int total = 0;
1389            byte[] buffer = new byte[65536];
1390            int c;
1391            while ((c = in.read(buffer)) != -1) {
1392                total += c;
1393                out.write(buffer, 0, c);
1394
1395                if (info.sizeBytes > 0) {
1396                    final float fraction = ((float) c / (float) info.sizeBytes);
1397                    session.addProgress(fraction);
1398                }
1399            }
1400            session.fsync(out);
1401
1402            if (logSuccess) {
1403                pw.println("Success: streamed " + total + " bytes");
1404            }
1405            return 0;
1406        } catch (IOException e) {
1407            pw.println("Error: failed to write; " + e.getMessage());
1408            return 1;
1409        } finally {
1410            IoUtils.closeQuietly(out);
1411            IoUtils.closeQuietly(in);
1412            IoUtils.closeQuietly(session);
1413        }
1414    }
1415
1416    private int doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
1417            throws RemoteException {
1418        final PrintWriter pw = getOutPrintWriter();
1419        PackageInstaller.Session session = null;
1420        try {
1421            session = new PackageInstaller.Session(
1422                    mInterface.getPackageInstaller().openSession(sessionId));
1423            session.removeSplit(splitName);
1424
1425            if (logSuccess) {
1426                pw.println("Success");
1427            }
1428            return 0;
1429        } catch (IOException e) {
1430            pw.println("Error: failed to remove split; " + e.getMessage());
1431            return 1;
1432        } finally {
1433            IoUtils.closeQuietly(session);
1434        }
1435    }
1436
1437    private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
1438        final PrintWriter pw = getOutPrintWriter();
1439        PackageInstaller.Session session = null;
1440        try {
1441            session = new PackageInstaller.Session(
1442                    mInterface.getPackageInstaller().openSession(sessionId));
1443
1444            final LocalIntentReceiver receiver = new LocalIntentReceiver();
1445            session.commit(receiver.getIntentSender());
1446
1447            final Intent result = receiver.getResult();
1448            final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
1449                    PackageInstaller.STATUS_FAILURE);
1450            if (status == PackageInstaller.STATUS_SUCCESS) {
1451                if (logSuccess) {
1452                    pw.println("Success");
1453                }
1454            } else {
1455                pw.println("Failure ["
1456                        + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
1457            }
1458            return status;
1459        } finally {
1460            IoUtils.closeQuietly(session);
1461        }
1462    }
1463
1464    private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
1465        final PrintWriter pw = getOutPrintWriter();
1466        PackageInstaller.Session session = null;
1467        try {
1468            session = new PackageInstaller.Session(
1469                    mInterface.getPackageInstaller().openSession(sessionId));
1470            session.abandon();
1471            if (logSuccess) {
1472                pw.println("Success");
1473            }
1474            return 0;
1475        } finally {
1476            IoUtils.closeQuietly(session);
1477        }
1478    }
1479
1480    private void doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels,
1481            boolean summary, int startProtectionLevel, int endProtectionLevel)
1482                    throws RemoteException {
1483        final PrintWriter pw = getOutPrintWriter();
1484        final int groupCount = groupList.size();
1485        for (int i = 0; i < groupCount; i++) {
1486            String groupName = groupList.get(i);
1487            String prefix = "";
1488            if (groups) {
1489                if (i > 0) {
1490                    pw.println("");
1491                }
1492                if (groupName != null) {
1493                    PermissionGroupInfo pgi =
1494                            mInterface.getPermissionGroupInfo(groupName, 0 /*flags*/);
1495                    if (summary) {
1496                        Resources res = getResources(pgi);
1497                        if (res != null) {
1498                            pw.print(loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel) + ": ");
1499                        } else {
1500                            pw.print(pgi.name + ": ");
1501
1502                        }
1503                    } else {
1504                        pw.println((labels ? "+ " : "") + "group:" + pgi.name);
1505                        if (labels) {
1506                            pw.println("  package:" + pgi.packageName);
1507                            Resources res = getResources(pgi);
1508                            if (res != null) {
1509                                pw.println("  label:"
1510                                        + loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel));
1511                                pw.println("  description:"
1512                                        + loadText(pgi, pgi.descriptionRes,
1513                                                pgi.nonLocalizedDescription));
1514                            }
1515                        }
1516                    }
1517                } else {
1518                    pw.println(((labels && !summary) ? "+ " : "") + "ungrouped:");
1519                }
1520                prefix = "  ";
1521            }
1522            List<PermissionInfo> ps =
1523                    mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
1524            final int count = ps.size();
1525            boolean first = true;
1526            for (int p = 0 ; p < count ; p++) {
1527                PermissionInfo pi = ps.get(p);
1528                if (groups && groupName == null && pi.group != null) {
1529                    continue;
1530                }
1531                final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
1532                if (base < startProtectionLevel
1533                        || base > endProtectionLevel) {
1534                    continue;
1535                }
1536                if (summary) {
1537                    if (first) {
1538                        first = false;
1539                    } else {
1540                        pw.print(", ");
1541                    }
1542                    Resources res = getResources(pi);
1543                    if (res != null) {
1544                        pw.print(loadText(pi, pi.labelRes,
1545                                pi.nonLocalizedLabel));
1546                    } else {
1547                        pw.print(pi.name);
1548                    }
1549                } else {
1550                    pw.println(prefix + (labels ? "+ " : "")
1551                            + "permission:" + pi.name);
1552                    if (labels) {
1553                        pw.println(prefix + "  package:" + pi.packageName);
1554                        Resources res = getResources(pi);
1555                        if (res != null) {
1556                            pw.println(prefix + "  label:"
1557                                    + loadText(pi, pi.labelRes,
1558                                            pi.nonLocalizedLabel));
1559                            pw.println(prefix + "  description:"
1560                                    + loadText(pi, pi.descriptionRes,
1561                                            pi.nonLocalizedDescription));
1562                        }
1563                        pw.println(prefix + "  protectionLevel:"
1564                                + PermissionInfo.protectionToString(pi.protectionLevel));
1565                    }
1566                }
1567            }
1568
1569            if (summary) {
1570                pw.println("");
1571            }
1572        }
1573    }
1574
1575    private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized)
1576            throws RemoteException {
1577        if (nonLocalized != null) {
1578            return nonLocalized.toString();
1579        }
1580        if (res != 0) {
1581            Resources r = getResources(pii);
1582            if (r != null) {
1583                try {
1584                    return r.getString(res);
1585                } catch (Resources.NotFoundException e) {
1586                }
1587            }
1588        }
1589        return null;
1590    }
1591
1592    private Resources getResources(PackageItemInfo pii) throws RemoteException {
1593        Resources res = mResourceCache.get(pii.packageName);
1594        if (res != null) return res;
1595
1596        ApplicationInfo ai = mInterface.getApplicationInfo(pii.packageName, 0, 0);
1597        AssetManager am = new AssetManager();
1598        am.addAssetPath(ai.publicSourceDir);
1599        res = new Resources(am, null, null);
1600        mResourceCache.put(pii.packageName, res);
1601        return res;
1602    }
1603
1604    @Override
1605    public void onHelp() {
1606        final PrintWriter pw = getOutPrintWriter();
1607        pw.println("Package manager (package) commands:");
1608        pw.println("  help");
1609        pw.println("    Print this help text.");
1610        pw.println("");
1611        pw.println("  compile [-m MODE | -r REASON] [-f] [-c]");
1612        pw.println("          [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)");
1613        pw.println("    Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".");
1614        pw.println("    Options:");
1615        pw.println("      -a: compile all packages");
1616        pw.println("      -c: clear profile data before compiling");
1617        pw.println("      -f: force compilation even if not needed");
1618        pw.println("      -m: select compilation mode");
1619        pw.println("          MODE is one of the dex2oat compiler filters:");
1620        pw.println("            assume-verified");
1621        pw.println("            extract");
1622        pw.println("            verify");
1623        pw.println("            quicken");
1624        pw.println("            space-profile");
1625        pw.println("            space");
1626        pw.println("            speed-profile");
1627        pw.println("            speed");
1628        pw.println("            everything");
1629        pw.println("      -r: select compilation reason");
1630        pw.println("          REASON is one of:");
1631        for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
1632            pw.println("            " + PackageManagerServiceCompilerMapping.REASON_STRINGS[i]);
1633        }
1634        pw.println("      --reset: restore package to its post-install state");
1635        pw.println("      --check-prof (true | false): look at profiles when doing dexopt?");
1636        pw.println("      --secondary-dex: compile app secondary dex files");
1637        pw.println("  bg-dexopt-job");
1638        pw.println("    Execute the background optimizations immediately.");
1639        pw.println("    Note that the command only runs the background optimizer logic. It may");
1640        pw.println("    overlap with the actual job but the job scheduler will not be able to");
1641        pw.println("    cancel it. It will also run even if the device is not in the idle");
1642        pw.println("    maintenance mode.");
1643        pw.println("  list features");
1644        pw.println("    Prints all features of the system.");
1645        pw.println("  list instrumentation [-f] [TARGET-PACKAGE]");
1646        pw.println("    Prints all test packages; optionally only those targeting TARGET-PACKAGE");
1647        pw.println("    Options:");
1648        pw.println("      -f: dump the name of the .apk file containing the test package");
1649        pw.println("  list libraries");
1650        pw.println("    Prints all system libraries.");
1651        pw.println("  list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] "
1652                + "[--uid UID] [--user USER_ID] [FILTER]");
1653        pw.println("    Prints all packages; optionally only those whose name contains");
1654        pw.println("    the text in FILTER.");
1655        pw.println("    Options:");
1656        pw.println("      -f: see their associated file");
1657        pw.println("      -d: filter to only show disabled packages");
1658        pw.println("      -e: filter to only show enabled packages");
1659        pw.println("      -s: filter to only show system packages");
1660        pw.println("      -3: filter to only show third party packages");
1661        pw.println("      -i: see the installer for the packages");
1662        pw.println("      -l: ignored (used for compatibility with older releases)");
1663        pw.println("      -U: also show the package UID");
1664        pw.println("      -u: also include uninstalled packages");
1665        pw.println("      --uid UID: filter to only show packages with the given UID");
1666        pw.println("      --user USER_ID: only list packages belonging to the given user");
1667        pw.println("  reconcile-secondary-dex-files TARGET-PACKAGE");
1668        pw.println("    Reconciles the package secondary dex files with the generated oat files.");
1669        pw.println("  list permission-groups");
1670        pw.println("    Prints all known permission groups.");
1671        pw.println("  list permissions [-g] [-f] [-d] [-u] [GROUP]");
1672        pw.println("    Prints all known permissions; optionally only those in GROUP.");
1673        pw.println("    Options:");
1674        pw.println("      -g: organize by group");
1675        pw.println("      -f: print all information");
1676        pw.println("      -s: short summary");
1677        pw.println("      -d: only list dangerous permissions");
1678        pw.println("      -u: list only the permissions users will see");
1679        pw.println("  dump-profiles TARGET-PACKAGE");
1680        pw.println("    Dumps method/class profile files to");
1681        pw.println("    /data/misc/profman/TARGET-PACKAGE.txt");
1682        pw.println("  resolve-activity [--brief] [--components] [--user USER_ID] INTENT");
1683        pw.println("    Prints the activity that resolves to the given Intent.");
1684        pw.println("  query-activities [--brief] [--components] [--user USER_ID] INTENT");
1685        pw.println("    Prints all activities that can handle the given Intent.");
1686        pw.println("  query-services [--brief] [--components] [--user USER_ID] INTENT");
1687        pw.println("    Prints all services that can handle the given Intent.");
1688        pw.println("  query-receivers [--brief] [--components] [--user USER_ID] INTENT");
1689        pw.println("    Prints all broadcast receivers that can handle the given Intent.");
1690        pw.println("  suspend [--user USER_ID] TARGET-PACKAGE");
1691        pw.println("    Suspends the specified package (as user).");
1692        pw.println("  unsuspend [--user USER_ID] TARGET-PACKAGE");
1693        pw.println("    Unsuspends the specified package (as user).");
1694        pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
1695        pw.println("    set the default home activity (aka launcher).");
1696        pw.println("  has-feature FEATURE_NAME [version]");
1697        pw.println("   prints true and returns exit status 0 when system has a FEATURE_NAME,");
1698        pw.println("   otherwise prints false and returns exit status 1");
1699        pw.println();
1700        Intent.printIntentArgsHelp(pw , "");
1701    }
1702
1703    private static class LocalIntentReceiver {
1704        private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
1705
1706        private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
1707            @Override
1708            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
1709                    IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
1710                try {
1711                    mResult.offer(intent, 5, TimeUnit.SECONDS);
1712                } catch (InterruptedException e) {
1713                    throw new RuntimeException(e);
1714                }
1715            }
1716        };
1717
1718        public IntentSender getIntentSender() {
1719            return new IntentSender((IIntentSender) mLocalSender);
1720        }
1721
1722        public Intent getResult() {
1723            try {
1724                return mResult.take();
1725            } catch (InterruptedException e) {
1726                throw new RuntimeException(e);
1727            }
1728        }
1729    }
1730}
1731