diff options
-rw-r--r-- | core/java/android/os/Process.java | 361 | ||||
-rw-r--r-- | core/java/android/os/ZygoteProcess.java | 447 | ||||
-rw-r--r-- | core/java/com/android/internal/os/RuntimeInit.java | 10 | ||||
-rw-r--r-- | core/java/com/android/internal/os/WebViewZygoteInit.java | 32 | ||||
-rw-r--r-- | core/java/com/android/internal/os/WrapperInit.java | 4 | ||||
-rw-r--r-- | core/java/com/android/internal/os/Zygote.java | 38 | ||||
-rw-r--r-- | core/java/com/android/internal/os/ZygoteConnection.java | 17 | ||||
-rw-r--r-- | core/java/com/android/internal/os/ZygoteInit.java | 197 | ||||
-rw-r--r-- | core/java/com/android/internal/os/ZygoteServer.java | 167 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 2 | ||||
-rw-r--r-- | services/core/java/com/android/server/net/NetworkPolicyManagerService.java | 19 |
11 files changed, 571 insertions, 723 deletions
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 6aa9fac8d48b..f664e70cf7be 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 @@ public class Process { 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 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. */ - public static final ZygoteProcess zygoteProcess = - new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET); + static ZygoteState primaryZygoteState; + + /** + * The state of the connection to the secondary zygote. + */ + static ZygoteState secondaryZygoteState; /** * Start a new process. @@ -412,9 +509,263 @@ public class Process { 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 d7a72960f4c4..000000000000 --- 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 c851e4ec959a..de671b1ab98d 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -230,7 +230,7 @@ public class RuntimeInit { * @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 @@ public class RuntimeInit { * 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 @@ public class RuntimeInit { * @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 @@ public class RuntimeInit { * @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 2ed7aa214ccd..000000000000 --- 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 594b6ab72ef3..c558cf8d1ee7 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -74,14 +74,14 @@ public class WrapperInit { } } - // 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 fc0ccb75de95..66cc97598ae8 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -22,9 +22,6 @@ import dalvik.system.ZygoteHooks; 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 @@ public final class Zygote { 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 132b02236ab9..85d84bb3f986 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -117,7 +117,7 @@ class ZygoteConnection { /** * 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 @@ class ZygoteConnection { * * @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 @@ class ZygoteConnection { fdsToClose[0] = fd.getInt$(); } - fd = zygoteServer.getServerSocketFileDescriptor(); + fd = ZygoteInit.getServerSocketFileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); @@ -238,13 +238,12 @@ class ZygoteConnection { 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 @@ class ZygoteConnection { * @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 @@ class ZygoteConnection { */ 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 52b72a4e9991..9efa83361166 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.Process; 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 dalvik.system.ZygoteHooks; 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 @@ public class ZygoteInit { 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 @@ public class ZygoteInit { 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 @@ public class ZygoteInit { /** 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 @@ public class ZygoteInit { */ 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 @@ public class ZygoteInit { /** * 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 @@ public class ZygoteInit { waitForSecondaryZygote(socketName); } - zygoteServer.closeServerSocket(); handleSystemServerProcess(parsedArgs); } @@ -604,8 +687,6 @@ public class ZygoteInit { } 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 @@ public class ZygoteInit { 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 @@ public class ZygoteInit { 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 @@ public class ZygoteInit { 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 @@ public class ZygoteInit { 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 @@ public class ZygoteInit { } /** + * 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 ab87641006a5..000000000000 --- 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 0a7c26f81c86..7ac139f62f45 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6705,7 +6705,7 @@ public final class ActivityManagerService extends ActivityManagerNative 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 5ae408bd01eb..330f46a3c95a 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 android.util.Xml; 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private final AppOpsManager mAppOps; + private final MyPackageMonitor mPackageMonitor; private final IPackageManager mIPm; @@ -409,6 +411,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + 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 |