blob: 251b2773aa6bd28824579e7b0952753cad0f5b9a [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.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.PrintWriterPrinter;
import com.android.internal.util.SizedInputStream;
import dalvik.system.DexFile;
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;
boolean mBrief;
boolean mComponents;
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-remove":
return runInstallRemove();
case "install-write":
return runInstallWrite();
case "compile":
return runCompile();
case "dump-profiles":
return runDumpProfiles();
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();
case "suspend":
return runSuspend(true);
case "unsuspend":
return runSuspend(false);
case "set-home-activity":
return runSetHomeActivity();
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);
boolean abandonSession = true;
try {
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 (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
if (doCommitSession(sessionId, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
abandonSession = false;
pw.println("Success");
return 0;
} finally {
if (abandonSession) {
try {
doAbandonSession(sessionId, false /*logSuccess*/);
} catch (Exception ignore) {
}
}
}
}
private int runSuspend(boolean suspendedState) {
final PrintWriter pw = getOutPrintWriter();
int userId = UserHandle.USER_SYSTEM;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
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;
}
try {
mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
userId);
pw.println("Package " + packageName + " new suspended state: "
+ mInterface.isPackageSuspendedForUser(packageName, userId));
return 0;
} catch (RemoteException | IllegalArgumentException e) {
pw.println(e.toString());
return 1;
}
}
private int runInstallAbandon() throws RemoteException {
final int sessionId = Integer.parseInt(getNextArg());
return doAbandonSession(sessionId, true /*logSuccess*/);
}
private int runInstallCommit() throws RemoteException {
final int sessionId = Integer.parseInt(getNextArg());
return doCommitSession(sessionId, true /*logSuccess*/);
}
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 doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
}
private int runInstallRemove() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final int sessionId = Integer.parseInt(getNextArg());
final String splitName = getNextArg();
if (splitName == null) {
pw.println("Error: split name not specified");
return 1;
}
return doRemoveSplit(sessionId, splitName, true /*logSuccess*/);
}
private int runCompile() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
boolean forceCompilation = false;
boolean allPackages = false;
boolean clearProfileData = false;
String compilerFilter = null;
String compilationReason = null;
String checkProfilesRaw = null;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "-a":
allPackages = true;
break;
case "-c":
clearProfileData = true;
break;
case "-f":
forceCompilation = true;
break;
case "-m":
compilerFilter = getNextArgRequired();
break;
case "-r":
compilationReason = getNextArgRequired();
break;
case "--check-prof":
checkProfilesRaw = getNextArgRequired();
break;
case "--reset":
forceCompilation = true;
clearProfileData = true;
compilationReason = "install";
break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
}
}
if (checkProfilesRaw != null) {
if ("true".equals(checkProfilesRaw)) {
checkProfiles = true;
} else if ("false".equals(checkProfilesRaw)) {
checkProfiles = false;
} else {
pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\".");
return 1;
}
}
if (compilerFilter != null && compilationReason != null) {
pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " +
"at the same time");
return 1;
}
if (compilerFilter == null && compilationReason == null) {
pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " +
"reason (\"-r\") at the same time");
return 1;
}
String targetCompilerFilter;
if (compilerFilter != null) {
if (!DexFile.isValidCompilerFilter(compilerFilter)) {
pw.println("Error: \"" + compilerFilter +
"\" is not a valid compilation filter.");
return 1;
}
targetCompilerFilter = compilerFilter;
} else {
int reason = -1;
for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals(
compilationReason)) {
reason = i;
break;
}
}
if (reason == -1) {
pw.println("Error: Unknown compilation reason: " + compilationReason);
return 1;
}
targetCompilerFilter =
PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason);
}
List<String> packageNames = null;
if (allPackages) {
packageNames = mInterface.getAllPackages();
} else {
String packageName = getNextArg();
if (packageName == null) {
pw.println("Error: package name not specified");
return 1;
}
packageNames = Collections.singletonList(packageName);
}
List<String> failedPackages = new ArrayList<>();
for (String packageName : packageNames) {
if (clearProfileData) {
mInterface.clearApplicationProfileData(packageName);
}
boolean result = mInterface.performDexOptMode(packageName,
checkProfiles, targetCompilerFilter, forceCompilation);
if (!result) {
failedPackages.add(packageName);
}
}
if (failedPackages.isEmpty()) {
pw.println("Success");
return 0;
} else if (failedPackages.size() == 1) {
pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled");
return 1;
} else {
pw.print("Failure: the following packages could not be compiled: ");
boolean is_first = true;
for (String packageName : failedPackages) {
if (is_first) {
is_first = false;
} else {
pw.print(", ");
}
pw.print(packageName);
}
pw.println();
return 1;
}
}
private int runDumpProfiles() throws RemoteException {
String packageName = getNextArg();
mInterface.dumpProfiles(packageName);
return 0;
}
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 = mInterface.getSystemAvailableFeatures().getList();
// 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.print(fi.name);
if (fi.version > 0) {
pw.print("=");
pw.print(fi.version);
}
pw.println();
} 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*/).getList();
// 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).getList();
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*/).getList();
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;
}
}
final String packageName = getNextArg();
if (packageName == null) {
pw.println("Error: package name not specified");
return 1;
}
// if a split is specified, just remove it and not the whole package
final String splitName = getNextArg();
if (splitName != null) {
return runRemoveSplit(packageName, splitName);
}
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 int runRemoveSplit(String packageName, String splitName) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING);
sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
sessionParams.appPackageName = packageName;
final int sessionId =
doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL);
boolean abandonSession = true;
try {
if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
if (doCommitSession(sessionId, false /*logSuccess*/)
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
abandonSession = false;
pw.println("Success");
return 0;
} finally {
if (abandonSession) {
try {
doAbandonSession(sessionId, false /*logSuccess*/);
} catch (Exception ignore) {
}
}
}
}
private Intent parseIntentAndUser() throws URISyntaxException {
mTargetUser = UserHandle.USER_CURRENT;
mBrief = false;
mComponents = false;
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;
} else if ("--brief".equals(opt)) {
mBrief = true;
return true;
} else if ("--components".equals(opt)) {
mComponents = true;
return true;
}
return false;
}
});
mTargetUser = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mTargetUser, false, false, null, null);
return intent;
}
private void printResolveInfo(PrintWriterPrinter pr, String prefix, ResolveInfo ri,
boolean brief, boolean components) {
if (brief || components) {
final ComponentName comp;
if (ri.activityInfo != null) {
comp = new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
} else if (ri.serviceInfo != null) {
comp = new ComponentName(ri.serviceInfo.packageName, ri.serviceInfo.name);
} else if (ri.providerInfo != null) {
comp = new ComponentName(ri.providerInfo.packageName, ri.providerInfo.name);
} else {
comp = null;
}
if (comp != null) {
if (!components) {
pr.println(prefix + "priority=" + ri.priority
+ " preferredOrder=" + ri.preferredOrder
+ " match=0x" + Integer.toHexString(ri.match)
+ " specificIndex=" + ri.specificIndex
+ " isDefault=" + ri.isDefault);
}
pr.println(prefix + comp.flattenToShortString());
return;
}
}
ri.dump(pr, prefix);
}
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);
printResolveInfo(pr, "", ri, mBrief, mComponents);
}
} 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).getList();
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No activities found");
} else {
if (!mComponents) {
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(":");
printResolveInfo(pr, " ", result.get(i), mBrief, mComponents);
}
} else {
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
for (int i = 0; i < result.size(); i++) {
printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
}
}
}
} 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).getList();
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No services found");
} else {
if (!mComponents) {
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(":");
printResolveInfo(pr, " ", result.get(i), mBrief, mComponents);
}
} else {
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
for (int i = 0; i < result.size(); i++) {
printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
}
}
}
} 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).getList();
PrintWriter pw = getOutPrintWriter();
if (result == null || result.size() <= 0) {
pw.println("No receivers found");
} else {
if (!mComponents) {
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(":");
printResolveInfo(pr, " ", result.get(i), mBrief, mComponents);
}
} else {
PrintWriterPrinter pr = new PrintWriterPrinter(pw);
for (int i = 0; i < result.size(); i++) {
printResolveInfo(pr, "", result.get(i), mBrief, mComponents);
}
}
}
} 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 "--dont-kill":
sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
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;
case "--force-sdk":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
}
return params;
}
private int runSetHomeActivity() {
final PrintWriter pw = getOutPrintWriter();
int userId = UserHandle.USER_SYSTEM;
String opt;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "--user":
userId = UserHandle.parseUserArg(getNextArgRequired());
break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
}
}
String component = getNextArg();
ComponentName componentName =
component != null ? ComponentName.unflattenFromString(component) : null;
if (componentName == null) {
pw.println("Error: component name not specified or invalid");
return 1;
}
try {
mInterface.setHomeActivity(componentName, userId);
return 0;
} catch (RemoteException e) {
pw.println(e.toString());
return 1;
}
}
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 doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
if (sizeBytes <= 0) {
pw.println("Error: must specify a APK size");
return 1;
}
if (inPath != null && !"-".equals(inPath)) {
pw.println("Error: APK content must be streamed");
return 1;
}
inPath = null;
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(getRawInputStream(), 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);
if (logSuccess) {
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 doRemoveSplit(int sessionId, String splitName, boolean logSuccess)
throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
session.removeSplit(splitName);
if (logSuccess) {
pw.println("Success");
}
return 0;
} catch (IOException e) {
pw.println("Error: failed to remove split; " + e.getMessage());
return 1;
} finally {
IoUtils.closeQuietly(session);
}
}
private int doCommitSession(int sessionId, boolean logSuccess) 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) {
if (logSuccess) {
System.out.println("Success");
}
} else {
pw.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
}
return status;
} finally {
IoUtils.closeQuietly(session);
}
}
private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
session.abandon();
if (logSuccess) {
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*/).getList();
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(" compile [-m MODE | -r REASON] [-f] [-c]");
pw.println(" [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)");
pw.println(" Trigger compilation of TARGET-PACKAGE or all packages if \"-a\".");
pw.println(" Options:");
pw.println(" -a: compile all packages");
pw.println(" -c: clear profile data before compiling");
pw.println(" -f: force compilation even if not needed");
pw.println(" -m: select compilation mode");
pw.println(" MODE is one of the dex2oat compiler filters:");
pw.println(" verify-none");
pw.println(" verify-at-runtime");
pw.println(" verify-profile");
pw.println(" interpret-only");
pw.println(" space-profile");
pw.println(" space");
pw.println(" speed-profile");
pw.println(" speed");
pw.println(" everything");
pw.println(" -r: select compilation reason");
pw.println(" REASON is one of:");
for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) {
pw.println(" " + PackageManagerServiceCompilerMapping.REASON_STRINGS[i]);
}
pw.println(" --reset: restore package to its post-install state");
pw.println(" --check-prof (true | false): look at profiles when doing dexopt?");
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 targeting 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(" dump-profiles TARGET-PACKAGE");
pw.println(" Dumps method/class profile files to");
pw.println(" /data/misc/profman/TARGET-PACKAGE.txt");
pw.println(" resolve-activity [--brief] [--components] [--user USER_ID] INTENT");
pw.println(" Prints the activity that resolves to the given Intent.");
pw.println(" query-activities [--brief] [--components] [--user USER_ID] INTENT");
pw.println(" Prints all activities that can handle the given Intent.");
pw.println(" query-services [--brief] [--components] [--user USER_ID] INTENT");
pw.println(" Prints all services that can handle the given Intent.");
pw.println(" query-receivers [--brief] [--components] [--user USER_ID] INTENT");
pw.println(" Prints all broadcast receivers that can handle the given Intent.");
pw.println(" suspend [--user USER_ID] TARGET-PACKAGE");
pw.println(" Suspends the specified package (as user).");
pw.println(" unsuspend [--user USER_ID] TARGET-PACKAGE");
pw.println(" Unsuspends the specified package (as user).");
pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
pw.println(" set the default home activity (aka launcher).");
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 void 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);
}
}
};
public IntentSender getIntentSender() {
return new IntentSender((IIntentSender) mLocalSender);
}
public Intent getResult() {
try {
return mResult.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}