Loading core/java/android/os/Process.java +201 −116 Original line number Diff line number Diff line Loading @@ -19,15 +19,15 @@ 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; import libcore.io.Libcore; /*package*/ class ZygoteStartFailedEx extends Exception { Loading @@ -48,17 +48,7 @@ public class Process { private static final String ZYGOTE_SOCKET = "zygote"; /** * Name of a process for running the platform's media services. * {@hide} */ public static final String ANDROID_SHARED_MEDIA = "com.android.process.media"; /** * Name of the process that Google content providers can share. * {@hide} */ public static final String GOOGLE_SHARED_APP_CONTENT = "com.google.process.content"; private static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary"; /** * Defines the UID/GID under which system code runs. Loading Loading @@ -346,14 +336,111 @@ public class Process { public static final int SIGNAL_KILL = 9; public static final int SIGNAL_USR1 = 10; // State for communicating with zygote process /** * State for communicating with the zygote process. */ 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; } static ZygoteState connect(String socketAddress, int tries) throws ZygoteStartFailedEx { LocalSocket zygoteSocket = null; DataInputStream zygoteInputStream = null; BufferedWriter zygoteWriter = null; /* * 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("Zygote", "Zygote not up yet, sleeping..."); Thread.sleep(ZYGOTE_RETRY_MILLIS); } catch (InterruptedException ex) { throw new ZygoteStartFailedEx(ex); } } try { zygoteSocket = new LocalSocket(); zygoteSocket.connect(new LocalSocketAddress(socketAddress, LocalSocketAddress.Namespace.RESERVED)); zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); static LocalSocket sZygoteSocket; static DataInputStream sZygoteInputStream; static BufferedWriter sZygoteWriter; 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; } } if (zygoteSocket == null) { throw new ZygoteStartFailedEx("connect failed"); } 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); } /** true if previous zygote open failed */ static boolean sPreviousZygoteOpenFailed; void close() { try { socket.close(); } catch (IOException ex) { Log.e(LOG_TAG,"I/O exception on routine close", ex); } mClosed = true; } boolean isClosed() { return mClosed; } } /** * The state of the connection to the primary zygote. */ static ZygoteState primaryZygoteState; /** * The state of the connection to the secondary zygote. */ static ZygoteState secondaryZygoteState; /** * Start a new process. Loading Loading @@ -395,7 +482,9 @@ public class Process { String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs); debugFlags, mountExternal, targetSdkVersion, seInfo, null, /* zygoteAbi TODO: Replace this with the real ABI */ zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); Loading @@ -408,78 +497,31 @@ public class Process { static final int ZYGOTE_RETRY_MILLIS = 500; /** * Tries to open socket to Zygote process if not already open. If * already open, does nothing. May block and retry. * Queries the zygote for the list of ABIS it supports. * * @throws ZygoteStartFailedEx if the query failed. */ private static void openZygoteSocketIfNeeded() private static String getAbiList(BufferedWriter writer, DataInputStream inputStream) throws ZygoteStartFailedEx { int retryCount; if (sPreviousZygoteOpenFailed) { /* * If we've failed before, expect that we'll fail again and * don't pause for retries. */ retryCount = 0; } else { retryCount = 10; } /* * 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... */ for (int retry = 0 ; (sZygoteSocket == null) && (retry < (retryCount + 1)) ; retry++ ) { if (retry > 0) { try { Log.i("Zygote", "Zygote not up yet, sleeping..."); Thread.sleep(ZYGOTE_RETRY_MILLIS); } catch (InterruptedException ex) { // should never happen } } try { sZygoteSocket = new LocalSocket(); sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, LocalSocketAddress.Namespace.RESERVED)); sZygoteInputStream = new DataInputStream(sZygoteSocket.getInputStream()); sZygoteWriter = new BufferedWriter( new OutputStreamWriter( sZygoteSocket.getOutputStream()), 256); Log.i("Zygote", "Process: zygote socket opened"); sPreviousZygoteOpenFailed = false; break; } catch (IOException ex) { if (sZygoteSocket != null) { try { sZygoteSocket.close(); } catch (IOException ex2) { Log.e(LOG_TAG,"I/O exception on close after exception", ex2); } } sZygoteSocket = null; } } if (sZygoteSocket == null) { sPreviousZygoteOpenFailed = true; throw new ZygoteStartFailedEx("connect failed"); // 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); } catch (IOException ioe) { throw new ZygoteStartFailedEx(ioe); } } Loading @@ -487,14 +529,12 @@ public class Process { * 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. * @param args argument list * @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 zygoteSendArgsAndGetResult(ArrayList<String> args) private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { openZygoteSocketIfNeeded(); try { /** * See com.android.internal.os.ZygoteInit.readArgumentList() Loading @@ -506,9 +546,11 @@ public class Process { * 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; sZygoteWriter.write(Integer.toString(args.size())); sZygoteWriter.newLine(); writer.write(Integer.toString(args.size())); writer.newLine(); int sz = args.size(); for (int i = 0; i < sz; i++) { Loading @@ -517,32 +559,22 @@ public class Process { throw new ZygoteStartFailedEx( "embedded newlines not allowed"); } sZygoteWriter.write(arg); sZygoteWriter.newLine(); writer.write(arg); writer.newLine(); } sZygoteWriter.flush(); writer.flush(); // Should there be a timeout on this? ProcessStartResult result = new ProcessStartResult(); result.pid = sZygoteInputStream.readInt(); result.pid = inputStream.readInt(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } result.usingWrapper = sZygoteInputStream.readBoolean(); result.usingWrapper = inputStream.readBoolean(); return result; } catch (IOException ex) { try { if (sZygoteSocket != null) { sZygoteSocket.close(); } } catch (IOException ex2) { // we're going to fail anyway Log.e(LOG_TAG,"I/O exception on routine close", ex2); } sZygoteSocket = null; zygoteState.close(); throw new ZygoteStartFailedEx(ex); } } Loading @@ -559,6 +591,7 @@ public class 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 the ABI the process should use. * @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 Loading @@ -570,6 +603,7 @@ public class Process { int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { Loading Loading @@ -637,8 +671,59 @@ public class Process { } } return zygoteSendArgsAndGetResult(argsForZygote); return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); } } /** * 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)); } // TODO: Revert this temporary change. This is required to test // and submit this change ahead of the package manager changes // that supply this abi. if (abi == null) { return primaryZygoteState; } if (primaryZygoteState.matches(abi)) { return primaryZygoteState; } // The primary zygote didn't match. Try the secondary. if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET, getNumTries(secondaryZygoteState)); } if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); } /** Loading Loading
core/java/android/os/Process.java +201 −116 Original line number Diff line number Diff line Loading @@ -19,15 +19,15 @@ 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; import libcore.io.Libcore; /*package*/ class ZygoteStartFailedEx extends Exception { Loading @@ -48,17 +48,7 @@ public class Process { private static final String ZYGOTE_SOCKET = "zygote"; /** * Name of a process for running the platform's media services. * {@hide} */ public static final String ANDROID_SHARED_MEDIA = "com.android.process.media"; /** * Name of the process that Google content providers can share. * {@hide} */ public static final String GOOGLE_SHARED_APP_CONTENT = "com.google.process.content"; private static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary"; /** * Defines the UID/GID under which system code runs. Loading Loading @@ -346,14 +336,111 @@ public class Process { public static final int SIGNAL_KILL = 9; public static final int SIGNAL_USR1 = 10; // State for communicating with zygote process /** * State for communicating with the zygote process. */ 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; } static ZygoteState connect(String socketAddress, int tries) throws ZygoteStartFailedEx { LocalSocket zygoteSocket = null; DataInputStream zygoteInputStream = null; BufferedWriter zygoteWriter = null; /* * 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("Zygote", "Zygote not up yet, sleeping..."); Thread.sleep(ZYGOTE_RETRY_MILLIS); } catch (InterruptedException ex) { throw new ZygoteStartFailedEx(ex); } } try { zygoteSocket = new LocalSocket(); zygoteSocket.connect(new LocalSocketAddress(socketAddress, LocalSocketAddress.Namespace.RESERVED)); zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); static LocalSocket sZygoteSocket; static DataInputStream sZygoteInputStream; static BufferedWriter sZygoteWriter; 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; } } if (zygoteSocket == null) { throw new ZygoteStartFailedEx("connect failed"); } 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); } /** true if previous zygote open failed */ static boolean sPreviousZygoteOpenFailed; void close() { try { socket.close(); } catch (IOException ex) { Log.e(LOG_TAG,"I/O exception on routine close", ex); } mClosed = true; } boolean isClosed() { return mClosed; } } /** * The state of the connection to the primary zygote. */ static ZygoteState primaryZygoteState; /** * The state of the connection to the secondary zygote. */ static ZygoteState secondaryZygoteState; /** * Start a new process. Loading Loading @@ -395,7 +482,9 @@ public class Process { String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs); debugFlags, mountExternal, targetSdkVersion, seInfo, null, /* zygoteAbi TODO: Replace this with the real ABI */ zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); Loading @@ -408,78 +497,31 @@ public class Process { static final int ZYGOTE_RETRY_MILLIS = 500; /** * Tries to open socket to Zygote process if not already open. If * already open, does nothing. May block and retry. * Queries the zygote for the list of ABIS it supports. * * @throws ZygoteStartFailedEx if the query failed. */ private static void openZygoteSocketIfNeeded() private static String getAbiList(BufferedWriter writer, DataInputStream inputStream) throws ZygoteStartFailedEx { int retryCount; if (sPreviousZygoteOpenFailed) { /* * If we've failed before, expect that we'll fail again and * don't pause for retries. */ retryCount = 0; } else { retryCount = 10; } /* * 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... */ for (int retry = 0 ; (sZygoteSocket == null) && (retry < (retryCount + 1)) ; retry++ ) { if (retry > 0) { try { Log.i("Zygote", "Zygote not up yet, sleeping..."); Thread.sleep(ZYGOTE_RETRY_MILLIS); } catch (InterruptedException ex) { // should never happen } } try { sZygoteSocket = new LocalSocket(); sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET, LocalSocketAddress.Namespace.RESERVED)); sZygoteInputStream = new DataInputStream(sZygoteSocket.getInputStream()); sZygoteWriter = new BufferedWriter( new OutputStreamWriter( sZygoteSocket.getOutputStream()), 256); Log.i("Zygote", "Process: zygote socket opened"); sPreviousZygoteOpenFailed = false; break; } catch (IOException ex) { if (sZygoteSocket != null) { try { sZygoteSocket.close(); } catch (IOException ex2) { Log.e(LOG_TAG,"I/O exception on close after exception", ex2); } } sZygoteSocket = null; } } if (sZygoteSocket == null) { sPreviousZygoteOpenFailed = true; throw new ZygoteStartFailedEx("connect failed"); // 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); } catch (IOException ioe) { throw new ZygoteStartFailedEx(ioe); } } Loading @@ -487,14 +529,12 @@ public class Process { * 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. * @param args argument list * @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 zygoteSendArgsAndGetResult(ArrayList<String> args) private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { openZygoteSocketIfNeeded(); try { /** * See com.android.internal.os.ZygoteInit.readArgumentList() Loading @@ -506,9 +546,11 @@ public class Process { * 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; sZygoteWriter.write(Integer.toString(args.size())); sZygoteWriter.newLine(); writer.write(Integer.toString(args.size())); writer.newLine(); int sz = args.size(); for (int i = 0; i < sz; i++) { Loading @@ -517,32 +559,22 @@ public class Process { throw new ZygoteStartFailedEx( "embedded newlines not allowed"); } sZygoteWriter.write(arg); sZygoteWriter.newLine(); writer.write(arg); writer.newLine(); } sZygoteWriter.flush(); writer.flush(); // Should there be a timeout on this? ProcessStartResult result = new ProcessStartResult(); result.pid = sZygoteInputStream.readInt(); result.pid = inputStream.readInt(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } result.usingWrapper = sZygoteInputStream.readBoolean(); result.usingWrapper = inputStream.readBoolean(); return result; } catch (IOException ex) { try { if (sZygoteSocket != null) { sZygoteSocket.close(); } } catch (IOException ex2) { // we're going to fail anyway Log.e(LOG_TAG,"I/O exception on routine close", ex2); } sZygoteSocket = null; zygoteState.close(); throw new ZygoteStartFailedEx(ex); } } Loading @@ -559,6 +591,7 @@ public class 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 the ABI the process should use. * @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 Loading @@ -570,6 +603,7 @@ public class Process { int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { Loading Loading @@ -637,8 +671,59 @@ public class Process { } } return zygoteSendArgsAndGetResult(argsForZygote); return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); } } /** * 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)); } // TODO: Revert this temporary change. This is required to test // and submit this change ahead of the package manager changes // that supply this abi. if (abi == null) { return primaryZygoteState; } if (primaryZygoteState.matches(abi)) { return primaryZygoteState; } // The primary zygote didn't match. Try the secondary. if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) { secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET, getNumTries(secondaryZygoteState)); } if (secondaryZygoteState.matches(abi)) { return secondaryZygoteState; } throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi); } /** Loading