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