Merge "Revert "Adjusts the USAP pool refill mechanism."" into qt-dev-plus-aosp
am: e5bcf4ba35
Change-Id: I351c3bb591783db6f278537700515282460772c7
This commit is contained in:
@@ -172,11 +172,6 @@ public final class Zygote {
|
|||||||
*/
|
*/
|
||||||
public static final int SOCKET_BUFFER_SIZE = 256;
|
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() */
|
/** a prototype instance for a future List.toArray() */
|
||||||
protected static final int[][] INT_ARRAY_2D = new int[0][0];
|
protected static final int[][] INT_ARRAY_2D = new int[0][0];
|
||||||
|
|
||||||
@@ -241,7 +236,8 @@ public final class Zygote {
|
|||||||
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
|
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
|
||||||
int targetSdkVersion) {
|
int targetSdkVersion) {
|
||||||
ZygoteHooks.preFork();
|
ZygoteHooks.preFork();
|
||||||
|
// Resets nice priority for zygote process.
|
||||||
|
resetNicePriority();
|
||||||
int pid = nativeForkAndSpecialize(
|
int pid = nativeForkAndSpecialize(
|
||||||
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
|
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
|
||||||
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
|
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
|
||||||
@@ -253,7 +249,6 @@ public final class Zygote {
|
|||||||
// Note that this event ends at the end of handleChildProc,
|
// Note that this event ends at the end of handleChildProc,
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
|
||||||
}
|
}
|
||||||
|
|
||||||
ZygoteHooks.postForkCommon();
|
ZygoteHooks.postForkCommon();
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
@@ -340,16 +335,15 @@ public final class Zygote {
|
|||||||
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
|
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
|
||||||
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
|
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
|
||||||
ZygoteHooks.preFork();
|
ZygoteHooks.preFork();
|
||||||
|
// Resets nice priority for zygote process.
|
||||||
|
resetNicePriority();
|
||||||
int pid = nativeForkSystemServer(
|
int pid = nativeForkSystemServer(
|
||||||
uid, gid, gids, runtimeFlags, rlimits,
|
uid, gid, gids, runtimeFlags, rlimits,
|
||||||
permittedCapabilities, effectiveCapabilities);
|
permittedCapabilities, effectiveCapabilities);
|
||||||
|
|
||||||
// Enable tracing as soon as we enter the system_server.
|
// Enable tracing as soon as we enter the system_server.
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
Trace.setTracingEnabled(true, runtimeFlags);
|
Trace.setTracingEnabled(true, runtimeFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZygoteHooks.postForkCommon();
|
ZygoteHooks.postForkCommon();
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
@@ -467,16 +461,13 @@ public final class Zygote {
|
|||||||
/**
|
/**
|
||||||
* Fork a new unspecialized app process from the 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 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
|
* @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
|
* processes this function will return a Runnable object representing the new
|
||||||
* application that is passed up from usapMain.
|
* application that is passed up from usapMain.
|
||||||
*/
|
*/
|
||||||
static Runnable forkUsap(LocalServerSocket usapPoolSocket,
|
static Runnable forkUsap(LocalServerSocket usapPoolSocket,
|
||||||
int[] sessionSocketRawFDs,
|
int[] sessionSocketRawFDs) {
|
||||||
boolean isPriorityFork) {
|
|
||||||
FileDescriptor[] pipeFDs = null;
|
FileDescriptor[] pipeFDs = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -486,8 +477,7 @@ public final class Zygote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int pid =
|
int pid =
|
||||||
nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(),
|
nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs);
|
||||||
sessionSocketRawFDs, isPriorityFork);
|
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
IoUtils.closeQuietly(pipeFDs[0]);
|
IoUtils.closeQuietly(pipeFDs[0]);
|
||||||
@@ -501,9 +491,8 @@ public final class Zygote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static native int nativeForkUsap(int readPipeFD,
|
private static native int nativeForkUsap(int readPipeFD,
|
||||||
int writePipeFD,
|
int writePipeFD,
|
||||||
int[] sessionSocketRawFDs,
|
int[] sessionSocketRawFDs);
|
||||||
boolean isPriorityFork);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is used by unspecialized app processes to wait for specialization requests from
|
* This function is used by unspecialized app processes to wait for specialization requests from
|
||||||
@@ -526,11 +515,6 @@ public final class Zygote {
|
|||||||
// Load resources
|
// Load resources
|
||||||
ZygoteInit.nativePreloadGraphicsDriver();
|
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) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
sessionSocket = usapPoolSocket.accept();
|
sessionSocket = usapPoolSocket.accept();
|
||||||
@@ -641,12 +625,6 @@ public final class Zygote {
|
|||||||
Log.w(loggingTag, "Unable to set package name.");
|
Log.w(loggingTag, "Unable to set package name.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void boostUsapPriority() {
|
|
||||||
nativeBoostUsapPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native void nativeBoostUsapPriority();
|
|
||||||
|
|
||||||
private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: ";
|
private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: ";
|
||||||
|
|
||||||
@@ -887,6 +865,15 @@ public final class Zygote {
|
|||||||
ZygoteHooks.postForkChild(runtimeFlags, isSystemServer, isZygote, instructionSet);
|
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.
|
* Executes "/system/bin/sh -c <command>" using the exec() system call.
|
||||||
* This method throws a runtime exception if exec() failed, otherwise, this
|
* This method throws a runtime exception if exec() failed, otherwise, this
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ class ZygoteConnection {
|
|||||||
if (zygoteServer.isUsapPoolEnabled()) {
|
if (zygoteServer.isUsapPoolEnabled()) {
|
||||||
Runnable fpResult =
|
Runnable fpResult =
|
||||||
zygoteServer.fillUsapPool(
|
zygoteServer.fillUsapPool(
|
||||||
new int[]{mSocket.getFileDescriptor().getInt$()}, false);
|
new int[]{mSocket.getFileDescriptor().getInt$()});
|
||||||
|
|
||||||
if (fpResult != null) {
|
if (fpResult != null) {
|
||||||
zygoteServer.setForkChild();
|
zygoteServer.setForkChild();
|
||||||
|
|||||||
@@ -822,9 +822,6 @@ public class ZygoteInit {
|
|||||||
public static void main(String argv[]) {
|
public static void main(String argv[]) {
|
||||||
ZygoteServer zygoteServer = null;
|
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
|
// Mark zygote start. This ensures that thread creation will throw
|
||||||
// an error.
|
// an error.
|
||||||
ZygoteHooks.startZygoteNoThreadCreation();
|
ZygoteHooks.startZygoteNoThreadCreation();
|
||||||
@@ -884,6 +881,8 @@ public class ZygoteInit {
|
|||||||
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
|
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
|
||||||
SystemClock.uptimeMillis());
|
SystemClock.uptimeMillis());
|
||||||
bootTimingsTraceLog.traceEnd(); // ZygotePreload
|
bootTimingsTraceLog.traceEnd(); // ZygotePreload
|
||||||
|
} else {
|
||||||
|
Zygote.resetNicePriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do an initial gc to clean up after startup
|
// Do an initial gc to clean up after startup
|
||||||
|
|||||||
@@ -66,12 +66,6 @@ class ZygoteServer {
|
|||||||
/** The default value used for the USAP_POOL_SIZE_MIN device property */
|
/** The default value used for the USAP_POOL_SIZE_MIN device property */
|
||||||
private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";
|
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
|
* 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
|
* should only be true for the primary and secondary Zygotes, and not the App Zygotes or the
|
||||||
@@ -137,18 +131,6 @@ class ZygoteServer {
|
|||||||
*/
|
*/
|
||||||
private int mUsapPoolRefillThreshold = 0;
|
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() {
|
ZygoteServer() {
|
||||||
mUsapPoolEventFD = null;
|
mUsapPoolEventFD = null;
|
||||||
mZygoteSocket = null;
|
mZygoteSocket = null;
|
||||||
@@ -285,13 +267,6 @@ class ZygoteServer {
|
|||||||
mUsapPoolSizeMax);
|
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
|
// Sanity check
|
||||||
if (mUsapPoolSizeMin >= mUsapPoolSizeMax) {
|
if (mUsapPoolSizeMin >= mUsapPoolSizeMax) {
|
||||||
Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size."
|
Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size."
|
||||||
@@ -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
|
* Checks to see if the current policy says that pool should be refilled, and spawns new USAPs
|
||||||
* refill event or not.
|
* if necessary.
|
||||||
*
|
*
|
||||||
* @param sessionSocketRawFDs Anonymous session sockets that are currently open
|
* @param sessionSocketRawFDs Anonymous session sockets that are currently open
|
||||||
* @return In the Zygote process this function will always return null; in unspecialized app
|
* @return In the Zygote process this function will always return null; in unspecialized app
|
||||||
@@ -335,45 +303,38 @@ class ZygoteServer {
|
|||||||
* application that is passed up from usapMain.
|
* 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");
|
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool");
|
||||||
|
|
||||||
// Ensure that the pool properties have been fetched.
|
// Ensure that the pool properties have been fetched.
|
||||||
fetchUsapPoolPolicyPropsIfUnfetched();
|
fetchUsapPoolPolicyPropsWithMinInterval();
|
||||||
|
|
||||||
int usapPoolCount = Zygote.getUsapPoolCount();
|
int usapPoolCount = Zygote.getUsapPoolCount();
|
||||||
int numUsapsToSpawn;
|
int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
|
||||||
|
|
||||||
if (isPriorityRefill) {
|
if (usapPoolCount < mUsapPoolSizeMin
|
||||||
// Refill to min
|
|| numUsapsToSpawn >= mUsapPoolRefillThreshold) {
|
||||||
numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount;
|
|
||||||
|
|
||||||
Log.i("zygote",
|
// Disable some VM functionality and reset some system values
|
||||||
"Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn);
|
// before forking.
|
||||||
} else {
|
ZygoteHooks.preFork();
|
||||||
// Refill up to max
|
Zygote.resetNicePriority();
|
||||||
numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
|
|
||||||
|
|
||||||
Log.i("zygote",
|
while (usapPoolCount++ < mUsapPoolSizeMax) {
|
||||||
"Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn);
|
Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs);
|
||||||
}
|
|
||||||
|
|
||||||
// Disable some VM functionality and reset some system values
|
if (caller != null) {
|
||||||
// before forking.
|
return caller;
|
||||||
ZygoteHooks.preFork();
|
}
|
||||||
|
|
||||||
while (--numUsapsToSpawn >= 0) {
|
|
||||||
Runnable caller =
|
|
||||||
Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill);
|
|
||||||
|
|
||||||
if (caller != null) {
|
|
||||||
return caller;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Re-enable runtime services for the Zygote. Services for unspecialized app process
|
// Re-enable runtime services for the Zygote. Services for unspecialized app process
|
||||||
// are re-enabled in specializeAppProcess.
|
// are re-enabled in specializeAppProcess.
|
||||||
ZygoteHooks.postForkCommon();
|
ZygoteHooks.postForkCommon();
|
||||||
|
|
||||||
|
Log.i("zygote",
|
||||||
|
"Filled the USAP pool. New USAPs: " + numUsapsToSpawn);
|
||||||
|
}
|
||||||
|
|
||||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||||
|
|
||||||
@@ -397,7 +358,7 @@ class ZygoteServer {
|
|||||||
mUsapPoolEnabled = newStatus;
|
mUsapPoolEnabled = newStatus;
|
||||||
|
|
||||||
if (newStatus) {
|
if (newStatus) {
|
||||||
return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false);
|
return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() });
|
||||||
} else {
|
} else {
|
||||||
Zygote.emptyUsapPool();
|
Zygote.emptyUsapPool();
|
||||||
return null;
|
return null;
|
||||||
@@ -416,8 +377,6 @@ class ZygoteServer {
|
|||||||
socketFDs.add(mZygoteSocket.getFileDescriptor());
|
socketFDs.add(mZygoteSocket.getFileDescriptor());
|
||||||
peers.add(null);
|
peers.add(null);
|
||||||
|
|
||||||
long usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
fetchUsapPoolPolicyPropsWithMinInterval();
|
fetchUsapPoolPolicyPropsWithMinInterval();
|
||||||
|
|
||||||
@@ -471,192 +430,140 @@ 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 {
|
try {
|
||||||
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
|
Os.poll(pollFDs, -1);
|
||||||
} catch (ErrnoException ex) {
|
} catch (ErrnoException ex) {
|
||||||
throw new RuntimeException("poll failed", ex);
|
throw new RuntimeException("poll failed", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
UsapPoolRefillAction usapPoolRefillAction = UsapPoolRefillAction.NONE;
|
boolean usapPoolFDRead = false;
|
||||||
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;
|
while (--pollIndex >= 0) {
|
||||||
usapPoolRefillAction = UsapPoolRefillAction.DELAYED;
|
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
if (pollIndex == 0) {
|
||||||
boolean usapPoolFDRead = false;
|
// Zygote server socket
|
||||||
|
|
||||||
|
ZygoteConnection newPeer = acceptCommandPeer(abiList);
|
||||||
|
peers.add(newPeer);
|
||||||
|
socketFDs.add(newPeer.getFileDescriptor());
|
||||||
|
|
||||||
|
} else if (pollIndex < usapPoolEventFDIndex) {
|
||||||
|
// Session socket accepted from the Zygote server socket
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZygoteConnection connection = peers.get(pollIndex);
|
||||||
|
final Runnable command = connection.processOneCommand(this);
|
||||||
|
|
||||||
|
// 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".
|
||||||
|
if (command == null) {
|
||||||
|
throw new IllegalStateException("command == null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return command;
|
||||||
|
} else {
|
||||||
|
// We're in the server - we should never have any commands to run.
|
||||||
|
if (command != null) {
|
||||||
|
throw new IllegalStateException("command != null");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
if (connection.isClosedByPeer()) {
|
||||||
|
connection.closeSocket();
|
||||||
|
peers.remove(pollIndex);
|
||||||
|
socketFDs.remove(pollIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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.
|
||||||
|
|
||||||
|
Slog.e(TAG, "Exception executing zygote command: ", e);
|
||||||
|
|
||||||
|
// Make sure the socket is closed so that the other end knows
|
||||||
|
// immediately that something has gone wrong and doesn't time out
|
||||||
|
// waiting for a response.
|
||||||
|
ZygoteConnection conn = peers.remove(pollIndex);
|
||||||
|
conn.closeSocket();
|
||||||
|
|
||||||
|
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.
|
||||||
|
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.
|
||||||
|
mIsForkChild = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Either the USAP pool event FD or a USAP reporting pipe.
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
long messagePayload = -1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
|
||||||
|
int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
|
||||||
|
|
||||||
|
if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
|
||||||
|
DataInputStream inputStream =
|
||||||
|
new DataInputStream(new ByteArrayInputStream(buffer));
|
||||||
|
|
||||||
|
messagePayload = inputStream.readLong();
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Incomplete read from USAP management FD of size "
|
||||||
|
+ readBytes);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (pollIndex == usapPoolEventFDIndex) {
|
||||||
|
Log.e(TAG, "Failed to read from USAP pool event FD: "
|
||||||
|
+ ex.getMessage());
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Failed to read from USAP reporting pipe: "
|
||||||
|
+ ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
while (--pollIndex >= 0) {
|
|
||||||
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pollIndex == 0) {
|
if (pollIndex > usapPoolEventFDIndex) {
|
||||||
// Zygote server socket
|
Zygote.removeUsapTableEntry((int) messagePayload);
|
||||||
|
|
||||||
ZygoteConnection newPeer = acceptCommandPeer(abiList);
|
|
||||||
peers.add(newPeer);
|
|
||||||
socketFDs.add(newPeer.getFileDescriptor());
|
|
||||||
|
|
||||||
} else if (pollIndex < usapPoolEventFDIndex) {
|
|
||||||
// Session socket accepted from the Zygote server socket
|
|
||||||
|
|
||||||
try {
|
|
||||||
ZygoteConnection connection = peers.get(pollIndex);
|
|
||||||
final Runnable command = connection.processOneCommand(this);
|
|
||||||
|
|
||||||
// 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".
|
|
||||||
if (command == null) {
|
|
||||||
throw new IllegalStateException("command == null");
|
|
||||||
}
|
|
||||||
|
|
||||||
return command;
|
|
||||||
} else {
|
|
||||||
// We're in the server - we should never have any commands to run.
|
|
||||||
if (command != null) {
|
|
||||||
throw new IllegalStateException("command != null");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
if (connection.isClosedByPeer()) {
|
|
||||||
connection.closeSocket();
|
|
||||||
peers.remove(pollIndex);
|
|
||||||
socketFDs.remove(pollIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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.
|
|
||||||
|
|
||||||
Slog.e(TAG, "Exception executing zygote command: ", e);
|
|
||||||
|
|
||||||
// Make sure the socket is closed so that the other end knows
|
|
||||||
// immediately that something has gone wrong and doesn't time out
|
|
||||||
// waiting for a response.
|
|
||||||
ZygoteConnection conn = peers.remove(pollIndex);
|
|
||||||
conn.closeSocket();
|
|
||||||
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
mIsForkChild = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Either the USAP pool event FD or a USAP reporting pipe.
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
|
|
||||||
int readBytes =
|
|
||||||
Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
|
|
||||||
|
|
||||||
if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
|
|
||||||
DataInputStream inputStream =
|
|
||||||
new DataInputStream(new ByteArrayInputStream(buffer));
|
|
||||||
|
|
||||||
messagePayload = inputStream.readLong();
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Incomplete read from USAP management FD of size "
|
|
||||||
+ readBytes);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
if (pollIndex == usapPoolEventFDIndex) {
|
|
||||||
Log.e(TAG, "Failed to read from USAP pool event FD: "
|
|
||||||
+ ex.getMessage());
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Failed to read from USAP reporting pipe: "
|
|
||||||
+ ex.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollIndex > usapPoolEventFDIndex) {
|
|
||||||
Zygote.removeUsapTableEntry((int) messagePayload);
|
|
||||||
}
|
|
||||||
|
|
||||||
usapPoolFDRead = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (usapPoolFDRead) {
|
usapPoolFDRead = true;
|
||||||
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) {
|
// Check to see if the USAP pool needs to be refilled.
|
||||||
|
if (usapPoolFDRead) {
|
||||||
int[] sessionSocketRawFDs =
|
int[] sessionSocketRawFDs =
|
||||||
socketFDs.subList(1, socketFDs.size())
|
socketFDs.subList(1, socketFDs.size())
|
||||||
.stream()
|
.stream()
|
||||||
.mapToInt(FileDescriptor::getInt$)
|
.mapToInt(FileDescriptor::getInt$)
|
||||||
.toArray();
|
.toArray();
|
||||||
|
|
||||||
final boolean isPriorityRefill =
|
final Runnable command = fillUsapPool(sessionSocketRawFDs);
|
||||||
usapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;
|
|
||||||
|
|
||||||
final Runnable command =
|
|
||||||
fillUsapPool(sessionSocketRawFDs, isPriorityRefill);
|
|
||||||
|
|
||||||
if (command != null) {
|
if (command != null) {
|
||||||
return command;
|
return command;
|
||||||
} else if (isPriorityRefill) {
|
|
||||||
// Schedule a delayed refill to finish refilling the pool.
|
|
||||||
usapPoolRefillTriggerTimestamp = System.currentTimeMillis();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,15 +169,6 @@ static int gUsapPoolEventFD = -1;
|
|||||||
*/
|
*/
|
||||||
static constexpr int USAP_POOL_SIZE_MAX_LIMIT = 100;
|
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.
|
* A helper class containing accounting information for USAPs.
|
||||||
*/
|
*/
|
||||||
@@ -902,8 +893,7 @@ static void ClearUsapTable() {
|
|||||||
// Utility routine to fork a process from the zygote.
|
// Utility routine to fork a process from the zygote.
|
||||||
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
|
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
|
||||||
const std::vector<int>& fds_to_close,
|
const std::vector<int>& fds_to_close,
|
||||||
const std::vector<int>& fds_to_ignore,
|
const std::vector<int>& fds_to_ignore) {
|
||||||
bool is_priority_fork) {
|
|
||||||
SetSignalHandlers();
|
SetSignalHandlers();
|
||||||
|
|
||||||
// Curry a failure function.
|
// Curry a failure function.
|
||||||
@@ -936,12 +926,6 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
|
|||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if (pid == 0) {
|
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.
|
// The child process.
|
||||||
PreApplicationInit();
|
PreApplicationInit();
|
||||||
|
|
||||||
@@ -1139,9 +1123,6 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
|
|||||||
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
|
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
|
||||||
is_system_server, is_child_zygote, managed_instruction_set);
|
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()) {
|
if (env->ExceptionCheck()) {
|
||||||
fail_fn("Error calling post fork hooks.");
|
fail_fn("Error calling post fork hooks.");
|
||||||
}
|
}
|
||||||
@@ -1379,7 +1360,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
|
|||||||
fds_to_ignore.push_back(gUsapPoolEventFD);
|
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) {
|
if (pid == 0) {
|
||||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
||||||
@@ -1406,8 +1387,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
|
|||||||
|
|
||||||
pid_t pid = ForkCommon(env, true,
|
pid_t pid = ForkCommon(env, true,
|
||||||
fds_to_close,
|
fds_to_close,
|
||||||
fds_to_ignore,
|
fds_to_ignore);
|
||||||
true);
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
||||||
permitted_capabilities, effective_capabilities,
|
permitted_capabilities, effective_capabilities,
|
||||||
@@ -1449,15 +1429,13 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
|
|||||||
* zygote in managed code.
|
* zygote in managed code.
|
||||||
* @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by
|
* @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.
|
* 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
|
* @return
|
||||||
*/
|
*/
|
||||||
static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
|
static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
|
||||||
jclass,
|
jclass,
|
||||||
jint read_pipe_fd,
|
jint read_pipe_fd,
|
||||||
jint write_pipe_fd,
|
jint write_pipe_fd,
|
||||||
jintArray managed_session_socket_fds,
|
jintArray managed_session_socket_fds) {
|
||||||
jboolean is_priority_fork) {
|
|
||||||
std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
|
std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
|
||||||
fds_to_ignore(fds_to_close);
|
fds_to_ignore(fds_to_close);
|
||||||
|
|
||||||
@@ -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.push_back(write_pipe_fd);
|
||||||
fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end());
|
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,
|
pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore);
|
||||||
is_priority_fork == JNI_TRUE);
|
|
||||||
|
|
||||||
if (usap_pid != 0) {
|
if (usap_pid != 0) {
|
||||||
++gUsapPoolCount;
|
++gUsapPoolCount;
|
||||||
@@ -1701,10 +1678,6 @@ static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv*
|
|||||||
return dl_iterate_phdr(disable_execute_only, nullptr) == 0;
|
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[] = {
|
static const JNINativeMethod gMethods[] = {
|
||||||
{ "nativeForkAndSpecialize",
|
{ "nativeForkAndSpecialize",
|
||||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
|
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
|
||||||
@@ -1717,7 +1690,7 @@ static const JNINativeMethod gMethods[] = {
|
|||||||
(void *) com_android_internal_os_Zygote_nativePreApplicationInit },
|
(void *) com_android_internal_os_Zygote_nativePreApplicationInit },
|
||||||
{ "nativeInstallSeccompUidGidFilter", "(II)V",
|
{ "nativeInstallSeccompUidGidFilter", "(II)V",
|
||||||
(void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter },
|
(void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter },
|
||||||
{ "nativeForkUsap", "(II[IZ)I",
|
{ "nativeForkUsap", "(II[I)I",
|
||||||
(void *) com_android_internal_os_Zygote_nativeForkUsap },
|
(void *) com_android_internal_os_Zygote_nativeForkUsap },
|
||||||
{ "nativeSpecializeAppProcess",
|
{ "nativeSpecializeAppProcess",
|
||||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
||||||
@@ -1735,9 +1708,7 @@ static const JNINativeMethod gMethods[] = {
|
|||||||
{ "nativeEmptyUsapPool", "()V",
|
{ "nativeEmptyUsapPool", "()V",
|
||||||
(void *) com_android_internal_os_Zygote_nativeEmptyUsapPool },
|
(void *) com_android_internal_os_Zygote_nativeEmptyUsapPool },
|
||||||
{ "nativeDisableExecuteOnly", "()Z",
|
{ "nativeDisableExecuteOnly", "()Z",
|
||||||
(void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly },
|
(void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly }
|
||||||
{ "nativeBoostUsapPriority", "()V",
|
|
||||||
(void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int register_com_android_internal_os_Zygote(JNIEnv* env) {
|
int register_com_android_internal_os_Zygote(JNIEnv* env) {
|
||||||
|
|||||||
Reference in New Issue
Block a user