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