Loading core/java/com/android/internal/os/Zygote.java +17 −30 Original line number Diff line number Diff line Loading @@ -172,11 +172,6 @@ public final class Zygote { */ public static final int SOCKET_BUFFER_SIZE = 256; /** * @hide for internal use only */ private static final int PRIORITY_MAX = -20; /** a prototype instance for a future List.toArray() */ protected static final int[][] INT_ARRAY_2D = new int[0][0]; Loading Loading @@ -241,7 +236,8 @@ public final class Zygote { int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); Loading @@ -253,7 +249,6 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } ZygoteHooks.postForkCommon(); return pid; } Loading Loading @@ -340,16 +335,15 @@ public final class Zygote { public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities); // Enable tracing as soon as we enter the system_server. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); } ZygoteHooks.postForkCommon(); return pid; } Loading Loading @@ -467,16 +461,13 @@ public final class Zygote { /** * Fork a new unspecialized app process from the zygote * * @param usapPoolSocket The server socket the USAP will call accept on * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @param isPriorityFork Value controlling the process priority level until accept is called * @return In the Zygote process this function will always return null; in unspecialized app * processes this function will return a Runnable object representing the new * application that is passed up from usapMain. */ static Runnable forkUsap(LocalServerSocket usapPoolSocket, int[] sessionSocketRawFDs, boolean isPriorityFork) { int[] sessionSocketRawFDs) { FileDescriptor[] pipeFDs = null; try { Loading @@ -486,8 +477,7 @@ public final class Zygote { } int pid = nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs, isPriorityFork); nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs); if (pid == 0) { IoUtils.closeQuietly(pipeFDs[0]); Loading @@ -502,8 +492,7 @@ public final class Zygote { private static native int nativeForkUsap(int readPipeFD, int writePipeFD, int[] sessionSocketRawFDs, boolean isPriorityFork); int[] sessionSocketRawFDs); /** * This function is used by unspecialized app processes to wait for specialization requests from Loading @@ -526,11 +515,6 @@ public final class Zygote { // Load resources ZygoteInit.nativePreloadGraphicsDriver(); // Change the priority to max before calling accept so we can respond to new specialization // requests as quickly as possible. This will be reverted to the default priority in the // native specialization code. boostUsapPriority(); while (true) { try { sessionSocket = usapPoolSocket.accept(); Loading Loading @@ -634,12 +618,6 @@ public final class Zygote { null /* classLoader */); } private static void boostUsapPriority() { nativeBoostUsapPriority(); } private static native void nativeBoostUsapPriority(); private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: "; /** Loading Loading @@ -879,6 +857,15 @@ public final class Zygote { ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); } /** * Resets the calling thread priority to the default value (Thread.NORM_PRIORITY * or nice value 0). This updates both the priority value in java.lang.Thread and * the nice value (setpriority). */ static void resetNicePriority() { Thread.currentThread().setPriority(Thread.NORM_PRIORITY); } /** * Executes "/system/bin/sh -c <command>" using the exec() system call. * This method throws a runtime exception if exec() failed, otherwise, this Loading core/java/com/android/internal/os/ZygoteConnection.java +1 −1 Original line number Diff line number Diff line Loading @@ -346,7 +346,7 @@ class ZygoteConnection { if (zygoteServer.isUsapPoolEnabled()) { Runnable fpResult = zygoteServer.fillUsapPool( new int[]{mSocket.getFileDescriptor().getInt$()}, false); new int[]{mSocket.getFileDescriptor().getInt$()}); if (fpResult != null) { zygoteServer.setForkChild(); Loading core/java/com/android/internal/os/ZygoteInit.java +2 −3 Original line number Diff line number Diff line Loading @@ -822,9 +822,6 @@ public class ZygoteInit { public static void main(String argv[]) { ZygoteServer zygoteServer = null; // Set the initial thread priority to the "normal" value. Thread.currentThread().setPriority(Thread.NORM_PRIORITY); // Mark zygote start. This ensures that thread creation will throw // an error. ZygoteHooks.startZygoteNoThreadCreation(); Loading Loading @@ -884,6 +881,8 @@ public class ZygoteInit { EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } else { Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup Loading core/java/com/android/internal/os/ZygoteServer.java +122 −215 Original line number Diff line number Diff line Loading @@ -66,12 +66,6 @@ class ZygoteServer { /** The default value used for the USAP_POOL_SIZE_MIN device property */ private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1"; /** The default value used for the USAP_REFILL_DELAY_MS device property */ private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000"; /** The "not a timestamp" value for the refill delay timestamp mechanism. */ private static final int INVALID_TIMESTAMP = -1; /** * Indicates if this Zygote server can support a unspecialized app process pool. Currently this * should only be true for the primary and secondary Zygotes, and not the App Zygotes or the Loading Loading @@ -137,18 +131,6 @@ class ZygoteServer { */ private int mUsapPoolRefillThreshold = 0; /** * Number of milliseconds to delay before refilling the pool if it hasn't reached its * minimum value. */ private int mUsapPoolRefillDelayMs = -1; private enum UsapPoolRefillAction { DELAYED, IMMEDIATE, NONE } ZygoteServer() { mUsapPoolEventFD = null; mZygoteSocket = null; Loading Loading @@ -285,13 +267,6 @@ class ZygoteServer { mUsapPoolSizeMax); } final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty( ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT); if (!usapPoolRefillDelayMsPropString.isEmpty()) { mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString); } // Sanity check if (mUsapPoolSizeMin >= mUsapPoolSizeMax) { Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size." Loading @@ -318,16 +293,9 @@ class ZygoteServer { } } private void fetchUsapPoolPolicyPropsIfUnfetched() { if (mIsFirstPropertyCheck) { mIsFirstPropertyCheck = false; fetchUsapPoolPolicyProps(); } } /** * Refill the USAP Pool to the appropriate level, determined by whether this is a priority * refill event or not. * Checks to see if the current policy says that pool should be refilled, and spawns new USAPs * if necessary. * * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @return In the Zygote process this function will always return null; in unspecialized app Loading @@ -335,36 +303,25 @@ class ZygoteServer { * application that is passed up from usapMain. */ Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) { Runnable fillUsapPool(int[] sessionSocketRawFDs) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool"); // Ensure that the pool properties have been fetched. fetchUsapPoolPolicyPropsIfUnfetched(); fetchUsapPoolPolicyPropsWithMinInterval(); int usapPoolCount = Zygote.getUsapPoolCount(); int numUsapsToSpawn; int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; if (isPriorityRefill) { // Refill to min numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount; Log.i("zygote", "Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn); } else { // Refill up to max numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; Log.i("zygote", "Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn); } if (usapPoolCount < mUsapPoolSizeMin || numUsapsToSpawn >= mUsapPoolRefillThreshold) { // Disable some VM functionality and reset some system values // before forking. ZygoteHooks.preFork(); Zygote.resetNicePriority(); while (--numUsapsToSpawn >= 0) { Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill); while (usapPoolCount++ < mUsapPoolSizeMax) { Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs); if (caller != null) { return caller; Loading @@ -375,6 +332,10 @@ class ZygoteServer { // are re-enabled in specializeAppProcess. ZygoteHooks.postForkCommon(); Log.i("zygote", "Filled the USAP pool. New USAPs: " + numUsapsToSpawn); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return null; Loading @@ -397,7 +358,7 @@ class ZygoteServer { mUsapPoolEnabled = newStatus; if (newStatus) { return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false); return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }); } else { Zygote.emptyUsapPool(); return null; Loading @@ -416,8 +377,6 @@ class ZygoteServer { socketFDs.add(mZygoteSocket.getFileDescriptor()); peers.add(null); long usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; while (true) { fetchUsapPoolPolicyPropsWithMinInterval(); Loading Loading @@ -469,40 +428,12 @@ class ZygoteServer { } } int pollTimeoutMs; if (usapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) { pollTimeoutMs = -1; } else { int elapsedTimeMs = (int) (System.currentTimeMillis() - usapPoolRefillTriggerTimestamp); if (elapsedTimeMs >= mUsapPoolRefillDelayMs) { // Normalize the poll timeout value when the time between one poll event and the // next pushes us over the delay value. This prevents poll receiving a 0 // timeout value, which would result in it returning immediately. pollTimeoutMs = -1; } else { pollTimeoutMs = mUsapPoolRefillDelayMs - elapsedTimeMs; } } int pollReturnValue; try { pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); Os.poll(pollFDs, -1); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } UsapPoolRefillAction usapPoolRefillAction = UsapPoolRefillAction.NONE; if (pollReturnValue == 0) { // The poll timeout has been exceeded. This only occurs when we have finished the // USAP pool refill delay period. usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; usapPoolRefillAction = UsapPoolRefillAction.DELAYED; } else { boolean usapPoolFDRead = false; while (--pollIndex >= 0) { Loading @@ -526,8 +457,8 @@ class ZygoteServer { // TODO (chriswailes): Is this extra check necessary? if (mIsForkChild) { // We're in the child. We should always have a command to run at // this stage if processOneCommand hasn't called "exec". // We're in the child. We should always have a command to run at this // stage if processOneCommand hasn't called "exec". if (command == null) { throw new IllegalStateException("command == null"); } Loading @@ -541,8 +472,7 @@ class ZygoteServer { // We don't know whether the remote side of the socket was closed or // not until we attempt to read from it from processOneCommand. This // shows up as a regular POLLIN event in our regular processing // loop. // shows up as a regular POLLIN event in our regular processing loop. if (connection.isClosedByPeer()) { connection.closeSocket(); peers.remove(pollIndex); Loading @@ -551,10 +481,10 @@ class ZygoteServer { } } catch (Exception e) { if (!mIsForkChild) { // We're in the server so any exception here is one that has taken // place pre-fork while processing commands or reading / writing // from the control socket. Make a loud noise about any such // exceptions so that we know exactly what failed and why. // We're in the server so any exception here is one that has taken place // pre-fork while processing commands or reading / writing from the // control socket. Make a loud noise about any such exceptions so that // we know exactly what failed and why. Slog.e(TAG, "Exception executing zygote command: ", e); Loading @@ -567,16 +497,15 @@ class ZygoteServer { socketFDs.remove(pollIndex); } else { // We're in the child so any exception caught here has happened post // fork and before we execute ActivityThread.main (or any other // main() method). Log the details of the exception and bring down // the process. // fork and before we execute ActivityThread.main (or any other main() // method). Log the details of the exception and bring down the process. Log.e(TAG, "Caught post-fork exception in child process.", e); throw e; } } finally { // Reset the child flag, in the event that the child process is a child- // zygote. The flag will not be consulted this loop pass after the // Runnable is returned. // zygote. The flag will not be consulted this loop pass after the Runnable // is returned. mIsForkChild = false; } } else { Loading @@ -584,15 +513,12 @@ class ZygoteServer { // If this is the event FD the payload will be the number of USAPs removed. // If this is a reporting pipe FD the payload will be the PID of the USAP // that was just specialized. The `continue` statements below ensure that // the messagePayload will always be valid if we complete the try block // without an exception. long messagePayload; // that was just specialized. long messagePayload = -1; try { byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { DataInputStream inputStream = Loading Loading @@ -624,37 +550,18 @@ class ZygoteServer { } } // Check to see if the USAP pool needs to be refilled. if (usapPoolFDRead) { int usapPoolCount = Zygote.getUsapPoolCount(); if (usapPoolCount < mUsapPoolSizeMin) { // Immediate refill usapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE; } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) { // Delayed refill usapPoolRefillTriggerTimestamp = System.currentTimeMillis(); } } } if (usapPoolRefillAction != UsapPoolRefillAction.NONE) { int[] sessionSocketRawFDs = socketFDs.subList(1, socketFDs.size()) .stream() .mapToInt(fd -> fd.getInt$()) .toArray(); final boolean isPriorityRefill = usapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE; final Runnable command = fillUsapPool(sessionSocketRawFDs, isPriorityRefill); final Runnable command = fillUsapPool(sessionSocketRawFDs); if (command != null) { return command; } else if (isPriorityRefill) { // Schedule a delayed refill to finish refilling the pool. usapPoolRefillTriggerTimestamp = System.currentTimeMillis(); } } } Loading core/jni/com_android_internal_os_Zygote.cpp +7 −36 Original line number Diff line number Diff line Loading @@ -169,15 +169,6 @@ static int gUsapPoolEventFD = -1; */ static constexpr int USAP_POOL_SIZE_MAX_LIMIT = 100; /** The numeric value for the maximum priority a process may possess. */ static constexpr int PROCESS_PRIORITY_MAX = -20; /** The numeric value for the minimum priority a process may possess. */ static constexpr int PROCESS_PRIORITY_MIN = 19; /** The numeric value for the normal priority a process should have. */ static constexpr int PROCESS_PRIORITY_DEFAULT = 0; /** * A helper class containing accounting information for USAPs. */ Loading Loading @@ -902,8 +893,7 @@ static void ClearUsapTable() { // Utility routine to fork a process from the zygote. static pid_t ForkCommon(JNIEnv* env, bool is_system_server, const std::vector<int>& fds_to_close, const std::vector<int>& fds_to_ignore, bool is_priority_fork) { const std::vector<int>& fds_to_ignore) { SetSignalHandlers(); // Curry a failure function. Loading Loading @@ -936,12 +926,6 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server, pid_t pid = fork(); if (pid == 0) { if (is_priority_fork) { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } else { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); } // The child process. PreApplicationInit(); Loading Loading @@ -1139,9 +1123,6 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); // Reset the process priority to the default value. setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT); if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); } Loading Loading @@ -1379,7 +1360,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( fds_to_ignore.push_back(gUsapPoolEventFD); } pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true); pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, Loading @@ -1406,8 +1387,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( pid_t pid = ForkCommon(env, true, fds_to_close, fds_to_ignore, true); fds_to_ignore); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, Loading Loading @@ -1449,15 +1429,13 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( * zygote in managed code. * @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by * the FD hygiene code and automatically "closed" in the new USAP. * @param is_priority_fork Controls the nice level assigned to the newly created process * @return */ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, jclass, jint read_pipe_fd, jint write_pipe_fd, jintArray managed_session_socket_fds, jboolean is_priority_fork) { jintArray managed_session_socket_fds) { std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), fds_to_ignore(fds_to_close); Loading @@ -1479,8 +1457,7 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, fds_to_ignore.push_back(write_pipe_fd); fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end()); pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, is_priority_fork == JNI_TRUE); pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore); if (usap_pid != 0) { ++gUsapPoolCount; Loading Loading @@ -1701,10 +1678,6 @@ static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv* return dl_iterate_phdr(disable_execute_only, nullptr) == 0; } static void com_android_internal_os_Zygote_nativeBoostUsapPriority(JNIEnv* env, jclass) { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", Loading @@ -1717,7 +1690,7 @@ static const JNINativeMethod gMethods[] = { (void *) com_android_internal_os_Zygote_nativePreApplicationInit }, { "nativeInstallSeccompUidGidFilter", "(II)V", (void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter }, { "nativeForkUsap", "(II[IZ)I", { "nativeForkUsap", "(II[I)I", (void *) com_android_internal_os_Zygote_nativeForkUsap }, { "nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V", Loading @@ -1735,9 +1708,7 @@ static const JNINativeMethod gMethods[] = { { "nativeEmptyUsapPool", "()V", (void *) com_android_internal_os_Zygote_nativeEmptyUsapPool }, { "nativeDisableExecuteOnly", "()Z", (void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly }, { "nativeBoostUsapPriority", "()V", (void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority } (void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly } }; int register_com_android_internal_os_Zygote(JNIEnv* env) { Loading Loading
core/java/com/android/internal/os/Zygote.java +17 −30 Original line number Diff line number Diff line Loading @@ -172,11 +172,6 @@ public final class Zygote { */ public static final int SOCKET_BUFFER_SIZE = 256; /** * @hide for internal use only */ private static final int PRIORITY_MAX = -20; /** a prototype instance for a future List.toArray() */ protected static final int[][] INT_ARRAY_2D = new int[0][0]; Loading Loading @@ -241,7 +236,8 @@ public final class Zygote { int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); Loading @@ -253,7 +249,6 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } ZygoteHooks.postForkCommon(); return pid; } Loading Loading @@ -340,16 +335,15 @@ public final class Zygote { public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork(); // Resets nice priority for zygote process. resetNicePriority(); int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities); // Enable tracing as soon as we enter the system_server. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); } ZygoteHooks.postForkCommon(); return pid; } Loading Loading @@ -467,16 +461,13 @@ public final class Zygote { /** * Fork a new unspecialized app process from the zygote * * @param usapPoolSocket The server socket the USAP will call accept on * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @param isPriorityFork Value controlling the process priority level until accept is called * @return In the Zygote process this function will always return null; in unspecialized app * processes this function will return a Runnable object representing the new * application that is passed up from usapMain. */ static Runnable forkUsap(LocalServerSocket usapPoolSocket, int[] sessionSocketRawFDs, boolean isPriorityFork) { int[] sessionSocketRawFDs) { FileDescriptor[] pipeFDs = null; try { Loading @@ -486,8 +477,7 @@ public final class Zygote { } int pid = nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs, isPriorityFork); nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs); if (pid == 0) { IoUtils.closeQuietly(pipeFDs[0]); Loading @@ -502,8 +492,7 @@ public final class Zygote { private static native int nativeForkUsap(int readPipeFD, int writePipeFD, int[] sessionSocketRawFDs, boolean isPriorityFork); int[] sessionSocketRawFDs); /** * This function is used by unspecialized app processes to wait for specialization requests from Loading @@ -526,11 +515,6 @@ public final class Zygote { // Load resources ZygoteInit.nativePreloadGraphicsDriver(); // Change the priority to max before calling accept so we can respond to new specialization // requests as quickly as possible. This will be reverted to the default priority in the // native specialization code. boostUsapPriority(); while (true) { try { sessionSocket = usapPoolSocket.accept(); Loading Loading @@ -634,12 +618,6 @@ public final class Zygote { null /* classLoader */); } private static void boostUsapPriority() { nativeBoostUsapPriority(); } private static native void nativeBoostUsapPriority(); private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: "; /** Loading Loading @@ -879,6 +857,15 @@ public final class Zygote { ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet); } /** * Resets the calling thread priority to the default value (Thread.NORM_PRIORITY * or nice value 0). This updates both the priority value in java.lang.Thread and * the nice value (setpriority). */ static void resetNicePriority() { Thread.currentThread().setPriority(Thread.NORM_PRIORITY); } /** * Executes "/system/bin/sh -c <command>" using the exec() system call. * This method throws a runtime exception if exec() failed, otherwise, this Loading
core/java/com/android/internal/os/ZygoteConnection.java +1 −1 Original line number Diff line number Diff line Loading @@ -346,7 +346,7 @@ class ZygoteConnection { if (zygoteServer.isUsapPoolEnabled()) { Runnable fpResult = zygoteServer.fillUsapPool( new int[]{mSocket.getFileDescriptor().getInt$()}, false); new int[]{mSocket.getFileDescriptor().getInt$()}); if (fpResult != null) { zygoteServer.setForkChild(); Loading
core/java/com/android/internal/os/ZygoteInit.java +2 −3 Original line number Diff line number Diff line Loading @@ -822,9 +822,6 @@ public class ZygoteInit { public static void main(String argv[]) { ZygoteServer zygoteServer = null; // Set the initial thread priority to the "normal" value. Thread.currentThread().setPriority(Thread.NORM_PRIORITY); // Mark zygote start. This ensures that thread creation will throw // an error. ZygoteHooks.startZygoteNoThreadCreation(); Loading Loading @@ -884,6 +881,8 @@ public class ZygoteInit { EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload } else { Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup Loading
core/java/com/android/internal/os/ZygoteServer.java +122 −215 Original line number Diff line number Diff line Loading @@ -66,12 +66,6 @@ class ZygoteServer { /** The default value used for the USAP_POOL_SIZE_MIN device property */ private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1"; /** The default value used for the USAP_REFILL_DELAY_MS device property */ private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000"; /** The "not a timestamp" value for the refill delay timestamp mechanism. */ private static final int INVALID_TIMESTAMP = -1; /** * Indicates if this Zygote server can support a unspecialized app process pool. Currently this * should only be true for the primary and secondary Zygotes, and not the App Zygotes or the Loading Loading @@ -137,18 +131,6 @@ class ZygoteServer { */ private int mUsapPoolRefillThreshold = 0; /** * Number of milliseconds to delay before refilling the pool if it hasn't reached its * minimum value. */ private int mUsapPoolRefillDelayMs = -1; private enum UsapPoolRefillAction { DELAYED, IMMEDIATE, NONE } ZygoteServer() { mUsapPoolEventFD = null; mZygoteSocket = null; Loading Loading @@ -285,13 +267,6 @@ class ZygoteServer { mUsapPoolSizeMax); } final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty( ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT); if (!usapPoolRefillDelayMsPropString.isEmpty()) { mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString); } // Sanity check if (mUsapPoolSizeMin >= mUsapPoolSizeMax) { Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size." Loading @@ -318,16 +293,9 @@ class ZygoteServer { } } private void fetchUsapPoolPolicyPropsIfUnfetched() { if (mIsFirstPropertyCheck) { mIsFirstPropertyCheck = false; fetchUsapPoolPolicyProps(); } } /** * Refill the USAP Pool to the appropriate level, determined by whether this is a priority * refill event or not. * Checks to see if the current policy says that pool should be refilled, and spawns new USAPs * if necessary. * * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @return In the Zygote process this function will always return null; in unspecialized app Loading @@ -335,36 +303,25 @@ class ZygoteServer { * application that is passed up from usapMain. */ Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) { Runnable fillUsapPool(int[] sessionSocketRawFDs) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool"); // Ensure that the pool properties have been fetched. fetchUsapPoolPolicyPropsIfUnfetched(); fetchUsapPoolPolicyPropsWithMinInterval(); int usapPoolCount = Zygote.getUsapPoolCount(); int numUsapsToSpawn; int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; if (isPriorityRefill) { // Refill to min numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount; Log.i("zygote", "Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn); } else { // Refill up to max numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; Log.i("zygote", "Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn); } if (usapPoolCount < mUsapPoolSizeMin || numUsapsToSpawn >= mUsapPoolRefillThreshold) { // Disable some VM functionality and reset some system values // before forking. ZygoteHooks.preFork(); Zygote.resetNicePriority(); while (--numUsapsToSpawn >= 0) { Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill); while (usapPoolCount++ < mUsapPoolSizeMax) { Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs); if (caller != null) { return caller; Loading @@ -375,6 +332,10 @@ class ZygoteServer { // are re-enabled in specializeAppProcess. ZygoteHooks.postForkCommon(); Log.i("zygote", "Filled the USAP pool. New USAPs: " + numUsapsToSpawn); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return null; Loading @@ -397,7 +358,7 @@ class ZygoteServer { mUsapPoolEnabled = newStatus; if (newStatus) { return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false); return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }); } else { Zygote.emptyUsapPool(); return null; Loading @@ -416,8 +377,6 @@ class ZygoteServer { socketFDs.add(mZygoteSocket.getFileDescriptor()); peers.add(null); long usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; while (true) { fetchUsapPoolPolicyPropsWithMinInterval(); Loading Loading @@ -469,40 +428,12 @@ class ZygoteServer { } } int pollTimeoutMs; if (usapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) { pollTimeoutMs = -1; } else { int elapsedTimeMs = (int) (System.currentTimeMillis() - usapPoolRefillTriggerTimestamp); if (elapsedTimeMs >= mUsapPoolRefillDelayMs) { // Normalize the poll timeout value when the time between one poll event and the // next pushes us over the delay value. This prevents poll receiving a 0 // timeout value, which would result in it returning immediately. pollTimeoutMs = -1; } else { pollTimeoutMs = mUsapPoolRefillDelayMs - elapsedTimeMs; } } int pollReturnValue; try { pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); Os.poll(pollFDs, -1); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } UsapPoolRefillAction usapPoolRefillAction = UsapPoolRefillAction.NONE; if (pollReturnValue == 0) { // The poll timeout has been exceeded. This only occurs when we have finished the // USAP pool refill delay period. usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; usapPoolRefillAction = UsapPoolRefillAction.DELAYED; } else { boolean usapPoolFDRead = false; while (--pollIndex >= 0) { Loading @@ -526,8 +457,8 @@ class ZygoteServer { // TODO (chriswailes): Is this extra check necessary? if (mIsForkChild) { // We're in the child. We should always have a command to run at // this stage if processOneCommand hasn't called "exec". // We're in the child. We should always have a command to run at this // stage if processOneCommand hasn't called "exec". if (command == null) { throw new IllegalStateException("command == null"); } Loading @@ -541,8 +472,7 @@ class ZygoteServer { // We don't know whether the remote side of the socket was closed or // not until we attempt to read from it from processOneCommand. This // shows up as a regular POLLIN event in our regular processing // loop. // shows up as a regular POLLIN event in our regular processing loop. if (connection.isClosedByPeer()) { connection.closeSocket(); peers.remove(pollIndex); Loading @@ -551,10 +481,10 @@ class ZygoteServer { } } catch (Exception e) { if (!mIsForkChild) { // We're in the server so any exception here is one that has taken // place pre-fork while processing commands or reading / writing // from the control socket. Make a loud noise about any such // exceptions so that we know exactly what failed and why. // We're in the server so any exception here is one that has taken place // pre-fork while processing commands or reading / writing from the // control socket. Make a loud noise about any such exceptions so that // we know exactly what failed and why. Slog.e(TAG, "Exception executing zygote command: ", e); Loading @@ -567,16 +497,15 @@ class ZygoteServer { socketFDs.remove(pollIndex); } else { // We're in the child so any exception caught here has happened post // fork and before we execute ActivityThread.main (or any other // main() method). Log the details of the exception and bring down // the process. // fork and before we execute ActivityThread.main (or any other main() // method). Log the details of the exception and bring down the process. Log.e(TAG, "Caught post-fork exception in child process.", e); throw e; } } finally { // Reset the child flag, in the event that the child process is a child- // zygote. The flag will not be consulted this loop pass after the // Runnable is returned. // zygote. The flag will not be consulted this loop pass after the Runnable // is returned. mIsForkChild = false; } } else { Loading @@ -584,15 +513,12 @@ class ZygoteServer { // If this is the event FD the payload will be the number of USAPs removed. // If this is a reporting pipe FD the payload will be the PID of the USAP // that was just specialized. The `continue` statements below ensure that // the messagePayload will always be valid if we complete the try block // without an exception. long messagePayload; // that was just specialized. long messagePayload = -1; try { byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { DataInputStream inputStream = Loading Loading @@ -624,37 +550,18 @@ class ZygoteServer { } } // Check to see if the USAP pool needs to be refilled. if (usapPoolFDRead) { int usapPoolCount = Zygote.getUsapPoolCount(); if (usapPoolCount < mUsapPoolSizeMin) { // Immediate refill usapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE; } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) { // Delayed refill usapPoolRefillTriggerTimestamp = System.currentTimeMillis(); } } } if (usapPoolRefillAction != UsapPoolRefillAction.NONE) { int[] sessionSocketRawFDs = socketFDs.subList(1, socketFDs.size()) .stream() .mapToInt(fd -> fd.getInt$()) .toArray(); final boolean isPriorityRefill = usapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE; final Runnable command = fillUsapPool(sessionSocketRawFDs, isPriorityRefill); final Runnable command = fillUsapPool(sessionSocketRawFDs); if (command != null) { return command; } else if (isPriorityRefill) { // Schedule a delayed refill to finish refilling the pool. usapPoolRefillTriggerTimestamp = System.currentTimeMillis(); } } } Loading
core/jni/com_android_internal_os_Zygote.cpp +7 −36 Original line number Diff line number Diff line Loading @@ -169,15 +169,6 @@ static int gUsapPoolEventFD = -1; */ static constexpr int USAP_POOL_SIZE_MAX_LIMIT = 100; /** The numeric value for the maximum priority a process may possess. */ static constexpr int PROCESS_PRIORITY_MAX = -20; /** The numeric value for the minimum priority a process may possess. */ static constexpr int PROCESS_PRIORITY_MIN = 19; /** The numeric value for the normal priority a process should have. */ static constexpr int PROCESS_PRIORITY_DEFAULT = 0; /** * A helper class containing accounting information for USAPs. */ Loading Loading @@ -902,8 +893,7 @@ static void ClearUsapTable() { // Utility routine to fork a process from the zygote. static pid_t ForkCommon(JNIEnv* env, bool is_system_server, const std::vector<int>& fds_to_close, const std::vector<int>& fds_to_ignore, bool is_priority_fork) { const std::vector<int>& fds_to_ignore) { SetSignalHandlers(); // Curry a failure function. Loading Loading @@ -936,12 +926,6 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server, pid_t pid = fork(); if (pid == 0) { if (is_priority_fork) { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } else { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); } // The child process. PreApplicationInit(); Loading Loading @@ -1139,9 +1123,6 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); // Reset the process priority to the default value. setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT); if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); } Loading Loading @@ -1379,7 +1360,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( fds_to_ignore.push_back(gUsapPoolEventFD); } pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true); pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, Loading @@ -1406,8 +1387,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( pid_t pid = ForkCommon(env, true, fds_to_close, fds_to_ignore, true); fds_to_ignore); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, Loading Loading @@ -1449,15 +1429,13 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( * zygote in managed code. * @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by * the FD hygiene code and automatically "closed" in the new USAP. * @param is_priority_fork Controls the nice level assigned to the newly created process * @return */ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, jclass, jint read_pipe_fd, jint write_pipe_fd, jintArray managed_session_socket_fds, jboolean is_priority_fork) { jintArray managed_session_socket_fds) { std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), fds_to_ignore(fds_to_close); Loading @@ -1479,8 +1457,7 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, fds_to_ignore.push_back(write_pipe_fd); fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end()); pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, is_priority_fork == JNI_TRUE); pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore); if (usap_pid != 0) { ++gUsapPoolCount; Loading Loading @@ -1701,10 +1678,6 @@ static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv* return dl_iterate_phdr(disable_execute_only, nullptr) == 0; } static void com_android_internal_os_Zygote_nativeBoostUsapPriority(JNIEnv* env, jclass) { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", Loading @@ -1717,7 +1690,7 @@ static const JNINativeMethod gMethods[] = { (void *) com_android_internal_os_Zygote_nativePreApplicationInit }, { "nativeInstallSeccompUidGidFilter", "(II)V", (void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter }, { "nativeForkUsap", "(II[IZ)I", { "nativeForkUsap", "(II[I)I", (void *) com_android_internal_os_Zygote_nativeForkUsap }, { "nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V", Loading @@ -1735,9 +1708,7 @@ static const JNINativeMethod gMethods[] = { { "nativeEmptyUsapPool", "()V", (void *) com_android_internal_os_Zygote_nativeEmptyUsapPool }, { "nativeDisableExecuteOnly", "()Z", (void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly }, { "nativeBoostUsapPriority", "()V", (void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority } (void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly } }; int register_com_android_internal_os_Zygote(JNIEnv* env) { Loading