summaryrefslogtreecommitdiff
path: root/core/java/android/os/Process.java
diff options
context:
space:
mode:
authorRobert Sesek <rsesek@google.com>2016-03-18 16:52:57 -0400
committerRobert Sesek <rsesek@google.com>2016-09-09 12:42:52 -0400
commit96b49848e7784bc4b40ffd01e2524461e1efcab7 (patch)
tree091cd1071de89ffe64bd1dae930f4ef2e402fe49 /core/java/android/os/Process.java
parentb9679dc1fad508a001e30a941148e1bdc3fe953f (diff)
Split the zygote logic out of android.os.Process into a new ZygoteProcess class.
There is no functional change. This is to support adding new types of zygotes that all operate using the same protocol. Bug: 21643067 (cherry picked from commit 94e824bc1b5f83024b7c9a228a8f2d0cd1347d11) Merged-In: Ie673ee816cae34ac20ffb8c774ec3e6461c3fd0a Change-Id: I104e6133a90dc93a9854836b5e92d3cd542163a3
Diffstat (limited to 'core/java/android/os/Process.java')
-rw-r--r--core/java/android/os/Process.java361
1 files changed, 5 insertions, 356 deletions
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f664e70cf7be..6aa9fac8d48b 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,34 +16,9 @@
package android.os;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
import android.system.Os;
import android.util.Log;
-import com.android.internal.os.Zygote;
import dalvik.system.VMRuntime;
-import java.io.BufferedWriter;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/*package*/ class ZygoteStartFailedEx extends Exception {
- ZygoteStartFailedEx(String s) {
- super(s);
- }
-
- ZygoteStartFailedEx(Throwable cause) {
- super(cause);
- }
-
- ZygoteStartFailedEx(String s, Throwable cause) {
- super(s, cause);
- }
-}
/**
* Tools for managing OS processes.
@@ -387,83 +362,11 @@ public class Process {
private static long sStartUptimeMillis;
/**
- * State for communicating with the zygote process.
- *
- * @hide for internal use only.
- */
- public static class ZygoteState {
- final LocalSocket socket;
- final DataInputStream inputStream;
- final BufferedWriter writer;
- final List<String> abiList;
-
- boolean mClosed;
-
- private ZygoteState(LocalSocket socket, DataInputStream inputStream,
- BufferedWriter writer, List<String> abiList) {
- this.socket = socket;
- this.inputStream = inputStream;
- this.writer = writer;
- this.abiList = abiList;
- }
-
- public static ZygoteState connect(String socketAddress) throws IOException {
- DataInputStream zygoteInputStream = null;
- BufferedWriter zygoteWriter = null;
- final LocalSocket zygoteSocket = new LocalSocket();
-
- try {
- zygoteSocket.connect(new LocalSocketAddress(socketAddress,
- LocalSocketAddress.Namespace.RESERVED));
-
- zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
-
- zygoteWriter = new BufferedWriter(new OutputStreamWriter(
- zygoteSocket.getOutputStream()), 256);
- } catch (IOException ex) {
- try {
- zygoteSocket.close();
- } catch (IOException ignore) {
- }
-
- throw ex;
- }
-
- String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
- Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);
-
- return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
- Arrays.asList(abiListString.split(",")));
- }
-
- boolean matches(String abi) {
- return abiList.contains(abi);
- }
-
- public void close() {
- try {
- socket.close();
- } catch (IOException ex) {
- Log.e(LOG_TAG,"I/O exception on routine close", ex);
- }
-
- mClosed = true;
- }
-
- boolean isClosed() {
- return mClosed;
- }
- }
-
- /**
- * The state of the connection to the primary zygote.
- */
- static ZygoteState primaryZygoteState;
-
- /**
- * The state of the connection to the secondary zygote.
+ * State associated with the zygote process.
+ * @hide
*/
- static ZygoteState secondaryZygoteState;
+ public static final ZygoteProcess zygoteProcess =
+ new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
/**
* Start a new process.
@@ -509,263 +412,9 @@ public class Process {
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
- try {
- return startViaZygote(processClass, niceName, uid, gid, gids,
+ return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
- } catch (ZygoteStartFailedEx ex) {
- Log.e(LOG_TAG,
- "Starting VM process through Zygote failed");
- throw new RuntimeException(
- "Starting VM process through Zygote failed", ex);
- }
- }
-
- /** retry interval for opening a zygote socket */
- static final int ZYGOTE_RETRY_MILLIS = 500;
-
- /**
- * Queries the zygote for the list of ABIS it supports.
- *
- * @throws ZygoteStartFailedEx if the query failed.
- */
- private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
- throws IOException {
- // Each query starts with the argument count (1 in this case)
- writer.write("1");
- // ... followed by a new-line.
- writer.newLine();
- // ... followed by our only argument.
- writer.write("--query-abi-list");
- writer.newLine();
- writer.flush();
-
- // The response is a length prefixed stream of ASCII bytes.
- int numBytes = inputStream.readInt();
- byte[] bytes = new byte[numBytes];
- inputStream.readFully(bytes);
-
- return new String(bytes, StandardCharsets.US_ASCII);
- }
-
- /**
- * Sends an argument list to the zygote process, which starts a new child
- * and returns the child's pid. Please note: the present implementation
- * replaces newlines in the argument list with spaces.
- *
- * @throws ZygoteStartFailedEx if process start failed for any reason
- */
- private static ProcessStartResult zygoteSendArgsAndGetResult(
- ZygoteState zygoteState, ArrayList<String> args)
- throws ZygoteStartFailedEx {
- try {
- /**
- * See com.android.internal.os.ZygoteInit.readArgumentList()
- * Presently the wire format to the zygote process is:
- * a) a count of arguments (argc, in essence)
- * b) a number of newline-separated argument strings equal to count
- *
- * After the zygote process reads these it will write the pid of
- * the child or -1 on failure, followed by boolean to
- * indicate whether a wrapper process was used.
- */
- final BufferedWriter writer = zygoteState.writer;
- final DataInputStream inputStream = zygoteState.inputStream;
-
- writer.write(Integer.toString(args.size()));
- writer.newLine();
-
- int sz = args.size();
- for (int i = 0; i < sz; i++) {
- String arg = args.get(i);
- if (arg.indexOf('\n') >= 0) {
- throw new ZygoteStartFailedEx(
- "embedded newlines not allowed");
- }
- writer.write(arg);
- writer.newLine();
- }
-
- writer.flush();
-
- // Should there be a timeout on this?
- ProcessStartResult result = new ProcessStartResult();
- result.pid = inputStream.readInt();
- if (result.pid < 0) {
- throw new ZygoteStartFailedEx("fork() failed");
- }
- result.usingWrapper = inputStream.readBoolean();
- return result;
- } catch (IOException ex) {
- zygoteState.close();
- throw new ZygoteStartFailedEx(ex);
- }
- }
-
- /**
- * Starts a new process via the zygote mechanism.
- *
- * @param processClass Class name whose static main() to run
- * @param niceName 'nice' process name to appear in ps
- * @param uid a POSIX uid that the new process should setuid() to
- * @param gid a POSIX gid that the new process shuold setgid() to
- * @param gids null-ok; a list of supplementary group IDs that the
- * new process should setgroup() to.
- * @param debugFlags Additional flags.
- * @param targetSdkVersion The target SDK version for the app.
- * @param seInfo null-ok SELinux information for the new process.
- * @param abi the ABI the process should use.
- * @param instructionSet null-ok the instruction set to use.
- * @param appDataDir null-ok the data directory of the app.
- * @param extraArgs Additional arguments to supply to the zygote process.
- * @return An object that describes the result of the attempt to start the process.
- * @throws ZygoteStartFailedEx if process start failed for any reason
- */
- private static ProcessStartResult startViaZygote(final String processClass,
- final String niceName,
- final int uid, final int gid,
- final int[] gids,
- int debugFlags, int mountExternal,
- int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String[] extraArgs)
- throws ZygoteStartFailedEx {
- synchronized(Process.class) {
- ArrayList<String> argsForZygote = new ArrayList<String>();
-
- // --runtime-args, --setuid=, --setgid=,
- // and --setgroups= must go first
- argsForZygote.add("--runtime-args");
- argsForZygote.add("--setuid=" + uid);
- argsForZygote.add("--setgid=" + gid);
- if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
- argsForZygote.add("--enable-jni-logging");
- }
- if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
- argsForZygote.add("--enable-safemode");
- }
- if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
- argsForZygote.add("--enable-debugger");
- }
- if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
- argsForZygote.add("--enable-checkjni");
- }
- if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
- argsForZygote.add("--generate-debug-info");
- }
- if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
- argsForZygote.add("--always-jit");
- }
- if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
- argsForZygote.add("--native-debuggable");
- }
- if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
- argsForZygote.add("--enable-assert");
- }
- if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
- argsForZygote.add("--mount-external-default");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
- argsForZygote.add("--mount-external-read");
- } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
- argsForZygote.add("--mount-external-write");
- }
- argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
-
- //TODO optionally enable debuger
- //argsForZygote.add("--enable-debugger");
-
- // --setgroups is a comma-separated list
- if (gids != null && gids.length > 0) {
- StringBuilder sb = new StringBuilder();
- sb.append("--setgroups=");
-
- int sz = gids.length;
- for (int i = 0; i < sz; i++) {
- if (i != 0) {
- sb.append(',');
- }
- sb.append(gids[i]);
- }
-
- argsForZygote.add(sb.toString());
- }
-
- if (niceName != null) {
- argsForZygote.add("--nice-name=" + niceName);
- }
-
- if (seInfo != null) {
- argsForZygote.add("--seinfo=" + seInfo);
- }
-
- if (instructionSet != null) {
- argsForZygote.add("--instruction-set=" + instructionSet);
- }
-
- if (appDataDir != null) {
- argsForZygote.add("--app-data-dir=" + appDataDir);
- }
-
- argsForZygote.add(processClass);
-
- if (extraArgs != null) {
- for (String arg : extraArgs) {
- argsForZygote.add(arg);
- }
- }
-
- return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
- }
- }
-
- /**
- * Tries to establish a connection to the zygote that handles a given {@code abi}. Might block and retry if the
- * zygote is unresponsive. This method is a no-op if a connection is already open.
- *
- * @hide
- */
- public static void establishZygoteConnectionForAbi(String abi) {
- try {
- openZygoteSocketIfNeeded(abi);
- } catch (ZygoteStartFailedEx ex) {
- throw new RuntimeException("Unable to connect to zygote for abi: " + abi, ex);
- }
- }
-
- /**
- * Tries to open socket to Zygote process if not already open. If
- * already open, does nothing. May block and retry.
- */
- private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
- if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
- try {
- primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
- } catch (IOException ioe) {
- throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
- }
- }
-
- if (primaryZygoteState.matches(abi)) {
- return primaryZygoteState;
- }
-
- // The primary zygote didn't match. Try the secondary.
- if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
- try {
- secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
- } catch (IOException ioe) {
- throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
- }
- }
-
- if (secondaryZygoteState.matches(abi)) {
- return secondaryZygoteState;
- }
-
- throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
/**