blob: b18c84678a8e1f03be1aaef39d1887c28975410d [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.ResolveInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.PrintWriterPrinter;
import com.android.internal.util.SizedInputStream;
import libcore.io.IoUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
class PackageManagerShellCommand extends ShellCommand {
final IPackageManager mInterface;
final private WeakHashMap<String, Resources> mResourceCache =
new WeakHashMap<String, Resources>();
int mTargetUser;
PackageManagerShellCommand(PackageManagerService service) {
mInterface = service;
}
@Override
public int onCommand(String cmd) {
if (cmd == null) {
return handleDefaultCommands(cmd);
}
final PrintWriter pw = getOutPrintWriter();
try {
switch(cmd) {
case "install":
return runInstall();
case "install-abandon":
case "install-destroy":
return runInstallAbandon();
case "install-commit":
return runInstallCommit();
case "install-create":
return runInstallCreate();
case "install-write":
return runInstallWrite();
case "list":
return runList();
case "uninstall":
return runUninstall();
case "resolve-activity":
return runResolveActivity();
case "query-activities":
return runQueryIntentActivities();
case "query-services":
return runQueryIntentServices();
case "query-receivers":
return runQueryIntentReceivers();
default:
return handleDefaultCommands(cmd);
}
} catch (RemoteException e) {
pw.println("Remote exception: " + e);
}
return -1;
}
private int runInstall() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final InstallParams params = makeInstallParams();
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
final String inPath = getNextArg();
if (inPath == null && params.sessionParams.sizeBytes == 0) {
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk") != 0) {
return 1;
}
if (doCommitSession(sessionId) != 0) {
return 1;
}
return 0;
}
private int runInstallAbandon() throws RemoteException {
final int sessionId = Integer.parseInt(getNextArg());
return doAbandonSession(sessionId);
}
private int runInstallCommit() throws RemoteException {
final int sessionId = Integer.parseInt(getNextArg());
return doCommitSession(sessionId);
}
private int runInstallCreate() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final InstallParams installParams = makeInstallParams();
final int sessionId = doCreateSession(installParams.sessionParams,
installParams.installerPackageName, installParams.userId);
// NOTE: adb depends on parsing this string
pw.println("Success: created install session [" + sessionId + "]");
return 0;
}
private int runInstallWrite() throws RemoteException {
long sizeBytes = -1;
String opt;
while ((opt = getNextOption()) != null) {
if (opt.equals("-S")) {
sizeBytes = Long.parseLong(getNextArg());
} else {
throw new IllegalArgumentException("Unknown option: " + opt);
}
}
final int sessionId = Integer.parseInt(getNextArg());
final String splitName = getNextArg();
final String path = getNextArg();
return doWriteSession(sessionId, path, sizeBytes, splitName);
}
private int runList() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final String type = getNextArg();
if (type == null) {
pw.println("Error: didn't specify type of data to list");
return -1;
}
switch(type) {
case "features":
return runListFeatures();
case "instrumentation":
return runListInstrumentation();
case "libraries":
return runListLibraries();
case "package":
case "packages":
return runListPackages(false /*showSourceDir*/);
case "permission-groups":
return runListPermissionGroups();
case "permissions":
return runListPermissions();
}
pw.println("Error: unknown list type '" + type + "'");
return -1;
}
private int runListFeatures() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final List<FeatureInfo> list = new ArrayList<FeatureInfo>();
final FeatureInfo[] rawList = mInterface.getSystemAvailableFeatures();
for (int i=0; i<rawList.length; i++) {
list.add(rawList[i]);
}
// sort by name
Collections.sort(list, new Comparator<FeatureInfo>() {
public int compare(FeatureInfo o1, FeatureInfo o2) {
if (o1.name == o2.name) return 0;
if (o1.name == null) return -1;
if (o2.name == null) return 1;
return o1.name.compareTo(o2.name);
}
});
final int count = (list != null) ? list.size() : 0;
for (int p = 0; p < count; p++) {
FeatureInfo fi = list.get(p);
pw.print("feature:");
if (fi.name != null) pw.println(fi.name);
else pw.println("reqGlEsVersion=0x"
+ Integer.toHexString(fi.reqGlEsVersion));
}
return 0;
}
private int runListInstrumentation() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
boolean showSourceDir = false;
String targetPackage = null;
try {
String opt;
while ((opt = getNextArg()) != null) {
switch (opt) {
case "-f":
showSourceDir = true;
break;
default:
if (opt.charAt(0) != '-') {
targetPackage = opt;
} else {
pw.println("Error: Unknown option: " + opt);
return -1;
}
break;
}
}
} catch (RuntimeException ex) {
pw.println("Error: " + ex.toString());
return -1;
}
final List<InstrumentationInfo> list =
mInterface.queryInstrumentation(targetPackage, 0 /*flags*/);
// sort by target package
Collections.sort(list, new Comparator<InstrumentationInfo>() {
public int compare(InstrumentationInfo o1, InstrumentationInfo o2) {
return o1.targetPackage.compareTo(o2.targetPackage);
}
});
final int count = (list != null) ? list.size() : 0;
for (int p = 0; p < count; p++) {
final InstrumentationInfo ii = list.get(p);
pw.print("instrumentation:");
if (showSourceDir) {
pw.print(ii.sourceDir);
pw.print("=");
}
final ComponentName cn = new ComponentName(ii.packageName, ii.name);
pw.print(cn.flattenToShortString());
pw.print(" (target=");
pw.print(ii.targetPackage);
pw.println(")");
}
return 0;
}
private int runListLibraries() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final List<String> list = new ArrayList<String>();
final String[] rawList = mInterface.getSystemSharedLibraryNames();
for (int i = 0; i < rawList.length; i++) {
list.add(rawList[i]);
}
// sort by name
Collections.sort(list, new Comparator<String>() {
public int compare(String o1, String o2) {
if (o1 == o2) return 0;
if (o1 == null) return -1;
if (o2 == null) return 1;
return o1.compareTo(o2);
}
});
final int count = (list != null) ? list.size() : 0;
for (int p = 0; p < count; p++) {
String lib = list.get(p);
pw.print("library:");
pw.println(lib);
}
return 0;
}
private int runListPackages(boolean showSourceDir) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
int getFlags = 0;
boolean listDisabled = false, listEnabled = false;
boolean listSystem = false, listThirdParty = false;
boolean listInstaller = false;
int userId = UserHandle.USER_SYSTEM;
try {
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-d":
listDisabled = true;
break;
case "-e":
listEnabled = true;
break;
case "-f":
showSourceDir = true;
break;
case "-i":
listInstaller = true;
break;
case "-l":
// old compat
break;
case "-lf":
showSourceDir = true;
break;
case "-s":
listSystem = true;
break;
case "-u":
getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
break;
case "-3":
listThirdParty = true;
break;
case "--user":
userId = UserHandle.parseUserArg(getNextArgRequired());
break;
default:
pw.println("Error: Unknown option: " + opt);
return -1;
}
}
} catch (RuntimeException ex) {
pw.println("Error: " + ex.toString());
return -1;
}
final String filter = getNextArg();
@SuppressWarnings("unchecked")
final ParceledListSlice<PackageInfo> slice =
mInterface.getInstalledPackages(getFlags, userId);
final List<PackageInfo> packages = slice.getList();
final int count = packages.size();
for (int p = 0; p < count; p++) {
final PackageInfo info = packages.get(p);
if (filter != null && !info.packageName.contains(filter)) {
continue;
}
final boolean isSystem =
(info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0;
if ((!listDisabled || !info.applicationInfo.enabled) &&
(!listEnabled || info.applicationInfo.enabled) &&
(!listSystem || isSystem) &&
(!listThirdParty || !isSystem)) {
pw.print("package:");
if (showSourceDir) {
pw.print(info.applicationInfo.sourceDir);
pw.print("=");
}
pw.print(info.packageName);
if (listInstaller) {
pw.print(" installer=");
pw.print(mInterface.getInstallerPackageName(info.packageName));
}
pw.println();
}
}
return 0;
}
private int runListPermissionGroups() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0);
final int count = pgs.size();
for (int p = 0; p < count ; p++) {
final PermissionGroupInfo pgi = pgs.get(p);
pw.print("permission group:");
pw.println(pgi.name);
}
return 0;
}
private int runListPermissions() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
boolean labels = false;
boolean groups = false;
boolean userOnly = false;
boolean summary = false;
boolean dangerousOnly = false;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-d":
dangerousOnly = true;
break;
case "-f":
labels = true;
break;
case "-g":
groups = true;
break;
case "-s":
groups = true;
labels = true;
summary = true;
break;
case "-u":
userOnly = true;
break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
}
}
final ArrayList<String> groupList = new ArrayList<String>();
if (groups) {
final List<PermissionGroupInfo> infos =
mInterface.getAllPermissionGroups(0 /*flags*/);
final int count = infos.size();
for (int i = 0; i < count; i++) {
groupList.add(infos.get(i).name);
}
groupList.add(null);
} else {
final String grp = getNextArg();
groupList.add(grp);
}
if (dangerousOnly) {
pw.println("Dangerous Permissions:");
pw.println("");
doListPermissions(groupList, groups, labels, summary,
PermissionInfo.PROTECTION_DANGEROUS,
PermissionInfo.PROTECTION_DANGEROUS);
if (userOnly) {
pw.println("Normal Permissions:");
pw.println("");
doListPermissions(groupList, groups, labels, summary,
PermissionInfo.PROTECTION_NORMAL,
PermissionInfo.PROTECTION_NORMAL);
}
} else if (userOnly) {
pw.println("Dangerous and Normal Permissions:");
pw.println("");
doListPermissions(groupList, groups, labels, summary,
PermissionInfo.PROTECTION_NORMAL,
PermissionInfo.PROTECTION_DANGEROUS);
} else {
pw.println("All Permissions:");
pw.println("");
doListPermissions(groupList, groups, labels, summary,
-10000, 10000);
}
return 0;
}
private int runUninstall() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
int flags = 0;
int userId = UserHandle.USER_ALL;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-k":
flags |= PackageManager.DELETE_KEEP_DATA;
break;
case "--user":
userId = UserHandle.parseUserArg(getNextArgRequired());
break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
}
}
String packageName = getNextArg();
if (packageName == null) {
pw.println("Error: package name not specified");
return 1;
}
userId = translateUserId(userId, "runUninstall");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
flags |= PackageManager.DELETE_ALL_USERS;
} else {
final PackageInfo info = mInterface.getPackageInfo(packageName, 0, userId);
if (info == null) {
pw.println("Failure - not installed for " + userId);
return 1;
}
final boolean isSystem =
(info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
// If we are being asked to delete a system app for just one
// user set flag so it disables rather than reverting to system
// version of the app.
if (isSystem) {
flags |= PackageManager.DELETE_SYSTEM_APP;
}
}
final LocalIntentReceiver receiver = new LocalIntentReceiver();
mInterface.getPackageInstaller().uninstall(packageName, null /*callerPackageName*/, flags,
receiver.getIntentSender(), userId);
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
pw.println("Success");
return 0;
} else {
pw.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
return 1;
}
}
private Intent parseIntentAndUser() throws URISyntaxException {
mTargetUser = UserHandle.USER_CURRENT;
Intent intent = Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() {
@Override
public boolean handleOption(String opt, ShellCommand cmd) {
if ("--user".equals(opt)) {
mTargetUser = UserHandle.parseUserArg(cmd.getNextArgRequired());
return true;
}
return false;
}
});
mTargetUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mTargetUser, false, false, null, null);
return intent;
}
private int runResolveActivity() {
Intent intent;
try {
intent = parseIntentAndUser();
} catch (URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
try {
ResolveInfo ri = mInterface.resolveIntent(intent, null, 0, mTargetUser);
PrintWriter pw = getOutPrintWriter();
if (ri == null) {
pw.println("No activity found");
} else {
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
ri.dump(pr, "");
}
} catch (RemoteException e) {
throw new RuntimeException("Failed calling service", e);
}
return 0;
}
private int runQueryIntentActivities() {
Intent intent;
try {
intent = parseIntentAndUser();
} catch (URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
try {
List<ResolveInfo> result = mInterface.queryIntentActivities(intent, null, 0,
mTargetUser);
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No activities found");
} else {
pw.print(result.size()); pw.println(" activities found:");
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
for (int i=0; i<result.size(); i++) {
pw.print(" Activity #"); pw.print(i); pw.println(":");
result.get(i).dump(pr, " ");
}
}
} catch (RemoteException e) {
throw new RuntimeException("Failed calling service", e);
}
return 0;
}
private int runQueryIntentServices() {
Intent intent;
try {
intent = parseIntentAndUser();
} catch (URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
try {
List<ResolveInfo> result = mInterface.queryIntentServices(intent, null, 0,
mTargetUser);
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No services found");
} else {
pw.print(result.size()); pw.println(" services found:");
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
for (int i=0; i<result.size(); i++) {
pw.print(" Service #"); pw.print(i); pw.println(":");
result.get(i).dump(pr, " ");
}
}
} catch (RemoteException e) {
throw new RuntimeException("Failed calling service", e);
}
return 0;
}
private int runQueryIntentReceivers() {
Intent intent;
try {
intent = parseIntentAndUser();
} catch (URISyntaxException e) {
throw new RuntimeException(e.getMessage(), e);
}
try {
List<ResolveInfo> result = mInterface.queryIntentReceivers(intent, null, 0,
mTargetUser);
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No receivers found");
} else {
pw.print(result.size()); pw.println(" receivers found:");
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
for (int i=0; i<result.size(); i++) {
pw.print(" Receiver #"); pw.print(i); pw.println(":");
result.get(i).dump(pr, " ");
}
}
} catch (RemoteException e) {
throw new RuntimeException("Failed calling service", e);
}
return 0;
}
private static class InstallParams {
SessionParams sessionParams;
String installerPackageName;
int userId = UserHandle.USER_ALL;
}
private InstallParams makeInstallParams() {
final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
final InstallParams params = new InstallParams();
params.sessionParams = sessionParams;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-l":
sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
break;
case "-r":
sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
break;
case "-i":
params.installerPackageName = getNextArg();
if (params.installerPackageName == null) {
throw new IllegalArgumentException("Missing installer package");
}
break;
case "-t":
sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
break;
case "-s":
sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL;
break;
case "-f":
sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
break;
case "-d":
sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
break;
case "-g":
sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
break;
case "--originating-uri":
sessionParams.originatingUri = Uri.parse(getNextArg());
break;
case "--referrer":
sessionParams.referrerUri = Uri.parse(getNextArg());
break;
case "-p":
sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
sessionParams.appPackageName = getNextArg();
if (sessionParams.appPackageName == null) {
throw new IllegalArgumentException("Missing inherit package name");
}
break;
case "-S":
sessionParams.setSize(Long.parseLong(getNextArg()));
break;
case "--abi":
sessionParams.abiOverride = checkAbiArgument(getNextArg());
break;
case "--ephemeral":
sessionParams.installFlags |= PackageManager.INSTALL_EPHEMERAL;
break;
case "--user":
params.userId = UserHandle.parseUserArg(getNextArgRequired());
break;
case "--install-location":
sessionParams.installLocation = Integer.parseInt(getNextArg());
break;
case "--force-uuid":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
sessionParams.volumeUuid = getNextArg();
if ("internal".equals(sessionParams.volumeUuid)) {
sessionParams.volumeUuid = null;
}
break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
}
return params;
}
private static String checkAbiArgument(String abi) {
if (TextUtils.isEmpty(abi)) {
throw new IllegalArgumentException("Missing ABI argument");
}
if ("-".equals(abi)) {
return abi;
}
final String[] supportedAbis = Build.SUPPORTED_ABIS;
for (String supportedAbi : supportedAbis) {
if (supportedAbi.equals(abi)) {
return abi;
}
}
throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
}
private int translateUserId(int userId, String logContext) {
return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, true, true, logContext, "pm command");
}
private int doCreateSession(SessionParams params, String installerPackageName, int userId)
throws RemoteException {
userId = translateUserId(userId, "runInstallCreate");
if (userId == UserHandle.USER_ALL) {
userId = UserHandle.USER_SYSTEM;
params.installFlags |= PackageManager.INSTALL_ALL_USERS;
}
final int sessionId = mInterface.getPackageInstaller()
.createSession(params, installerPackageName, userId);
return sessionId;
}
private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName)
throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
if ("-".equals(inPath)) {
inPath = null;
} else if (inPath != null) {
final File file = new File(inPath);
if (file.isFile()) {
sizeBytes = file.length();
}
}
final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId);
PackageInstaller.Session session = null;
InputStream in = null;
OutputStream out = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
if (inPath != null) {
in = new FileInputStream(inPath);
} else {
in = new SizedInputStream(getInputStream(), sizeBytes);
}
out = session.openWrite(splitName, 0, sizeBytes);
int total = 0;
byte[] buffer = new byte[65536];
int c;
while ((c = in.read(buffer)) != -1) {
total += c;
out.write(buffer, 0, c);
if (info.sizeBytes > 0) {
final float fraction = ((float) c / (float) info.sizeBytes);
session.addProgress(fraction);
}
}
session.fsync(out);
pw.println("Success: streamed " + total + " bytes");
return 0;
} catch (IOException e) {
pw.println("Error: failed to write; " + e.getMessage());
return 1;
} finally {
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(session);
}
}
private int doCommitSession(int sessionId) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
final LocalIntentReceiver receiver = new LocalIntentReceiver();
session.commit(receiver.getIntentSender());
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
pw.println("Success");
} else {
pw.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
pw.println("Failure details: " + result.getExtras());
}
return status;
} finally {
IoUtils.closeQuietly(session);
}
}
private int doAbandonSession(int sessionId) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
session.abandon();
pw.println("Success");
return 0;
} finally {
IoUtils.closeQuietly(session);
}
}
private void doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels,
boolean summary, int startProtectionLevel, int endProtectionLevel)
throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final int groupCount = groupList.size();
for (int i = 0; i < groupCount; i++) {
String groupName = groupList.get(i);
String prefix = "";
if (groups) {
if (i > 0) {
pw.println("");
}
if (groupName != null) {
PermissionGroupInfo pgi =
mInterface.getPermissionGroupInfo(groupName, 0 /*flags*/);
if (summary) {
Resources res = getResources(pgi);
if (res != null) {
pw.print(loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel) + ": ");
} else {
pw.print(pgi.name + ": ");
}
} else {
pw.println((labels ? "+ " : "") + "group:" + pgi.name);
if (labels) {
pw.println(" package:" + pgi.packageName);
Resources res = getResources(pgi);
if (res != null) {
pw.println(" label:"
+ loadText(pgi, pgi.labelRes, pgi.nonLocalizedLabel));
pw.println(" description:"
+ loadText(pgi, pgi.descriptionRes,
pgi.nonLocalizedDescription));
}
}
}
} else {
pw.println(((labels && !summary) ? "+ " : "") + "ungrouped:");
}
prefix = " ";
}
List<PermissionInfo> ps =
mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/);
final int count = ps.size();
boolean first = true;
for (int p = 0 ; p < count ; p++) {
PermissionInfo pi = ps.get(p);
if (groups && groupName == null && pi.group != null) {
continue;
}
final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
if (base < startProtectionLevel
|| base > endProtectionLevel) {
continue;
}
if (summary) {
if (first) {
first = false;
} else {
pw.print(", ");
}
Resources res = getResources(pi);
if (res != null) {
pw.print(loadText(pi, pi.labelRes,
pi.nonLocalizedLabel));
} else {
pw.print(pi.name);
}
} else {
pw.println(prefix + (labels ? "+ " : "")
+ "permission:" + pi.name);
if (labels) {
pw.println(prefix + " package:" + pi.packageName);
Resources res = getResources(pi);
if (res != null) {
pw.println(prefix + " label:"
+ loadText(pi, pi.labelRes,
pi.nonLocalizedLabel));
pw.println(prefix + " description:"
+ loadText(pi, pi.descriptionRes,
pi.nonLocalizedDescription));
}
pw.println(prefix + " protectionLevel:"
+ PermissionInfo.protectionToString(pi.protectionLevel));
}
}
}
if (summary) {
pw.println("");
}
}
}
private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized)
throws RemoteException {
if (nonLocalized != null) {
return nonLocalized.toString();
}
if (res != 0) {
Resources r = getResources(pii);
if (r != null) {
try {
return r.getString(res);
} catch (Resources.NotFoundException e) {
}
}
}
return null;
}
private Resources getResources(PackageItemInfo pii) throws RemoteException {
Resources res = mResourceCache.get(pii.packageName);
if (res != null) return res;
ApplicationInfo ai = mInterface.getApplicationInfo(pii.packageName, 0, 0);
AssetManager am = new AssetManager();
am.addAssetPath(ai.publicSourceDir);
res = new Resources(am, null, null);
mResourceCache.put(pii.packageName, res);
return res;
}
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
pw.println("Package manager (package) commands:");
pw.println(" help");
pw.println(" Print this help text.");
pw.println("");
pw.println(" list features");
pw.println(" Prints all features of the system.");
pw.println(" list instrumentation [-f] [TARGET-PACKAGE]");
pw.println(" Prints all test packages; optionally only those targetting TARGET-PACKAGE");
pw.println(" Options:");
pw.println(" -f: dump the name of the .apk file containing the test package");
pw.println(" list libraries");
pw.println(" Prints all system libraries.");
pw.println(" list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]");
pw.println(" Prints all packages; optionally only those whose name contains");
pw.println(" the text in FILTER.");
pw.println(" Options:");
pw.println(" -f: see their associated file");
pw.println(" -d: filter to only show disabled packages");
pw.println(" -e: filter to only show enabled packages");
pw.println(" -s: filter to only show system packages");
pw.println(" -3: filter to only show third party packages");
pw.println(" -i: see the installer for the packages");
pw.println(" -u: also include uninstalled packages");
pw.println(" list permission-groups");
pw.println(" Prints all known permission groups.");
pw.println(" list permissions [-g] [-f] [-d] [-u] [GROUP]");
pw.println(" Prints all known permissions; optionally only those in GROUP.");
pw.println(" Options:");
pw.println(" -g: organize by group");
pw.println(" -f: print all information");
pw.println(" -s: short summary");
pw.println(" -d: only list dangerous permissions");
pw.println(" -u: list only the permissions users will see");
pw.println(" resolve-activity [--user USER_ID] INTENT");
pw.println(" Prints the activity that resolves to the given Intent.");
pw.println(" query-activities [--user USER_ID] INTENT");
pw.println(" Prints all activities that can handle the given Intent.");
pw.println(" query-services [--user USER_ID] INTENT");
pw.println(" Prints all services that can handle the given Intent.");
pw.println(" query-receivers [--user USER_ID] INTENT");
pw.println(" Prints all broadcast receivers that can handle the given Intent.");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
private static class LocalIntentReceiver {
private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
@Override
public int send(int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
try {
mResult.offer(intent, 5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return 0;
}
};
public IntentSender getIntentSender() {
return new IntentSender((IIntentSender) mLocalSender);
}
public Intent getResult() {
try {
return mResult.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}