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