Merge "Fix parameter description"
am: 750b523aa2
Change-Id: I5edb7e6910b92d3c2f93a61fc9e68489ece8e72f
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 6aa9fac..f664e70 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,9 +16,34 @@
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.
@@ -362,11 +387,83 @@
private static long sStartUptimeMillis;
/**
- * State associated with the zygote process.
- * @hide
+ * State for communicating with the zygote process.
+ *
+ * @hide for internal use only.
*/
- public static final ZygoteProcess zygoteProcess =
- new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
+ 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.
+ */
+ static ZygoteState secondaryZygoteState;
/**
* Start a new process.
@@ -412,9 +509,263 @@
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
- return zygoteProcess.start(processClass, niceName, uid, gid, gids,
+ try {
+ return startViaZygote(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);
}
/**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
deleted file mode 100644
index d7a7296..0000000
--- a/core/java/android/os/ZygoteProcess.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.os;
-
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.util.Log;
-import com.android.internal.os.Zygote;
-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);
- }
-}
-
-/**
- * Maintains communication state with the zygote processes. This class is responsible
- * for the sockets opened to the zygotes and for starting processes on behalf of the
- * {@link android.os.Process} class.
- *
- * {@hide}
- */
-public class ZygoteProcess {
- private static final String LOG_TAG = "ZygoteProcess";
-
- /**
- * The name of the socket used to communicate with the primary zygote.
- */
- private final String mSocket;
-
- /**
- * The name of the secondary (alternate ABI) zygote socket.
- */
- private final String mSecondarySocket;
-
- public ZygoteProcess(String primarySocket, String secondarySocket) {
- mSocket = primarySocket;
- mSecondarySocket = secondarySocket;
- }
-
- /**
- * State for communicating with the zygote process.
- */
- 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.
- */
- private ZygoteState primaryZygoteState;
-
- /**
- * The state of the connection to the secondary zygote.
- */
- private ZygoteState secondaryZygoteState;
-
- /**
- * Start a new process.
- *
- * <p>If processes are enabled, a new process is created and the
- * static main() function of a <var>processClass</var> is executed there.
- * The process will continue running after this function returns.
- *
- * <p>If processes are not enabled, a new thread in the caller's
- * process is created and main() of <var>processClass</var> called there.
- *
- * <p>The niceName parameter, if not an empty string, is a custom name to
- * give to the process instead of using processClass. This allows you to
- * make easily identifyable processes even if you are using the same base
- * <var>processClass</var> to start them.
- *
- * @param processClass The class to use as the process's main entry
- * point.
- * @param niceName A more readable name to use for the process.
- * @param uid The user-id under which the process will run.
- * @param gid The group-id under which the process will run.
- * @param gids Additional group-ids associated with the process.
- * @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 non-null the ABI this app should be started with.
- * @param instructionSet null-ok the instruction set to use.
- * @param appDataDir null-ok the data directory of the app.
- * @param zygoteArgs Additional arguments to supply to the zygote process.
- *
- * @return An object that describes the result of the attempt to start the process.
- * @throws RuntimeException on fatal start failure
- */
- public final Process.ProcessStartResult start(final String processClass,
- final String niceName,
- int uid, int gid, int[] gids,
- int debugFlags, int mountExternal,
- int targetSdkVersion,
- String seInfo,
- String abi,
- String instructionSet,
- String appDataDir,
- String[] zygoteArgs) {
- try {
- return startViaZygote(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 Process.ProcessStartResult zygoteSendArgsAndGetResult(
- ZygoteState zygoteState, ArrayList<String> args)
- throws ZygoteStartFailedEx {
- try {
- /**
- * See com.android.internal.os.SystemZygoteInit.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?
- Process.ProcessStartResult result = new Process.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 Process.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.
- */
- public 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 ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
- if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
- try {
- primaryZygoteState = ZygoteState.connect(mSocket);
- } 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(mSecondarySocket);
- } 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);
- }
-}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index c851e4e..de671b1 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -230,7 +230,7 @@
* @param classLoader the classLoader to load {@className} with
*/
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
- throws Zygote.MethodAndArgsCaller {
+ throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
@@ -264,7 +264,7 @@
* clears up all the stack frames that were required in setting
* up the process.
*/
- throw new Zygote.MethodAndArgsCaller(m, argv);
+ throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
public static final void main(String[] argv) {
@@ -301,7 +301,7 @@
* @param argv arg strings
*/
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
- throws Zygote.MethodAndArgsCaller {
+ throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
@@ -324,14 +324,14 @@
* @param argv arg strings
*/
public static void wrapperInit(int targetSdkVersion, String[] argv)
- throws Zygote.MethodAndArgsCaller {
+ throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
applicationInit(targetSdkVersion, argv, null);
}
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
- throws Zygote.MethodAndArgsCaller {
+ throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
deleted file mode 100644
index 2ed7aa2..0000000
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2016 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.internal.os;
-
-/**
- * Startup class for the WebView zygote process.
- *
- * See {@link ZygoteInit} for generic zygote startup documentation.
- *
- * @hide
- */
-class WebViewZygoteInit {
- public static final String TAG = "WebViewZygoteInit";
-
- public static void main(String argv[]) {
- throw new RuntimeException("Not implemented yet");
- }
-}
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 594b6ab..c558cf8 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -74,14 +74,14 @@
}
}
- // Mimic system Zygote preloading.
+ // Mimic Zygote preloading.
ZygoteInit.preload();
// Launch the application.
String[] runtimeArgs = new String[args.length - 2];
System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
- } catch (Zygote.MethodAndArgsCaller caller) {
+ } catch (ZygoteInit.MethodAndArgsCaller caller) {
caller.run();
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index fc0ccb7..66cc975 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -22,9 +22,6 @@
import android.system.ErrnoException;
import android.system.Os;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
/** @hide */
public final class Zygote {
/*
@@ -194,39 +191,4 @@
command.append(" '").append(arg.replace("'", "'\\''")).append("'");
}
}
-
- /**
- * Helper exception class which holds a method and arguments and
- * can call them. This is used as part of a trampoline to get rid of
- * the initial process setup stack frames.
- */
- public static class MethodAndArgsCaller extends Exception
- implements Runnable {
- /** method to call */
- private final Method mMethod;
-
- /** argument array */
- private final String[] mArgs;
-
- public MethodAndArgsCaller(Method method, String[] args) {
- mMethod = method;
- mArgs = args;
- }
-
- public void run() {
- try {
- mMethod.invoke(null, new Object[] { mArgs });
- } catch (IllegalAccessException ex) {
- throw new RuntimeException(ex);
- } catch (InvocationTargetException ex) {
- Throwable cause = ex.getCause();
- if (cause instanceof RuntimeException) {
- throw (RuntimeException) cause;
- } else if (cause instanceof Error) {
- throw (Error) cause;
- }
- throw new RuntimeException(ex);
- }
- }
- }
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 132b022..85d84bb 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -117,7 +117,7 @@
/**
* Reads one start command from the command socket. If successful,
- * a child is forked and a {@link Zygote.MethodAndArgsCaller}
+ * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
* exception is thrown in that child while in the parent process,
* the method returns normally. On failure, the child is not
* spawned and messages are printed to the log and stderr. Returns
@@ -126,10 +126,10 @@
*
* @return false if command socket should continue to be read from, or
* true if an end-of-file has been encountered.
- * @throws Zygote.MethodAndArgsCaller trampoline to invoke main()
+ * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
* method in child process
*/
- boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
+ boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
@@ -214,7 +214,7 @@
fdsToClose[0] = fd.getInt$();
}
- fd = zygoteServer.getServerSocketFileDescriptor();
+ fd = ZygoteInit.getServerSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
@@ -238,13 +238,12 @@
try {
if (pid == 0) {
// in child
- zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
- // throw Zygote.MethodAndArgsCaller or exec().
+ // throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {
// in parent...pid of < 0 means failure
@@ -713,12 +712,12 @@
* @param newStderr null-ok; stream to use for stderr until stdio
* is reopened.
*
- * @throws Zygote.MethodAndArgsCaller on success to
+ * @throws ZygoteInit.MethodAndArgsCaller on success to
* trampoline to code that invokes static main.
*/
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
- throws Zygote.MethodAndArgsCaller {
+ throws ZygoteInit.MethodAndArgsCaller {
/**
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
@@ -726,6 +725,8 @@
*/
closeSocket();
+ ZygoteInit.closeServerSocket();
+
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 52b72a4..9efa833 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import static android.system.OsConstants.POLLIN;
import static android.system.OsConstants.S_IRWXG;
import static android.system.OsConstants.S_IRWXO;
@@ -30,11 +31,11 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
-import android.os.ZygoteProcess;
import android.security.keystore.AndroidKeyStoreProvider;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.system.StructPollfd;
import android.text.Hyphenator;
import android.util.EventLog;
import android.util.Log;
@@ -51,13 +52,17 @@
import libcore.io.IoUtils;
import java.io.BufferedReader;
+import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.security.Security;
import java.security.Provider;
+import java.util.ArrayList;
/**
* Startup class for the zygote process.
@@ -77,6 +82,8 @@
private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container";
+ private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
+
private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
@@ -87,8 +94,11 @@
private static final String SOCKET_NAME_ARG = "--socket-name=";
+ private static LocalServerSocket sServerSocket;
+
/**
- * Used to pre-load resources.
+ * Used to pre-load resources. We hold a global reference on it so it
+ * never gets destroyed.
*/
private static Resources mResources;
@@ -100,6 +110,78 @@
/** Controls whether we should preload resources during zygote init. */
public static final boolean PRELOAD_RESOURCES = true;
+ /**
+ * Registers a server socket for zygote command connections
+ *
+ * @throws RuntimeException when open fails
+ */
+ private static void registerZygoteSocket(String socketName) {
+ if (sServerSocket == null) {
+ int fileDesc;
+ final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
+ try {
+ String env = System.getenv(fullSocketName);
+ fileDesc = Integer.parseInt(env);
+ } catch (RuntimeException ex) {
+ throw new RuntimeException(fullSocketName + " unset or invalid", ex);
+ }
+
+ try {
+ FileDescriptor fd = new FileDescriptor();
+ fd.setInt$(fileDesc);
+ sServerSocket = new LocalServerSocket(fd);
+ } catch (IOException ex) {
+ throw new RuntimeException(
+ "Error binding to local socket '" + fileDesc + "'", ex);
+ }
+ }
+ }
+
+ /**
+ * Waits for and accepts a single command connection. Throws
+ * RuntimeException on failure.
+ */
+ private static ZygoteConnection acceptCommandPeer(String abiList) {
+ try {
+ return new ZygoteConnection(sServerSocket.accept(), abiList);
+ } catch (IOException ex) {
+ throw new RuntimeException(
+ "IOException during accept()", ex);
+ }
+ }
+
+ /**
+ * Close and clean up zygote sockets. Called on shutdown and on the
+ * child's exit path.
+ */
+ static void closeServerSocket() {
+ try {
+ if (sServerSocket != null) {
+ FileDescriptor fd = sServerSocket.getFileDescriptor();
+ sServerSocket.close();
+ if (fd != null) {
+ Os.close(fd);
+ }
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Zygote: error closing sockets", ex);
+ } catch (ErrnoException ex) {
+ Log.e(TAG, "Zygote: error closing descriptor", ex);
+ }
+
+ sServerSocket = null;
+ }
+
+ /**
+ * Return the server socket's underlying file descriptor, so that
+ * ZygoteConnection can pass it to the native code for proper
+ * closure after a child process is forked off.
+ */
+
+ static FileDescriptor getServerSocketFileDescriptor() {
+ return sServerSocket.getFileDescriptor();
+ }
+
private static final int UNPRIVILEGED_UID = 9999;
private static final int UNPRIVILEGED_GID = 9999;
@@ -422,7 +504,9 @@
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
- throws Zygote.MethodAndArgsCaller {
+ throws ZygoteInit.MethodAndArgsCaller {
+
+ closeServerSocket();
// set umask to 0077 so new files and directories will default to owner-only permissions.
Os.umask(S_IRWXG | S_IRWXO);
@@ -525,8 +609,8 @@
/**
* Prepare the arguments and fork for the system server process.
*/
- private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
- throws Zygote.MethodAndArgsCaller, RuntimeException {
+ private static boolean startSystemServer(String abiList, String socketName)
+ throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_IPC_LOCK,
OsConstants.CAP_KILL,
@@ -582,7 +666,6 @@
waitForSecondaryZygote(socketName);
}
- zygoteServer.closeServerSocket();
handleSystemServerProcess(parsedArgs);
}
@@ -604,8 +687,6 @@
}
public static void main(String argv[]) {
- ZygoteServer zygoteServer = new ZygoteServer();
-
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
@@ -642,7 +723,7 @@
throw new RuntimeException("No ABI list supplied.");
}
- zygoteServer.registerServerSocket(socketName);
+ registerZygoteSocket(socketName);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
@@ -659,6 +740,8 @@
gcAndFinalize();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
@@ -669,18 +752,18 @@
ZygoteHooks.stopZygoteNoThreadCreation();
if (startSystemServer) {
- startSystemServer(abiList, socketName, zygoteServer);
+ startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
- zygoteServer.runSelectLoop(abiList);
+ runSelectLoop(abiList);
- zygoteServer.closeServerSocket();
- } catch (Zygote.MethodAndArgsCaller caller) {
+ closeServerSocket();
+ } catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
- Log.e(TAG, "System zygote died with exception", ex);
- zygoteServer.closeServerSocket();
+ Log.e(TAG, "Zygote died with exception", ex);
+ closeServerSocket();
throw ex;
}
}
@@ -701,8 +784,7 @@
Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
while (true) {
try {
- final ZygoteProcess.ZygoteState zs =
- ZygoteProcess.ZygoteState.connect(otherZygoteName);
+ final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName);
zs.close();
break;
} catch (IOException ioe) {
@@ -717,8 +799,89 @@
}
/**
+ * Runs the zygote process's select loop. Accepts new connections as
+ * they happen, and reads commands from connections one spawn-request's
+ * worth at a time.
+ *
+ * @throws MethodAndArgsCaller in a child process when a main() should
+ * be executed.
+ */
+ private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
+ ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
+ ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
+
+ fds.add(sServerSocket.getFileDescriptor());
+ peers.add(null);
+
+ while (true) {
+ StructPollfd[] pollFds = new StructPollfd[fds.size()];
+ for (int i = 0; i < pollFds.length; ++i) {
+ pollFds[i] = new StructPollfd();
+ pollFds[i].fd = fds.get(i);
+ pollFds[i].events = (short) POLLIN;
+ }
+ try {
+ Os.poll(pollFds, -1);
+ } catch (ErrnoException ex) {
+ throw new RuntimeException("poll failed", ex);
+ }
+ for (int i = pollFds.length - 1; i >= 0; --i) {
+ if ((pollFds[i].revents & POLLIN) == 0) {
+ continue;
+ }
+ if (i == 0) {
+ ZygoteConnection newPeer = acceptCommandPeer(abiList);
+ peers.add(newPeer);
+ fds.add(newPeer.getFileDesciptor());
+ } else {
+ boolean done = peers.get(i).runOnce();
+ if (done) {
+ peers.remove(i);
+ fds.remove(i);
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Class not instantiable.
*/
private ZygoteInit() {
}
+
+ /**
+ * Helper exception class which holds a method and arguments and
+ * can call them. This is used as part of a trampoline to get rid of
+ * the initial process setup stack frames.
+ */
+ public static class MethodAndArgsCaller extends Exception
+ implements Runnable {
+ /** method to call */
+ private final Method mMethod;
+
+ /** argument array */
+ private final String[] mArgs;
+
+ public MethodAndArgsCaller(Method method, String[] args) {
+ mMethod = method;
+ mArgs = args;
+ }
+
+ public void run() {
+ try {
+ mMethod.invoke(null, new Object[] { mArgs });
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+ } catch (InvocationTargetException ex) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ }
+ throw new RuntimeException(ex);
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
deleted file mode 100644
index ab876410..0000000
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2007 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.internal.os;
-
-import static android.system.OsConstants.POLLIN;
-
-import android.net.LocalServerSocket;
-import android.system.Os;
-import android.system.ErrnoException;
-import android.system.StructPollfd;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.FileDescriptor;
-import java.util.ArrayList;
-
-/**
- * Server socket class for zygote processes.
- *
- * Provides functions to wait for commands on a UNIX domain socket, and fork
- * off child processes that inherit the initial state of the VM.%
- *
- * Please see {@link ZygoteConnection.Arguments} for documentation on the
- * client protocol.
- */
-class ZygoteServer {
- public static final String TAG = "ZygoteServer";
-
- private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
-
- private LocalServerSocket mServerSocket;
-
- ZygoteServer() {
- }
-
- /**
- * Registers a server socket for zygote command connections
- *
- * @throws RuntimeException when open fails
- */
- void registerServerSocket(String socketName) {
- if (mServerSocket == null) {
- int fileDesc;
- final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
- try {
- String env = System.getenv(fullSocketName);
- fileDesc = Integer.parseInt(env);
- } catch (RuntimeException ex) {
- throw new RuntimeException(fullSocketName + " unset or invalid", ex);
- }
-
- try {
- FileDescriptor fd = new FileDescriptor();
- fd.setInt$(fileDesc);
- mServerSocket = new LocalServerSocket(fd);
- } catch (IOException ex) {
- throw new RuntimeException(
- "Error binding to local socket '" + fileDesc + "'", ex);
- }
- }
- }
-
- /**
- * Waits for and accepts a single command connection. Throws
- * RuntimeException on failure.
- */
- private ZygoteConnection acceptCommandPeer(String abiList) {
- try {
- return new ZygoteConnection(mServerSocket.accept(), abiList);
- } catch (IOException ex) {
- throw new RuntimeException(
- "IOException during accept()", ex);
- }
- }
-
- /**
- * Close and clean up zygote sockets. Called on shutdown and on the
- * child's exit path.
- */
- void closeServerSocket() {
- try {
- if (mServerSocket != null) {
- FileDescriptor fd = mServerSocket.getFileDescriptor();
- mServerSocket.close();
- if (fd != null) {
- Os.close(fd);
- }
- }
- } catch (IOException ex) {
- Log.e(TAG, "Zygote: error closing sockets", ex);
- } catch (ErrnoException ex) {
- Log.e(TAG, "Zygote: error closing descriptor", ex);
- }
-
- mServerSocket = null;
- }
-
- /**
- * Return the server socket's underlying file descriptor, so that
- * ZygoteConnection can pass it to the native code for proper
- * closure after a child process is forked off.
- */
-
- FileDescriptor getServerSocketFileDescriptor() {
- return mServerSocket.getFileDescriptor();
- }
-
- /**
- * Runs the zygote process's select loop. Accepts new connections as
- * they happen, and reads commands from connections one spawn-request's
- * worth at a time.
- *
- * @throws Zygote.MethodAndArgsCaller in a child process when a main()
- * should be executed.
- */
- void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
- ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
- ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
-
- fds.add(mServerSocket.getFileDescriptor());
- peers.add(null);
-
- while (true) {
- StructPollfd[] pollFds = new StructPollfd[fds.size()];
- for (int i = 0; i < pollFds.length; ++i) {
- pollFds[i] = new StructPollfd();
- pollFds[i].fd = fds.get(i);
- pollFds[i].events = (short) POLLIN;
- }
- try {
- Os.poll(pollFds, -1);
- } catch (ErrnoException ex) {
- throw new RuntimeException("poll failed", ex);
- }
- for (int i = pollFds.length - 1; i >= 0; --i) {
- if ((pollFds[i].revents & POLLIN) == 0) {
- continue;
- }
- if (i == 0) {
- ZygoteConnection newPeer = acceptCommandPeer(abiList);
- peers.add(newPeer);
- fds.add(newPeer.getFileDesciptor());
- } else {
- boolean done = peers.get(i).runOnce(this);
- if (done) {
- peers.remove(i);
- fds.remove(i);
- }
- }
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 867168a..08b204a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6703,7 +6703,7 @@
ArraySet<String> completedIsas = new ArraySet<String>();
for (String abi : Build.SUPPORTED_ABIS) {
- Process.zygoteProcess.establishZygoteConnectionForAbi(abi);
+ Process.establishZygoteConnectionForAbi(abi);
final String instructionSet = VMRuntime.getInstructionSet(abi);
if (!completedIsas.contains(instructionSet)) {
try {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5ae408b..330f46a 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -163,6 +163,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -365,6 +366,7 @@
private final AppOpsManager mAppOps;
+ private final MyPackageMonitor mPackageMonitor;
private final IPackageManager mIPm;
@@ -409,6 +411,8 @@
mAppOps = context.getSystemService(AppOpsManager.class);
+ mPackageMonitor = new MyPackageMonitor();
+
// Expose private service for system components to use.
LocalServices.addService(NetworkPolicyManagerInternal.class,
new NetworkPolicyManagerInternalImpl());
@@ -536,6 +540,8 @@
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+ mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+
synchronized (mRulesLock) {
updatePowerSaveWhitelistLocked();
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -725,7 +731,6 @@
if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
synchronized (mRulesLock) {
mUidPolicy.delete(uid);
- removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
updateRestrictionRulesForUidLocked(uid);
writePolicyLocked();
}
@@ -3474,6 +3479,18 @@
}
}
+ private class MyPackageMonitor extends PackageMonitor {
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ if (LOGV) Slog.v(TAG, "onPackageRemoved: " + packageName + " ->" + uid);
+ synchronized (mRulesLock) {
+ removeRestrictBackgroundWhitelistedUidLocked(uid, true, true);
+ updateRestrictionRulesForUidLocked(uid);
+ }
+ }
+ }
+
private class NetworkPolicyManagerInternalImpl extends NetworkPolicyManagerInternal {
@Override