am 402120a2: Merge "Wait for secondary zygote before bringing up the system_server."
* commit '402120a2236b294dff9a51461cb22400a6ef67f6': Wait for secondary zygote before bringing up the system_server.
This commit is contained in:
@@ -31,13 +31,17 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/*package*/ class ZygoteStartFailedEx extends Exception {
|
/*package*/ class ZygoteStartFailedEx extends Exception {
|
||||||
/**
|
ZygoteStartFailedEx(String s) {
|
||||||
* Something prevented the zygote process startup from happening normally
|
super(s);
|
||||||
*/
|
}
|
||||||
|
|
||||||
ZygoteStartFailedEx() {};
|
ZygoteStartFailedEx(Throwable cause) {
|
||||||
ZygoteStartFailedEx(String s) {super(s);}
|
super(cause);
|
||||||
ZygoteStartFailedEx(Throwable cause) {super(cause);}
|
}
|
||||||
|
|
||||||
|
ZygoteStartFailedEx(String s, Throwable cause) {
|
||||||
|
super(s, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,9 +50,15 @@ import java.util.List;
|
|||||||
public class Process {
|
public class Process {
|
||||||
private static final String LOG_TAG = "Process";
|
private static final String LOG_TAG = "Process";
|
||||||
|
|
||||||
private static final String ZYGOTE_SOCKET = "zygote";
|
/**
|
||||||
|
* @hide for internal use only.
|
||||||
|
*/
|
||||||
|
public static final String ZYGOTE_SOCKET = "zygote";
|
||||||
|
|
||||||
private static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
|
/**
|
||||||
|
* @hide for internal use only.
|
||||||
|
*/
|
||||||
|
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the UID/GID under which system code runs.
|
* Defines the UID/GID under which system code runs.
|
||||||
@@ -338,8 +348,10 @@ public class Process {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* State for communicating with the zygote process.
|
* State for communicating with the zygote process.
|
||||||
|
*
|
||||||
|
* @hide for internal use only.
|
||||||
*/
|
*/
|
||||||
static class ZygoteState {
|
public static class ZygoteState {
|
||||||
final LocalSocket socket;
|
final LocalSocket socket;
|
||||||
final DataInputStream inputStream;
|
final DataInputStream inputStream;
|
||||||
final BufferedWriter writer;
|
final BufferedWriter writer;
|
||||||
@@ -355,32 +367,12 @@ public class Process {
|
|||||||
this.abiList = abiList;
|
this.abiList = abiList;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ZygoteState connect(String socketAddress, int tries) throws ZygoteStartFailedEx {
|
public static ZygoteState connect(String socketAddress) throws IOException {
|
||||||
LocalSocket zygoteSocket = null;
|
|
||||||
DataInputStream zygoteInputStream = null;
|
DataInputStream zygoteInputStream = null;
|
||||||
BufferedWriter zygoteWriter = null;
|
BufferedWriter zygoteWriter = null;
|
||||||
|
final LocalSocket zygoteSocket = new LocalSocket();
|
||||||
/*
|
|
||||||
* See bug #811181: Sometimes runtime can make it up before zygote.
|
|
||||||
* Really, we'd like to do something better to avoid this condition,
|
|
||||||
* but for now just wait a bit...
|
|
||||||
*
|
|
||||||
* TODO: This bug was filed in 2007. Get rid of this code. The zygote
|
|
||||||
* forks the system_server so it shouldn't be possible for the zygote
|
|
||||||
* socket to be brought up after the system_server is.
|
|
||||||
*/
|
|
||||||
for (int i = 0; i < tries; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
try {
|
|
||||||
Log.i(LOG_TAG, "Zygote not up yet, sleeping...");
|
|
||||||
Thread.sleep(ZYGOTE_RETRY_MILLIS);
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
throw new ZygoteStartFailedEx(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
zygoteSocket = new LocalSocket();
|
|
||||||
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
|
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
|
||||||
LocalSocketAddress.Namespace.RESERVED));
|
LocalSocketAddress.Namespace.RESERVED));
|
||||||
|
|
||||||
@@ -388,22 +380,13 @@ public class Process {
|
|||||||
|
|
||||||
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
|
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
|
||||||
zygoteSocket.getOutputStream()), 256);
|
zygoteSocket.getOutputStream()), 256);
|
||||||
break;
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
if (zygoteSocket != null) {
|
|
||||||
try {
|
try {
|
||||||
zygoteSocket.close();
|
zygoteSocket.close();
|
||||||
} catch (IOException ex2) {
|
} catch (IOException ignore) {
|
||||||
Log.e(LOG_TAG,"I/O exception on close after exception", ex2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
zygoteSocket = null;
|
throw ex;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zygoteSocket == null) {
|
|
||||||
throw new ZygoteStartFailedEx("connect failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
|
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
|
||||||
@@ -417,7 +400,7 @@ public class Process {
|
|||||||
return abiList.contains(abi);
|
return abiList.contains(abi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
@@ -503,9 +486,7 @@ public class Process {
|
|||||||
* @throws ZygoteStartFailedEx if the query failed.
|
* @throws ZygoteStartFailedEx if the query failed.
|
||||||
*/
|
*/
|
||||||
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
|
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
|
||||||
throws ZygoteStartFailedEx {
|
throws IOException {
|
||||||
try {
|
|
||||||
|
|
||||||
// Each query starts with the argument count (1 in this case)
|
// Each query starts with the argument count (1 in this case)
|
||||||
writer.write("1");
|
writer.write("1");
|
||||||
// ... followed by a new-line.
|
// ... followed by a new-line.
|
||||||
@@ -521,9 +502,6 @@ public class Process {
|
|||||||
inputStream.readFully(bytes);
|
inputStream.readFully(bytes);
|
||||||
|
|
||||||
return new String(bytes, StandardCharsets.US_ASCII);
|
return new String(bytes, StandardCharsets.US_ASCII);
|
||||||
} catch (IOException ioe) {
|
|
||||||
throw new ZygoteStartFailedEx(ioe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -676,31 +654,17 @@ public class Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of times we attempt a connection to the zygote. We
|
|
||||||
* sleep for {@link #ZYGOTE_RETRY_MILLIS} milliseconds between each try.
|
|
||||||
*
|
|
||||||
* This could probably be removed, see TODO in {@code ZygoteState#connect}.
|
|
||||||
*/
|
|
||||||
private static int getNumTries(ZygoteState state) {
|
|
||||||
// Retry 10 times for the first connection to each zygote.
|
|
||||||
if (state == null) {
|
|
||||||
return 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This means the connection has already been established, but subsequently
|
|
||||||
// closed, possibly due to an IOException. We retry just once if that's the
|
|
||||||
// case.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to open socket to Zygote process if not already open. If
|
* Tries to open socket to Zygote process if not already open. If
|
||||||
* already open, does nothing. May block and retry.
|
* already open, does nothing. May block and retry.
|
||||||
*/
|
*/
|
||||||
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
|
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
|
||||||
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
|
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
|
||||||
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET, getNumTries(primaryZygoteState));
|
try {
|
||||||
|
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (primaryZygoteState.matches(abi)) {
|
if (primaryZygoteState.matches(abi)) {
|
||||||
@@ -709,8 +673,11 @@ public class Process {
|
|||||||
|
|
||||||
// The primary zygote didn't match. Try the secondary.
|
// The primary zygote didn't match. Try the secondary.
|
||||||
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
|
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
|
||||||
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
|
try {
|
||||||
getNumTries(secondaryZygoteState));
|
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secondaryZygoteState.matches(abi)) {
|
if (secondaryZygoteState.matches(abi)) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import android.content.res.Resources;
|
|||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.net.LocalServerSocket;
|
import android.net.LocalServerSocket;
|
||||||
import android.opengl.EGL14;
|
import android.opengl.EGL14;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@@ -505,7 +506,7 @@ 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()
|
private static boolean startSystemServer(String abiList, String socketName)
|
||||||
throws MethodAndArgsCaller, RuntimeException {
|
throws MethodAndArgsCaller, RuntimeException {
|
||||||
long capabilities = posixCapabilitiesAsBits(
|
long capabilities = posixCapabilitiesAsBits(
|
||||||
OsConstants.CAP_BLOCK_SUSPEND,
|
OsConstants.CAP_BLOCK_SUSPEND,
|
||||||
@@ -553,6 +554,10 @@ public class ZygoteInit {
|
|||||||
|
|
||||||
/* For child process */
|
/* For child process */
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
if (hasSecondZygote(abiList)) {
|
||||||
|
waitForSecondaryZygote(socketName);
|
||||||
|
}
|
||||||
|
|
||||||
handleSystemServerProcess(parsedArgs);
|
handleSystemServerProcess(parsedArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,7 +620,7 @@ public class ZygoteInit {
|
|||||||
Trace.setTracingEnabled(false);
|
Trace.setTracingEnabled(false);
|
||||||
|
|
||||||
if (startSystemServer) {
|
if (startSystemServer) {
|
||||||
startSystemServer();
|
startSystemServer(abiList, socketName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "Accepting command socket connections");
|
Log.i(TAG, "Accepting command socket connections");
|
||||||
@@ -631,6 +636,36 @@ public class ZygoteInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return {@code true} if this device configuration has another zygote.
|
||||||
|
*
|
||||||
|
* We determine this by comparing the device ABI list with this zygotes
|
||||||
|
* list. If this zygote supports all ABIs this device supports, there won't
|
||||||
|
* be another zygote.
|
||||||
|
*/
|
||||||
|
private static boolean hasSecondZygote(String abiList) {
|
||||||
|
return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void waitForSecondaryZygote(String socketName) {
|
||||||
|
String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
|
||||||
|
Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName);
|
||||||
|
zs.close();
|
||||||
|
break;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the zygote process's select loop. Accepts new connections as
|
* Runs the zygote process's select loop. Accepts new connections as
|
||||||
* they happen, and reads commands from connections one spawn-request's
|
* they happen, and reads commands from connections one spawn-request's
|
||||||
|
|||||||
Reference in New Issue
Block a user