Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1448)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java

Issue 2689673007: android: Move PendingSpawnQueue into ChildConnectionAllocator (Closed)
Patch Set: review Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
index 1a8996c81a8bbc549361a8b4ac3df2fdc6125d39..b17d282b5f46a57d3cc27e2b682d9744f32b3fb0 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -42,6 +42,10 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* This class provides the method to start/stop ChildProcess called by native.
+ *
+ * Note about threading. The threading here is complicated and not well documented.
+ * Code can run on these threads: UI, Launcher, async thread pool, binder, and one-off
+ * background threads.
*/
@JNINamespace("content")
public class ChildProcessLauncher {
@@ -65,7 +69,8 @@ public class ChildProcessLauncher {
private final boolean mInSandbox;
// Each Allocator keeps a queue for the pending spawn data. Once a connection is free, we
// dequeue the pending spawn data from the same allocator as the connection.
- private final PendingSpawnQueue mPendingSpawnQueue = new PendingSpawnQueue();
+ // SHOULD BE ACCESSED WITH mConnectionLock.
+ private final Queue<SpawnData> mPendingSpawnQueue = new LinkedList<>();
public ChildConnectionAllocator(boolean inSandbox, int numChildServices,
String serviceClassName) {
@@ -78,28 +83,32 @@ public class ChildProcessLauncher {
mInSandbox = inSandbox;
}
- public ChildProcessConnection allocate(
- Context context, ChildProcessConnection.DeathCallback deathCallback,
- ChromiumLinkerParams chromiumLinkerParams,
- boolean alwaysInForeground,
- ChildProcessCreationParams creationParams) {
+ // Allocate or enqueue. If there are no free slots, return null and enqueue the spawn data.
+ public ChildProcessConnection allocate(SpawnData spawnData,
+ ChildProcessConnection.DeathCallback deathCallback,
+ ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeground) {
+ assert spawnData.inSandbox() == mInSandbox;
synchronized (mConnectionLock) {
if (mFreeConnectionIndices.isEmpty()) {
Log.d(TAG, "Ran out of services to allocate.");
+ if (!spawnData.forWarmUp()) {
+ mPendingSpawnQueue.add(spawnData);
+ }
return null;
}
int slot = mFreeConnectionIndices.remove(0);
assert mChildProcessConnections[slot] == null;
- mChildProcessConnections[slot] = new ChildProcessConnectionImpl(context, slot,
- mInSandbox, deathCallback, mChildClassName, chromiumLinkerParams,
- alwaysInForeground, creationParams);
+ mChildProcessConnections[slot] = new ChildProcessConnectionImpl(spawnData.context(),
+ slot, mInSandbox, deathCallback, mChildClassName, chromiumLinkerParams,
+ alwaysInForeground, spawnData.getCreationParams());
Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox,
slot);
return mChildProcessConnections[slot];
}
}
- public void free(ChildProcessConnection connection) {
+ // Also return the first SpawnData in the pending queue, if any.
+ public SpawnData free(ChildProcessConnection connection) {
synchronized (mConnectionLock) {
int slot = connection.getServiceNumber();
if (mChildProcessConnections[slot] != connection) {
@@ -115,6 +124,7 @@ public class ChildProcessLauncher {
Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d", mInSandbox,
slot);
}
+ return mPendingSpawnQueue.poll();
}
}
@@ -124,10 +134,6 @@ public class ChildProcessLauncher {
}
}
- public PendingSpawnQueue getPendingSpawnQueue() {
- return mPendingSpawnQueue;
- }
-
/** @return the count of connections managed by the allocator */
@VisibleForTesting
int allocatedConnectionsCountForTesting() {
@@ -138,9 +144,24 @@ public class ChildProcessLauncher {
ChildProcessConnection[] connectionArrayForTesting() {
return mChildProcessConnections;
}
+
+ @VisibleForTesting
+ void enqueuePendingQueueForTesting(SpawnData spawnData) {
+ synchronized (mConnectionLock) {
+ mPendingSpawnQueue.add(spawnData);
+ }
+ }
+
+ @VisibleForTesting
+ int pendingSpawnsCountForTesting() {
+ synchronized (mConnectionLock) {
+ return mPendingSpawnQueue.size();
+ }
+ }
}
- private static class PendingSpawnData {
+ private static class SpawnData {
+ private final boolean mForWarmup; // Do not queue up if failed.
private final Context mContext;
private final String[] mCommandLine;
private final int mChildProcessId;
@@ -150,15 +171,10 @@ public class ChildProcessLauncher {
private final boolean mInSandbox;
private final ChildProcessCreationParams mCreationParams;
- private PendingSpawnData(
- Context context,
- String[] commandLine,
- int childProcessId,
- FileDescriptorInfo[] filesToBeMapped,
- long clientContext,
- int callbackType,
- boolean inSandbox,
- ChildProcessCreationParams creationParams) {
+ private SpawnData(boolean forWarmUp, Context context, String[] commandLine,
+ int childProcessId, FileDescriptorInfo[] filesToBeMapped, long clientContext,
+ int callbackType, boolean inSandbox, ChildProcessCreationParams creationParams) {
+ mForWarmup = forWarmUp;
mContext = context;
mCommandLine = commandLine;
mChildProcessId = childProcessId;
@@ -169,6 +185,10 @@ public class ChildProcessLauncher {
mCreationParams = creationParams;
}
+ private boolean forWarmUp() {
+ return mForWarmup;
+ }
+
private Context context() {
return mContext;
}
@@ -195,37 +215,6 @@ public class ChildProcessLauncher {
}
}
- private static class PendingSpawnQueue {
- // The list of pending process spawn requests and its lock.
- // Operations on this queue must be atomical w.r.t. free connections updates.
- private Queue<PendingSpawnData> mPendingSpawns = new LinkedList<PendingSpawnData>();
- final Object mPendingSpawnsLock = new Object();
-
- /**
- * Queue up a spawn requests to be processed once a free service is available.
- * Called when a spawn is requested while we are at the capacity.
- */
- public void enqueueLocked(final PendingSpawnData pendingSpawn) {
- assert Thread.holdsLock(mPendingSpawnsLock);
- mPendingSpawns.add(pendingSpawn);
- }
-
- /**
- * Pop the next request from the queue. Called when a free service is available.
- * @return the next spawn request waiting in the queue.
- */
- public PendingSpawnData dequeueLocked() {
- assert Thread.holdsLock(mPendingSpawnsLock);
- return mPendingSpawns.poll();
- }
-
- /** @return the count of pending spawns in the queue */
- public int sizeLocked() {
- assert Thread.holdsLock(mPendingSpawnsLock);
- return mPendingSpawns.size();
- }
- }
-
// Service class for child process.
// Map from package name to ChildConnectionAllocator.
private static Map<String, ChildConnectionAllocator> sSandboxedChildConnectionAllocatorMap;
@@ -356,18 +345,14 @@ public class ChildProcessLauncher {
return sSandboxedChildConnectionAllocatorMap.get(packageName);
}
- /**
- * Get the PendingSpawnQueue of the Allocator. Initialize the Allocator if needed.
- */
- private static PendingSpawnQueue getPendingSpawnQueue(Context context, String packageName,
- boolean inSandbox) {
+ private static ChildConnectionAllocator getAllocatorForTesting(
+ Context context, String packageName, boolean inSandbox) {
initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
- return getConnectionAllocator(packageName, inSandbox).getPendingSpawnQueue();
+ return getConnectionAllocator(packageName, inSandbox);
}
- private static ChildProcessConnection allocateConnection(Context context, boolean inSandbox,
- ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeground,
- ChildProcessCreationParams creationParams) {
+ private static ChildProcessConnection allocateConnection(SpawnData spawnData,
+ ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeground) {
ChildProcessConnection.DeathCallback deathCallback =
new ChildProcessConnection.DeathCallback() {
@Override
@@ -379,12 +364,14 @@ public class ChildProcessLauncher {
}
}
};
- String packageName = creationParams != null ? creationParams.getPackageName()
- : context.getPackageName();
+ final ChildProcessCreationParams creationParams = spawnData.getCreationParams();
+ final Context context = spawnData.context();
+ final boolean inSandbox = spawnData.inSandbox();
+ String packageName =
+ creationParams != null ? creationParams.getPackageName() : context.getPackageName();
initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
return getConnectionAllocator(packageName, inSandbox)
- .allocate(context, deathCallback, chromiumLinkerParams, alwaysInForeground,
- creationParams);
+ .allocate(spawnData, deathCallback, chromiumLinkerParams, alwaysInForeground);
}
private static boolean sLinkerInitialized;
@@ -417,20 +404,23 @@ public class ChildProcessLauncher {
}
}
- private static ChildProcessConnection allocateBoundConnection(Context context,
- String[] commandLine, boolean inSandbox, boolean alwaysInForeground,
- ChildProcessCreationParams creationParams,
- ChildProcessConnection.StartCallback startCallback) {
+ private static ChildProcessConnection allocateBoundConnection(SpawnData spawnData,
+ boolean alwaysInForeground, ChildProcessConnection.StartCallback startCallback) {
+ final Context context = spawnData.context();
+ final String[] commandLine = spawnData.commandLine();
+ final boolean inSandbox = spawnData.inSandbox();
+ final ChildProcessCreationParams creationParams = spawnData.getCreationParams();
ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnection();
- ChildProcessConnection connection = allocateConnection(
- context, inSandbox, chromiumLinkerParams, alwaysInForeground, creationParams);
+ ChildProcessConnection connection =
+ allocateConnection(spawnData, chromiumLinkerParams, alwaysInForeground);
if (connection != null) {
connection.start(commandLine, startCallback);
String packageName = creationParams != null ? creationParams.getPackageName()
- : context.getPackageName();
- if (inSandbox && !getConnectionAllocator(packageName, inSandbox)
- .isFreeConnectionAvailable()) {
+ : context.getPackageName();
+ if (inSandbox
+ && !getConnectionAllocator(packageName, inSandbox)
+ .isFreeConnectionAvailable()) {
// Proactively releases all the moderate bindings once all the sandboxed services
// are allocated, which will be very likely to have some of them killed by OOM
// killer.
@@ -456,7 +446,7 @@ public class ChildProcessLauncher {
ThreadUtils.postOnUiThreadDelayed(new Runnable() {
@Override
public void run() {
- final PendingSpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
+ final SpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
if (pendingSpawn != null) {
new Thread(new Runnable() {
@Override
@@ -472,15 +462,11 @@ public class ChildProcessLauncher {
}, FREE_CONNECTION_DELAY_MILLIS);
}
- private static PendingSpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
+ private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
ChildConnectionAllocator allocator = getConnectionAllocator(
conn.getPackageName(), conn.isInSandbox());
assert allocator != null;
- PendingSpawnQueue pendingSpawnQueue = allocator.getPendingSpawnQueue();
- synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
- allocator.free(conn);
- return pendingSpawnQueue.dequeueLocked();
- }
+ return allocator.free(conn);
}
// Represents an invalid process handle; same as base/process/process.h kNullProcessHandle.
@@ -612,8 +598,12 @@ public class ChildProcessLauncher {
}
}
};
- sSpareSandboxedConnection = allocateBoundConnection(context, null, true, false,
- params, startCallback);
+ SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context,
+ null /* commandLine */, -1 /* child process id */,
+ null /* filesToBeMapped */, 0 /* clientContext */,
+ CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, params);
+ sSpareSandboxedConnection = allocateBoundConnection(
+ spawnData, false /* alwaysInForeground */, startCallback);
}
}
}
@@ -722,8 +712,6 @@ public class ChildProcessLauncher {
if (allocatedConnection == null) {
boolean alwaysInForeground = false;
if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true;
- PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(
- context, packageName, inSandbox);
ChildProcessConnection.StartCallback startCallback =
new ChildProcessConnection.StartCallback() {
@Override
@@ -747,17 +735,14 @@ public class ChildProcessLauncher {
});
}
};
- synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
- allocatedConnection = allocateBoundConnection(
- context, commandLine, inSandbox, alwaysInForeground, creationParams,
- startCallback);
- if (allocatedConnection == null) {
- Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn.");
- pendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine,
- childProcessId, filesToBeMapped, clientContext,
- callbackType, inSandbox, creationParams));
- return null;
- }
+
+ SpawnData spawnData = new SpawnData(false /* forWarmUp */, context, commandLine,
+ childProcessId, filesToBeMapped, clientContext, callbackType, inSandbox,
+ creationParams);
+ allocatedConnection =
+ allocateBoundConnection(spawnData, alwaysInForeground, startCallback);
+ if (allocatedConnection == null) {
+ return null;
}
}
@@ -893,14 +878,21 @@ public class ChildProcessLauncher {
@VisibleForTesting
static ChildProcessConnection allocateBoundConnectionForTesting(Context context,
ChildProcessCreationParams creationParams) {
- return allocateBoundConnection(context, null, true, false, creationParams, null);
+ return allocateBoundConnection(
+ new SpawnData(false /* forWarmUp */, context, null /* commandLine */,
+ 0 /* childProcessId */, null /* filesToBeMapped */, 0 /* clientContext */,
+ CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, creationParams),
+ false /* alwaysInForeground */, null);
}
@VisibleForTesting
static ChildProcessConnection allocateConnectionForTesting(Context context,
ChildProcessCreationParams creationParams) {
return allocateConnection(
- context, true, getLinkerParamsForNewConnection(), false, creationParams);
+ new SpawnData(false /* forWarmUp */, context, null /* commandLine */,
+ 0 /* childProcessId */, null /* filesToBeMapped */, 0 /* clientContext */,
+ CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, creationParams),
+ getLinkerParamsForNewConnection(), false);
}
/**
@@ -911,13 +903,11 @@ public class ChildProcessLauncher {
ChildProcessCreationParams creationParams, boolean inSandbox) {
String packageName = creationParams != null ? creationParams.getPackageName()
: context.getPackageName();
- PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(context,
- packageName, inSandbox);
- synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
- pendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine, 1,
- new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true,
- creationParams));
- }
+ ChildConnectionAllocator allocator =
+ getAllocatorForTesting(context, packageName, inSandbox);
+ allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp*/, context,
+ commandLine, 1, new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true,
+ creationParams));
}
/**
@@ -935,8 +925,7 @@ public class ChildProcessLauncher {
* @return gets the service connection array for a specific package name.
*/
@VisibleForTesting
- static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(
- String packageName) {
+ static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(String packageName) {
return sSandboxedChildConnectionAllocatorMap.get(packageName).connectionArrayForTesting();
}
@@ -953,12 +942,11 @@ public class ChildProcessLauncher {
* @return the count of pending spawns in the queue.
*/
@VisibleForTesting
- static int pendingSpawnsCountForTesting(Context context, String packageName,
- boolean inSandbox) {
- PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(context, packageName, inSandbox);
- synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
- return pendingSpawnQueue.sizeLocked();
- }
+ static int pendingSpawnsCountForTesting(
+ Context context, String packageName, boolean inSandbox) {
+ ChildConnectionAllocator allocator =
+ getAllocatorForTesting(context, packageName, inSandbox);
+ return allocator.pendingSpawnsCountForTesting();
}
/**
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698