diff options
| author | Robert Sesek <rsesek@google.com> | 2016-03-18 16:52:57 -0400 |
|---|---|---|
| committer | Robert Sesek <rsesek@google.com> | 2016-09-09 12:42:52 -0400 |
| commit | 96b49848e7784bc4b40ffd01e2524461e1efcab7 (patch) | |
| tree | 091cd1071de89ffe64bd1dae930f4ef2e402fe49 /core/java/android/os/Process.java | |
| parent | b9679dc1fad508a001e30a941148e1bdc3fe953f (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.java | 361 |
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); } /** |
