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