Merge "Wait for secondary zygote before bringing up the system_server."

This commit is contained in:
Narayan Kamath
2014-05-15 13:34:09 +00:00
committed by Gerrit Code Review
2 changed files with 96 additions and 94 deletions

View File

@@ -31,13 +31,17 @@ import java.util.Arrays;
import java.util.List;
/*package*/ class ZygoteStartFailedEx extends Exception {
/**
* Something prevented the zygote process startup from happening normally
*/
ZygoteStartFailedEx(String s) {
super(s);
}
ZygoteStartFailedEx() {};
ZygoteStartFailedEx(String s) {super(s);}
ZygoteStartFailedEx(Throwable cause) {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 {
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.
@@ -338,8 +348,10 @@ public class Process {
/**
* State for communicating with the zygote process.
*
* @hide for internal use only.
*/
static class ZygoteState {
public static class ZygoteState {
final LocalSocket socket;
final DataInputStream inputStream;
final BufferedWriter writer;
@@ -355,55 +367,26 @@ public class Process {
this.abiList = abiList;
}
static ZygoteState connect(String socketAddress, int tries) throws ZygoteStartFailedEx {
LocalSocket zygoteSocket = null;
public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = 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 {
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 = new LocalSocket();
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
break;
} catch (IOException ex) {
if (zygoteSocket != null) {
try {
zygoteSocket.close();
} catch (IOException ex2) {
Log.e(LOG_TAG,"I/O exception on close after exception", ex2);
}
}
zygoteSocket = null;
zygoteSocket.close();
} catch (IOException ignore) {
}
}
if (zygoteSocket == null) {
throw new ZygoteStartFailedEx("connect failed");
throw ex;
}
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
@@ -417,7 +400,7 @@ public class Process {
return abiList.contains(abi);
}
void close() {
public void close() {
try {
socket.close();
} catch (IOException ex) {
@@ -503,27 +486,22 @@ public class Process {
* @throws ZygoteStartFailedEx if the query failed.
*/
private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
throws ZygoteStartFailedEx {
try {
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();
// 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);
// 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);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx(ioe);
}
return new String(bytes, StandardCharsets.US_ASCII);
}
/**
@@ -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
* already open, does nothing. May block and retry.
*/
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
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)) {
@@ -709,8 +673,11 @@ public class Process {
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET,
getNumTries(secondaryZygoteState));
try {
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
if (secondaryZygoteState.matches(abi)) {

View File

@@ -23,6 +23,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.net.LocalServerSocket;
import android.opengl.EGL14;
import android.os.Build;
import android.os.Debug;
import android.os.Process;
import android.os.SystemClock;
@@ -496,7 +497,7 @@ public class ZygoteInit {
/**
* 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 {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
@@ -544,6 +545,10 @@ public class ZygoteInit {
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
@@ -606,7 +611,7 @@ public class ZygoteInit {
Trace.setTracingEnabled(false);
if (startSystemServer) {
startSystemServer();
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
@@ -622,6 +627,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
* they happen, and reads commands from connections one spawn-request's