summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Alex Buynytskyy <alexbuy@google.com> 2020-01-21 17:14:12 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-01-21 17:14:12 +0000
commitc982e4e311279ff3e5ee67f35257c545e34993c4 (patch)
treee19389279f983f1e80304824372d71cb3251fd6d
parent52bf7227ec6322f36f3cba2f248bab1984add2f4 (diff)
parent43dd0b9ab48eebec71aa836caa7149c4d3970987 (diff)
Merge "Multi-file streaming installation."
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java127
1 files changed, 86 insertions, 41 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 5adab378bb73..044e552f59dc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -132,6 +132,7 @@ import java.util.concurrent.TimeUnit;
class PackageManagerShellCommand extends ShellCommand {
/** Path for streaming APK content */
private static final String STDIN_PATH = "-";
+ private static final byte[] STDIN_PATH_BYTES = "-".getBytes(StandardCharsets.UTF_8);
/** Path where ART profiles snapshots are dumped for the shell user */
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
private static final int DEFAULT_WAIT_MS = 60 * 1000;
@@ -472,6 +473,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
}
+
params.sessionParams.setSize(sessionSize);
}
/**
@@ -1170,57 +1172,52 @@ class PackageManagerShellCommand extends ShellCommand {
private int doRunInstall(final InstallParams params) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final boolean streaming = params.sessionParams.dataLoaderParams != null;
- ArrayList<String> inPaths = getRemainingArgs();
- if (inPaths.isEmpty()) {
- inPaths.add(STDIN_PATH);
- }
+ final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
+ final boolean isApex =
+ (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
- final boolean hasSplits = inPaths.size() > 1;
+ ArrayList<String> args = getRemainingArgs();
- if (STDIN_PATH.equals(inPaths.get(0))) {
- if (hasSplits) {
- pw.println("Error: can't specify SPLIT(s) along with STDIN");
- return 1;
- }
- if (params.sessionParams.sizeBytes == -1) {
- pw.println("Error: must either specify a package size or an APK file");
- return 1;
- }
+ final boolean fromStdIn = args.isEmpty() || STDIN_PATH.equals(args.get(0));
+ final boolean hasSplits = args.size() > 1;
+
+ if (fromStdIn && params.sessionParams.sizeBytes == -1) {
+ pw.println("Error: must either specify a package size or an APK file");
+ return 1;
}
- final boolean isApex =
- (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
if (isApex && hasSplits) {
pw.println("Error: can't specify SPLIT(s) for APEX");
return 1;
}
- if (!streaming) {
- setParamsSize(params, inPaths);
+ if (!isStreaming) {
+ if (fromStdIn && hasSplits) {
+ pw.println("Error: can't specify SPLIT(s) along with STDIN");
+ return 1;
+ }
+
+ if (args.isEmpty()) {
+ args.add(STDIN_PATH);
+ } else {
+ setParamsSize(params, args);
+ }
}
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
boolean abandonSession = true;
try {
- for (String inPath : inPaths) {
- if (streaming) {
- String name = new File(inPath).getName();
- byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);
- if (doAddFile(sessionId, name, params.sessionParams.sizeBytes, metadata,
- false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
- return 1;
- }
- } else {
- String splitName = hasSplits ? new File(inPath).getName()
- : "base." + (isApex ? "apex" : "apk");
-
- if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
- false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
- return 1;
- }
+ if (isStreaming) {
+ if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex)
+ != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
+ } else {
+ if (doWriteSplits(sessionId, args, params.sessionParams.sizeBytes, isApex)
+ != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
}
}
if (doCommitSession(sessionId, false /*logSuccess*/)
@@ -2956,23 +2953,71 @@ class PackageManagerShellCommand extends ShellCommand {
return sessionId;
}
- private int doAddFile(int sessionId, String name, long sizeBytes, byte[] metadata,
- boolean logSuccess) throws RemoteException {
+ private int doAddFiles(int sessionId, ArrayList<String> args, long sessionSizeBytes,
+ boolean isApex) throws RemoteException {
PackageInstaller.Session session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
try {
- session.addFile(name, sizeBytes, metadata);
-
- if (logSuccess) {
- getOutPrintWriter().println("Success");
+ // 1. Single file from stdin.
+ if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
+ String name = "base." + (isApex ? "apex" : "apk");
+ session.addFile(name, sessionSizeBytes, STDIN_PATH_BYTES);
+ return 0;
}
+ for (String arg : args) {
+ final int delimLocation = arg.indexOf(':');
+
+ // 2. File with specified size read from stdin.
+ if (delimLocation != -1) {
+ String name = arg.substring(0, delimLocation);
+ String sizeStr = arg.substring(delimLocation + 1);
+ long sizeBytes;
+
+ if (TextUtils.isEmpty(name)) {
+ getErrPrintWriter().println("Empty file name in: " + arg);
+ return 1;
+ }
+ try {
+ sizeBytes = Long.parseUnsignedLong(sizeStr);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Unable to parse size from: " + arg);
+ return 1;
+ }
+
+ session.addFile(name, sizeBytes, STDIN_PATH_BYTES);
+ continue;
+ }
+
+ // 3. Local file.
+ final String inPath = arg;
+
+ String name = new File(inPath).getName();
+ byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);
+
+ session.addFile(name, -1, metadata);
+ }
return 0;
} finally {
IoUtils.closeQuietly(session);
}
}
+ private int doWriteSplits(int sessionId, ArrayList<String> splitPaths, long sessionSizeBytes,
+ boolean isApex) throws RemoteException {
+ final boolean multipleSplits = splitPaths.size() > 1;
+ for (String splitPath : splitPaths) {
+ String splitName = multipleSplits ? new File(splitPath).getName()
+ : "base." + (isApex ? "apex" : "apk");
+
+ if (doWriteSplit(sessionId, splitPath, sessionSizeBytes, splitName,
+ false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
boolean logSuccess) throws RemoteException {
PackageInstaller.Session session = null;