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