Merge "Refactor ZygoteInit to support a WebView-specific zygote." into stage-aosp-master
This commit is contained in:
committed by
Android (Google) Code Review
commit
38bfbf8d2a
@@ -230,7 +230,7 @@ public class RuntimeInit {
|
|||||||
* @param classLoader the classLoader to load {@className} with
|
* @param classLoader the classLoader to load {@className} with
|
||||||
*/
|
*/
|
||||||
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
|
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
|
||||||
throws ZygoteInit.MethodAndArgsCaller {
|
throws Zygote.MethodAndArgsCaller {
|
||||||
Class<?> cl;
|
Class<?> cl;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -264,7 +264,7 @@ public class RuntimeInit {
|
|||||||
* clears up all the stack frames that were required in setting
|
* clears up all the stack frames that were required in setting
|
||||||
* up the process.
|
* up the process.
|
||||||
*/
|
*/
|
||||||
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
|
throw new Zygote.MethodAndArgsCaller(m, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final void main(String[] argv) {
|
public static final void main(String[] argv) {
|
||||||
@@ -301,7 +301,7 @@ public class RuntimeInit {
|
|||||||
* @param argv arg strings
|
* @param argv arg strings
|
||||||
*/
|
*/
|
||||||
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
|
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
|
||||||
throws ZygoteInit.MethodAndArgsCaller {
|
throws Zygote.MethodAndArgsCaller {
|
||||||
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
|
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
|
||||||
|
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
|
||||||
@@ -324,14 +324,14 @@ public class RuntimeInit {
|
|||||||
* @param argv arg strings
|
* @param argv arg strings
|
||||||
*/
|
*/
|
||||||
public static void wrapperInit(int targetSdkVersion, String[] argv)
|
public static void wrapperInit(int targetSdkVersion, String[] argv)
|
||||||
throws ZygoteInit.MethodAndArgsCaller {
|
throws Zygote.MethodAndArgsCaller {
|
||||||
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
|
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from wrapper");
|
||||||
|
|
||||||
applicationInit(targetSdkVersion, argv, null);
|
applicationInit(targetSdkVersion, argv, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
|
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
|
||||||
throws ZygoteInit.MethodAndArgsCaller {
|
throws Zygote.MethodAndArgsCaller {
|
||||||
// If the application calls System.exit(), terminate the process
|
// If the application calls System.exit(), terminate the process
|
||||||
// immediately without running any shutdown hooks. It is not possible to
|
// immediately without running any shutdown hooks. It is not possible to
|
||||||
// shutdown an Android application gracefully. Among other things, the
|
// shutdown an Android application gracefully. Among other things, the
|
||||||
|
|||||||
32
core/java/com/android/internal/os/WebViewZygoteInit.java
Normal file
32
core/java/com/android/internal/os/WebViewZygoteInit.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,14 +74,14 @@ public class WrapperInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mimic Zygote preloading.
|
// Mimic system Zygote preloading.
|
||||||
ZygoteInit.preload();
|
ZygoteInit.preload();
|
||||||
|
|
||||||
// Launch the application.
|
// Launch the application.
|
||||||
String[] runtimeArgs = new String[args.length - 2];
|
String[] runtimeArgs = new String[args.length - 2];
|
||||||
System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
|
System.arraycopy(args, 2, runtimeArgs, 0, runtimeArgs.length);
|
||||||
RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
|
RuntimeInit.wrapperInit(targetSdkVersion, runtimeArgs);
|
||||||
} catch (ZygoteInit.MethodAndArgsCaller caller) {
|
} catch (Zygote.MethodAndArgsCaller caller) {
|
||||||
caller.run();
|
caller.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import dalvik.system.ZygoteHooks;
|
|||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public final class Zygote {
|
public final class Zygote {
|
||||||
/*
|
/*
|
||||||
@@ -191,4 +194,39 @@ public final class Zygote {
|
|||||||
command.append(" '").append(arg.replace("'", "'\\''")).append("'");
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class ZygoteConnection {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads one start command from the command socket. If successful,
|
* Reads one start command from the command socket. If successful,
|
||||||
* a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
|
* a child is forked and a {@link Zygote.MethodAndArgsCaller}
|
||||||
* exception is thrown in that child while in the parent process,
|
* exception is thrown in that child while in the parent process,
|
||||||
* the method returns normally. On failure, the child is not
|
* the method returns normally. On failure, the child is not
|
||||||
* spawned and messages are printed to the log and stderr. Returns
|
* 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
|
* @return false if command socket should continue to be read from, or
|
||||||
* true if an end-of-file has been encountered.
|
* true if an end-of-file has been encountered.
|
||||||
* @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
|
* @throws Zygote.MethodAndArgsCaller trampoline to invoke main()
|
||||||
* method in child process
|
* method in child process
|
||||||
*/
|
*/
|
||||||
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
|
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
|
||||||
|
|
||||||
String args[];
|
String args[];
|
||||||
Arguments parsedArgs = null;
|
Arguments parsedArgs = null;
|
||||||
@@ -214,7 +214,7 @@ class ZygoteConnection {
|
|||||||
fdsToClose[0] = fd.getInt$();
|
fdsToClose[0] = fd.getInt$();
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = ZygoteInit.getServerSocketFileDescriptor();
|
fd = zygoteServer.getServerSocketFileDescriptor();
|
||||||
|
|
||||||
if (fd != null) {
|
if (fd != null) {
|
||||||
fdsToClose[1] = fd.getInt$();
|
fdsToClose[1] = fd.getInt$();
|
||||||
@@ -238,12 +238,13 @@ class ZygoteConnection {
|
|||||||
try {
|
try {
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// in child
|
// in child
|
||||||
|
zygoteServer.closeServerSocket();
|
||||||
IoUtils.closeQuietly(serverPipeFd);
|
IoUtils.closeQuietly(serverPipeFd);
|
||||||
serverPipeFd = null;
|
serverPipeFd = null;
|
||||||
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
|
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
|
||||||
|
|
||||||
// should never get here, the child is expected to either
|
// should never get here, the child is expected to either
|
||||||
// throw ZygoteInit.MethodAndArgsCaller or exec().
|
// throw Zygote.MethodAndArgsCaller or exec().
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
// in parent...pid of < 0 means failure
|
// in parent...pid of < 0 means failure
|
||||||
@@ -712,12 +713,12 @@ class ZygoteConnection {
|
|||||||
* @param newStderr null-ok; stream to use for stderr until stdio
|
* @param newStderr null-ok; stream to use for stderr until stdio
|
||||||
* is reopened.
|
* is reopened.
|
||||||
*
|
*
|
||||||
* @throws ZygoteInit.MethodAndArgsCaller on success to
|
* @throws Zygote.MethodAndArgsCaller on success to
|
||||||
* trampoline to code that invokes static main.
|
* trampoline to code that invokes static main.
|
||||||
*/
|
*/
|
||||||
private void handleChildProc(Arguments parsedArgs,
|
private void handleChildProc(Arguments parsedArgs,
|
||||||
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
|
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
|
||||||
throws ZygoteInit.MethodAndArgsCaller {
|
throws Zygote.MethodAndArgsCaller {
|
||||||
/**
|
/**
|
||||||
* By the time we get here, the native code has closed the two actual Zygote
|
* 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
|
* socket connections, and substituted /dev/null in their place. The LocalSocket
|
||||||
@@ -725,8 +726,6 @@ class ZygoteConnection {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
closeSocket();
|
closeSocket();
|
||||||
ZygoteInit.closeServerSocket();
|
|
||||||
|
|
||||||
if (descriptors != null) {
|
if (descriptors != null) {
|
||||||
try {
|
try {
|
||||||
Os.dup2(descriptors[0], STDIN_FILENO);
|
Os.dup2(descriptors[0], STDIN_FILENO);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package com.android.internal.os;
|
package com.android.internal.os;
|
||||||
|
|
||||||
import static android.system.OsConstants.POLLIN;
|
|
||||||
import static android.system.OsConstants.S_IRWXG;
|
import static android.system.OsConstants.S_IRWXG;
|
||||||
import static android.system.OsConstants.S_IRWXO;
|
import static android.system.OsConstants.S_IRWXO;
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ import android.security.keystore.AndroidKeyStoreProvider;
|
|||||||
import android.system.ErrnoException;
|
import android.system.ErrnoException;
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.system.StructPollfd;
|
|
||||||
import android.text.Hyphenator;
|
import android.text.Hyphenator;
|
||||||
import android.util.EventLog;
|
import android.util.EventLog;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -52,17 +50,13 @@ import dalvik.system.ZygoteHooks;
|
|||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Startup class for the zygote process.
|
* Startup class for the zygote process.
|
||||||
@@ -82,8 +76,6 @@ public class ZygoteInit {
|
|||||||
private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
|
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 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_START = 3020;
|
||||||
private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
|
private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
|
||||||
|
|
||||||
@@ -94,11 +86,8 @@ public class ZygoteInit {
|
|||||||
|
|
||||||
private static final String SOCKET_NAME_ARG = "--socket-name=";
|
private static final String SOCKET_NAME_ARG = "--socket-name=";
|
||||||
|
|
||||||
private static LocalServerSocket sServerSocket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to pre-load resources. We hold a global reference on it so it
|
* Used to pre-load resources.
|
||||||
* never gets destroyed.
|
|
||||||
*/
|
*/
|
||||||
private static Resources mResources;
|
private static Resources mResources;
|
||||||
|
|
||||||
@@ -110,78 +99,6 @@ public class ZygoteInit {
|
|||||||
/** Controls whether we should preload resources during zygote init. */
|
/** Controls whether we should preload resources during zygote init. */
|
||||||
public static final boolean PRELOAD_RESOURCES = true;
|
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_UID = 9999;
|
||||||
private static final int UNPRIVILEGED_GID = 9999;
|
private static final int UNPRIVILEGED_GID = 9999;
|
||||||
|
|
||||||
@@ -504,9 +421,7 @@ public class ZygoteInit {
|
|||||||
*/
|
*/
|
||||||
private static void handleSystemServerProcess(
|
private static void handleSystemServerProcess(
|
||||||
ZygoteConnection.Arguments parsedArgs)
|
ZygoteConnection.Arguments parsedArgs)
|
||||||
throws ZygoteInit.MethodAndArgsCaller {
|
throws Zygote.MethodAndArgsCaller {
|
||||||
|
|
||||||
closeServerSocket();
|
|
||||||
|
|
||||||
// set umask to 0077 so new files and directories will default to owner-only permissions.
|
// set umask to 0077 so new files and directories will default to owner-only permissions.
|
||||||
Os.umask(S_IRWXG | S_IRWXO);
|
Os.umask(S_IRWXG | S_IRWXO);
|
||||||
@@ -609,8 +524,8 @@ public class ZygoteInit {
|
|||||||
/**
|
/**
|
||||||
* Prepare the arguments and fork for the system server process.
|
* Prepare the arguments and fork for the system server process.
|
||||||
*/
|
*/
|
||||||
private static boolean startSystemServer(String abiList, String socketName)
|
private static boolean startSystemServer(String abiList, String socketName, ZygoteServer zygoteServer)
|
||||||
throws MethodAndArgsCaller, RuntimeException {
|
throws Zygote.MethodAndArgsCaller, RuntimeException {
|
||||||
long capabilities = posixCapabilitiesAsBits(
|
long capabilities = posixCapabilitiesAsBits(
|
||||||
OsConstants.CAP_IPC_LOCK,
|
OsConstants.CAP_IPC_LOCK,
|
||||||
OsConstants.CAP_KILL,
|
OsConstants.CAP_KILL,
|
||||||
@@ -666,6 +581,7 @@ public class ZygoteInit {
|
|||||||
waitForSecondaryZygote(socketName);
|
waitForSecondaryZygote(socketName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zygoteServer.closeServerSocket();
|
||||||
handleSystemServerProcess(parsedArgs);
|
handleSystemServerProcess(parsedArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,6 +603,8 @@ public class ZygoteInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String argv[]) {
|
public static void main(String argv[]) {
|
||||||
|
ZygoteServer zygoteServer = new ZygoteServer();
|
||||||
|
|
||||||
// Mark zygote start. This ensures that thread creation will throw
|
// Mark zygote start. This ensures that thread creation will throw
|
||||||
// an error.
|
// an error.
|
||||||
ZygoteHooks.startZygoteNoThreadCreation();
|
ZygoteHooks.startZygoteNoThreadCreation();
|
||||||
@@ -723,7 +641,7 @@ public class ZygoteInit {
|
|||||||
throw new RuntimeException("No ABI list supplied.");
|
throw new RuntimeException("No ABI list supplied.");
|
||||||
}
|
}
|
||||||
|
|
||||||
registerZygoteSocket(socketName);
|
zygoteServer.registerServerSocket(socketName);
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
|
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
|
||||||
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
|
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
|
||||||
SystemClock.uptimeMillis());
|
SystemClock.uptimeMillis());
|
||||||
@@ -740,8 +658,6 @@ public class ZygoteInit {
|
|||||||
gcAndFinalize();
|
gcAndFinalize();
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
|
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
|
// Disable tracing so that forked processes do not inherit stale tracing tags from
|
||||||
// Zygote.
|
// Zygote.
|
||||||
Trace.setTracingEnabled(false);
|
Trace.setTracingEnabled(false);
|
||||||
@@ -752,18 +668,18 @@ public class ZygoteInit {
|
|||||||
ZygoteHooks.stopZygoteNoThreadCreation();
|
ZygoteHooks.stopZygoteNoThreadCreation();
|
||||||
|
|
||||||
if (startSystemServer) {
|
if (startSystemServer) {
|
||||||
startSystemServer(abiList, socketName);
|
startSystemServer(abiList, socketName, zygoteServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "Accepting command socket connections");
|
Log.i(TAG, "Accepting command socket connections");
|
||||||
runSelectLoop(abiList);
|
zygoteServer.runSelectLoop(abiList);
|
||||||
|
|
||||||
closeServerSocket();
|
zygoteServer.closeServerSocket();
|
||||||
} catch (MethodAndArgsCaller caller) {
|
} catch (Zygote.MethodAndArgsCaller caller) {
|
||||||
caller.run();
|
caller.run();
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
Log.e(TAG, "Zygote died with exception", ex);
|
Log.e(TAG, "System zygote died with exception", ex);
|
||||||
closeServerSocket();
|
zygoteServer.closeServerSocket();
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -798,90 +714,9 @@ 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.
|
* Class not instantiable.
|
||||||
*/
|
*/
|
||||||
private ZygoteInit() {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
167
core/java/com/android/internal/os/ZygoteServer.java
Normal file
167
core/java/com/android/internal/os/ZygoteServer.java
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user