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