resolve merge conflicts of 40654b7696 to qt-dev-plus-aosp
Bug: None Test: I solemnly swear I tested this conflict resolution. Merged-In: If26d625c4b1e5e8eee54dcdacb32360b0d852829 Change-Id: I36452eb4cfbc1c22533a2168aaa2ee0fad54286c
This commit is contained in:
@@ -172,6 +172,11 @@ 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];
|
||||
|
||||
@@ -236,8 +241,7 @@ 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);
|
||||
@@ -249,6 +253,7 @@ 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;
|
||||
}
|
||||
@@ -335,15 +340,16 @@ 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;
|
||||
}
|
||||
@@ -461,13 +467,16 @@ 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) {
|
||||
int[] sessionSocketRawFDs,
|
||||
boolean isPriorityFork) {
|
||||
FileDescriptor[] pipeFDs = null;
|
||||
|
||||
try {
|
||||
@@ -477,7 +486,8 @@ public final class Zygote {
|
||||
}
|
||||
|
||||
int pid =
|
||||
nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs);
|
||||
nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(),
|
||||
sessionSocketRawFDs, isPriorityFork);
|
||||
|
||||
if (pid == 0) {
|
||||
IoUtils.closeQuietly(pipeFDs[0]);
|
||||
@@ -491,8 +501,9 @@ public final class Zygote {
|
||||
}
|
||||
|
||||
private static native int nativeForkUsap(int readPipeFD,
|
||||
int writePipeFD,
|
||||
int[] sessionSocketRawFDs);
|
||||
int writePipeFD,
|
||||
int[] sessionSocketRawFDs,
|
||||
boolean isPriorityFork);
|
||||
|
||||
/**
|
||||
* This function is used by unspecialized app processes to wait for specialization requests from
|
||||
@@ -515,6 +526,11 @@ 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();
|
||||
@@ -626,6 +642,12 @@ public final class Zygote {
|
||||
}
|
||||
}
|
||||
|
||||
private static void boostUsapPriority() {
|
||||
nativeBoostUsapPriority();
|
||||
}
|
||||
|
||||
private static native void nativeBoostUsapPriority();
|
||||
|
||||
private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: ";
|
||||
|
||||
/**
|
||||
@@ -865,15 +887,6 @@ 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
|
||||
|
||||
@@ -330,7 +330,7 @@ class ZygoteConnection {
|
||||
if (zygoteServer.isUsapPoolEnabled()) {
|
||||
Runnable fpResult =
|
||||
zygoteServer.fillUsapPool(
|
||||
new int[]{mSocket.getFileDescriptor().getInt$()});
|
||||
new int[]{mSocket.getFileDescriptor().getInt$()}, false);
|
||||
|
||||
if (fpResult != null) {
|
||||
zygoteServer.setForkChild();
|
||||
|
||||
@@ -822,6 +822,9 @@ 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();
|
||||
@@ -881,8 +884,6 @@ 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
|
||||
|
||||
@@ -66,6 +66,15 @@ class ZygoteServer {
|
||||
/** The default value used for the USAP_POOL_SIZE_MIN device property */
|
||||
private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";
|
||||
|
||||
/**
|
||||
* Number of milliseconds to delay before refilling the pool if it hasn't reached its
|
||||
* minimum value.
|
||||
*/
|
||||
private static final int USAP_REFILL_DELAY_MS = 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
|
||||
@@ -131,6 +140,12 @@ class ZygoteServer {
|
||||
*/
|
||||
private int mUsapPoolRefillThreshold = 0;
|
||||
|
||||
private enum UsapPoolRefillAction {
|
||||
DELAYED,
|
||||
IMMEDIATE,
|
||||
NONE
|
||||
}
|
||||
|
||||
ZygoteServer() {
|
||||
mUsapPoolEventFD = null;
|
||||
mZygoteSocket = null;
|
||||
@@ -293,9 +308,16 @@ class ZygoteServer {
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchUsapPoolPolicyPropsIfUnfetched() {
|
||||
if (mIsFirstPropertyCheck) {
|
||||
mIsFirstPropertyCheck = false;
|
||||
fetchUsapPoolPolicyProps();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the current policy says that pool should be refilled, and spawns new USAPs
|
||||
* if necessary.
|
||||
* Refill the USAP Pool to the appropriate level, determined by whether this is a priority
|
||||
* refill event or not.
|
||||
*
|
||||
* @param sessionSocketRawFDs Anonymous session sockets that are currently open
|
||||
* @return In the Zygote process this function will always return null; in unspecialized app
|
||||
@@ -303,39 +325,46 @@ class ZygoteServer {
|
||||
* application that is passed up from usapMain.
|
||||
*/
|
||||
|
||||
Runnable fillUsapPool(int[] sessionSocketRawFDs) {
|
||||
Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool");
|
||||
|
||||
// Ensure that the pool properties have been fetched.
|
||||
fetchUsapPoolPolicyPropsWithMinInterval();
|
||||
fetchUsapPoolPolicyPropsIfUnfetched();
|
||||
|
||||
int usapPoolCount = Zygote.getUsapPoolCount();
|
||||
int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
|
||||
int numUsapsToSpawn;
|
||||
|
||||
if (usapPoolCount < mUsapPoolSizeMin
|
||||
|| numUsapsToSpawn >= mUsapPoolRefillThreshold) {
|
||||
|
||||
// Disable some VM functionality and reset some system values
|
||||
// before forking.
|
||||
ZygoteHooks.preFork();
|
||||
Zygote.resetNicePriority();
|
||||
|
||||
while (usapPoolCount++ < mUsapPoolSizeMax) {
|
||||
Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs);
|
||||
|
||||
if (caller != null) {
|
||||
return caller;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-enable runtime services for the Zygote. Services for unspecialized app process
|
||||
// are re-enabled in specializeAppProcess.
|
||||
ZygoteHooks.postForkCommon();
|
||||
if (isPriorityRefill) {
|
||||
// Refill to min
|
||||
numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount;
|
||||
|
||||
Log.i("zygote",
|
||||
"Filled the USAP pool. New USAPs: " + numUsapsToSpawn);
|
||||
"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);
|
||||
}
|
||||
|
||||
// Disable some VM functionality and reset some system values
|
||||
// before forking.
|
||||
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
|
||||
// are re-enabled in specializeAppProcess.
|
||||
ZygoteHooks.postForkCommon();
|
||||
|
||||
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
|
||||
|
||||
return null;
|
||||
@@ -358,7 +387,7 @@ class ZygoteServer {
|
||||
mUsapPoolEnabled = newStatus;
|
||||
|
||||
if (newStatus) {
|
||||
return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() });
|
||||
return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false);
|
||||
} else {
|
||||
Zygote.emptyUsapPool();
|
||||
return null;
|
||||
@@ -377,6 +406,8 @@ class ZygoteServer {
|
||||
socketFDs.add(mZygoteSocket.getFileDescriptor());
|
||||
peers.add(null);
|
||||
|
||||
long usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
|
||||
|
||||
while (true) {
|
||||
fetchUsapPoolPolicyPropsWithMinInterval();
|
||||
|
||||
@@ -430,142 +461,192 @@ class ZygoteServer {
|
||||
}
|
||||
}
|
||||
|
||||
int pollTimeoutMs;
|
||||
|
||||
if (usapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
|
||||
pollTimeoutMs = -1;
|
||||
} else {
|
||||
int elapsedTimeMs =
|
||||
(int) (System.currentTimeMillis() - usapPoolRefillTriggerTimestamp);
|
||||
|
||||
if (elapsedTimeMs >= USAP_REFILL_DELAY_MS) {
|
||||
// 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 = USAP_REFILL_DELAY_MS - elapsedTimeMs;
|
||||
}
|
||||
}
|
||||
|
||||
int pollReturnValue;
|
||||
try {
|
||||
Os.poll(pollFDs, -1);
|
||||
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
|
||||
} catch (ErrnoException ex) {
|
||||
throw new RuntimeException("poll failed", ex);
|
||||
}
|
||||
|
||||
boolean usapPoolFDRead = false;
|
||||
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.
|
||||
|
||||
while (--pollIndex >= 0) {
|
||||
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
|
||||
continue;
|
||||
}
|
||||
usapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
|
||||
usapPoolRefillAction = UsapPoolRefillAction.DELAYED;
|
||||
|
||||
if (pollIndex == 0) {
|
||||
// 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. 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());
|
||||
}
|
||||
} else {
|
||||
boolean usapPoolFDRead = false;
|
||||
|
||||
while (--pollIndex >= 0) {
|
||||
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pollIndex > usapPoolEventFDIndex) {
|
||||
Zygote.removeUsapTableEntry((int) messagePayload);
|
||||
}
|
||||
if (pollIndex == 0) {
|
||||
// Zygote server socket
|
||||
|
||||
usapPoolFDRead = true;
|
||||
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) {
|
||||
int usapPoolCount = Zygote.getUsapPoolCount();
|
||||
|
||||
if (usapPoolCount < mUsapPoolSizeMin) {
|
||||
// Immediate refill
|
||||
usapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
|
||||
} else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {
|
||||
// Delayed refill
|
||||
usapPoolRefillTriggerTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if the USAP pool needs to be refilled.
|
||||
if (usapPoolFDRead) {
|
||||
if (usapPoolRefillAction != UsapPoolRefillAction.NONE) {
|
||||
int[] sessionSocketRawFDs =
|
||||
socketFDs.subList(1, socketFDs.size())
|
||||
.stream()
|
||||
.mapToInt(FileDescriptor::getInt$)
|
||||
.toArray();
|
||||
|
||||
final Runnable command = fillUsapPool(sessionSocketRawFDs);
|
||||
final boolean isPriorityRefill =
|
||||
usapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;
|
||||
|
||||
final Runnable command =
|
||||
fillUsapPool(sessionSocketRawFDs, isPriorityRefill);
|
||||
|
||||
if (command != null) {
|
||||
return command;
|
||||
} else if (isPriorityRefill) {
|
||||
// Schedule a delayed refill to finish refilling the pool.
|
||||
usapPoolRefillTriggerTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,15 @@ 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.
|
||||
*/
|
||||
@@ -893,7 +902,8 @@ 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) {
|
||||
const std::vector<int>& fds_to_ignore,
|
||||
bool is_priority_fork) {
|
||||
SetSignalHandlers();
|
||||
|
||||
// Curry a failure function.
|
||||
@@ -926,6 +936,12 @@ 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();
|
||||
|
||||
@@ -1123,6 +1139,9 @@ 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.");
|
||||
}
|
||||
@@ -1360,7 +1379,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);
|
||||
pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
|
||||
|
||||
if (pid == 0) {
|
||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
||||
@@ -1387,7 +1406,8 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
|
||||
|
||||
pid_t pid = ForkCommon(env, true,
|
||||
fds_to_close,
|
||||
fds_to_ignore);
|
||||
fds_to_ignore,
|
||||
true);
|
||||
if (pid == 0) {
|
||||
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
|
||||
permitted_capabilities, effective_capabilities,
|
||||
@@ -1429,13 +1449,15 @@ 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) {
|
||||
jintArray managed_session_socket_fds,
|
||||
jboolean is_priority_fork) {
|
||||
std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
|
||||
fds_to_ignore(fds_to_close);
|
||||
|
||||
@@ -1457,7 +1479,8 @@ 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);
|
||||
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) {
|
||||
++gUsapPoolCount;
|
||||
@@ -1678,6 +1701,10 @@ 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",
|
||||
@@ -1690,7 +1717,7 @@ static const JNINativeMethod gMethods[] = {
|
||||
(void *) com_android_internal_os_Zygote_nativePreApplicationInit },
|
||||
{ "nativeInstallSeccompUidGidFilter", "(II)V",
|
||||
(void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter },
|
||||
{ "nativeForkUsap", "(II[I)I",
|
||||
{ "nativeForkUsap", "(II[IZ)I",
|
||||
(void *) com_android_internal_os_Zygote_nativeForkUsap },
|
||||
{ "nativeSpecializeAppProcess",
|
||||
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
|
||||
@@ -1708,7 +1735,9 @@ static const JNINativeMethod gMethods[] = {
|
||||
{ "nativeEmptyUsapPool", "()V",
|
||||
(void *) com_android_internal_os_Zygote_nativeEmptyUsapPool },
|
||||
{ "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) {
|
||||
|
||||
Reference in New Issue
Block a user