diff options
| author | 2020-01-21 17:14:12 +0000 | |
|---|---|---|
| committer | 2020-01-21 17:14:12 +0000 | |
| commit | c982e4e311279ff3e5ee67f35257c545e34993c4 (patch) | |
| tree | e19389279f983f1e80304824372d71cb3251fd6d | |
| parent | 52bf7227ec6322f36f3cba2f248bab1984add2f4 (diff) | |
| parent | 43dd0b9ab48eebec71aa836caa7149c4d3970987 (diff) | |
Merge "Multi-file streaming installation."
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerShellCommand.java | 127 |
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; |