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

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

Issue 2795113003: Factor out inner-classes out of ChildProcessLauncher. (Closed)
Patch Set: Addressed boliu@'s comments. Created 3 years, 8 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
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 db717bfcc52f6f32ea769d49eec437c164d70f8c..6fbc3ed6a12953831fd75b05c7bdacd6ba9cb186 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
@@ -4,14 +4,10 @@
package org.chromium.content.browser;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.text.TextUtils;
import org.chromium.base.CpuFeatures;
import org.chromium.base.Log;
@@ -22,14 +18,9 @@ import org.chromium.base.library_loader.Linker;
import org.chromium.base.process_launcher.ChildProcessCreationParams;
import org.chromium.base.process_launcher.FileDescriptorInfo;
import org.chromium.content.app.ChromiumLinkerParams;
-import org.chromium.content.app.PrivilegedProcessService;
-import org.chromium.content.app.SandboxedProcessService;
import org.chromium.content.common.ContentSwitches;
-import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.Map;
-import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -42,310 +33,15 @@ import java.util.concurrent.ConcurrentHashMap;
public class ChildProcessLauncher {
private static final String TAG = "ChildProcLauncher";
- private static class ChildConnectionAllocator {
- // Connections to services. Indices of the array correspond to the service numbers.
- private final ChildProcessConnection[] mChildProcessConnections;
-
- // The list of free (not bound) service indices.
- // SHOULD BE ACCESSED WITH mConnectionLock.
- private final ArrayList<Integer> mFreeConnectionIndices;
- private final Object mConnectionLock = new Object();
-
- private final String mChildClassName;
- 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.
- // SHOULD BE ACCESSED WITH mConnectionLock.
- private final Queue<SpawnData> mPendingSpawnQueue = new LinkedList<>();
-
- public ChildConnectionAllocator(boolean inSandbox, int numChildServices,
- String serviceClassName) {
- mChildProcessConnections = new ChildProcessConnectionImpl[numChildServices];
- mFreeConnectionIndices = new ArrayList<Integer>(numChildServices);
- for (int i = 0; i < numChildServices; i++) {
- mFreeConnectionIndices.add(i);
- }
- mChildClassName = serviceClassName;
- mInSandbox = inSandbox;
- }
-
- // Allocate or enqueue. If there are no free slots, return null and enqueue the spawn data.
- public ChildProcessConnection allocate(SpawnData spawnData,
- ChildProcessConnection.DeathCallback deathCallback,
- Bundle childProcessCommonParameters) {
- assert spawnData.isInSandbox() == mInSandbox;
- synchronized (mConnectionLock) {
- if (mFreeConnectionIndices.isEmpty()) {
- Log.d(TAG, "Ran out of services to allocate.");
- if (!spawnData.isForWarmUp()) {
- mPendingSpawnQueue.add(spawnData);
- }
- return null;
- }
- int slot = mFreeConnectionIndices.remove(0);
- assert mChildProcessConnections[slot] == null;
- mChildProcessConnections[slot] =
- new ChildProcessConnectionImpl(spawnData.getContext(), slot, mInSandbox,
- deathCallback, mChildClassName, childProcessCommonParameters,
- spawnData.isAlwaysInForeground(), spawnData.getCreationParams());
- Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox,
- slot);
- return mChildProcessConnections[slot];
- }
- }
-
- // 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) {
- int occupier = mChildProcessConnections[slot] == null
- ? -1 : mChildProcessConnections[slot].getServiceNumber();
- Log.e(TAG, "Unable to find connection to free in slot: %d "
- + "already occupied by service: %d", slot, occupier);
- assert false;
- } else {
- mChildProcessConnections[slot] = null;
- assert !mFreeConnectionIndices.contains(slot);
- mFreeConnectionIndices.add(slot);
- Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d", mInSandbox,
- slot);
- }
- return mPendingSpawnQueue.poll();
- }
- }
-
- public boolean isFreeConnectionAvailable() {
- synchronized (mConnectionLock) {
- return !mFreeConnectionIndices.isEmpty();
- }
- }
-
- /** @return the count of connections managed by the allocator */
- @VisibleForTesting
- int allocatedConnectionsCountForTesting() {
- return mChildProcessConnections.length - mFreeConnectionIndices.size();
- }
-
- @VisibleForTesting
- 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 SpawnData {
- private final boolean mForWarmup; // Do not queue up if failed.
- private final Context mContext;
- private final String[] mCommandLine;
- private final int mChildProcessId;
- private final FileDescriptorInfo[] mFilesToBeMapped;
- private final LaunchCallback mLaunchCallback;
- private final IBinder mChildProcessCallback;
- private final boolean mInSandbox;
- private final boolean mAlwaysInForeground;
- private final ChildProcessCreationParams mCreationParams;
-
- private SpawnData(boolean forWarmUp, Context context, String[] commandLine,
- int childProcessId, FileDescriptorInfo[] filesToBeMapped,
- LaunchCallback launchCallback, IBinder childProcessCallback, boolean inSandbox,
- boolean alwaysInForeground, ChildProcessCreationParams creationParams) {
- mForWarmup = forWarmUp;
- mContext = context;
- mCommandLine = commandLine;
- mChildProcessId = childProcessId;
- mFilesToBeMapped = filesToBeMapped;
- mLaunchCallback = launchCallback;
- mChildProcessCallback = childProcessCallback;
- mInSandbox = inSandbox;
- mAlwaysInForeground = alwaysInForeground;
- mCreationParams = creationParams;
- }
-
- private boolean isForWarmUp() {
- return mForWarmup;
- }
- private Context getContext() {
- return mContext;
- }
- private String[] getCommandLine() {
- return mCommandLine;
- }
- private int getChildProcessId() {
- return mChildProcessId;
- }
- private FileDescriptorInfo[] getFilesToBeMapped() {
- return mFilesToBeMapped;
- }
- private LaunchCallback getLaunchCallback() {
- return mLaunchCallback;
- }
- private IBinder getChildProcessCallback() {
- return mChildProcessCallback;
- }
- private boolean isInSandbox() {
- return mInSandbox;
- }
- private boolean isAlwaysInForeground() {
- return mAlwaysInForeground;
- }
- private ChildProcessCreationParams getCreationParams() {
- return mCreationParams;
- }
- }
-
/**
* Implemented by ChildProcessLauncherHelper.
*/
public interface LaunchCallback { void onChildProcessStarted(int pid); }
- // Service class for child process.
- // Map from package name to ChildConnectionAllocator.
- private static Map<String, ChildConnectionAllocator> sSandboxedChildConnectionAllocatorMap;
- // As the default value it uses PrivilegedProcessService0.
- private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator;
-
private static final boolean SPARE_CONNECTION_ALWAYS_IN_FOREGROUND = false;
- private static final String NUM_SANDBOXED_SERVICES_KEY =
- "org.chromium.content.browser.NUM_SANDBOXED_SERVICES";
- private static final String NUM_PRIVILEGED_SERVICES_KEY =
- "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES";
- private static final String SANDBOXED_SERVICES_NAME_KEY =
- "org.chromium.content.browser.SANDBOXED_SERVICES_NAME";
-
- // Used by tests to override the default sandboxed service settings.
- private static int sSandboxedServicesCountForTesting = -1;
- private static String sSandboxedServicesNameForTesting;
-
- @VisibleForTesting
- public static void setSanboxServicesSettingsForTesting(int serviceCount, String serviceName) {
- sSandboxedServicesCountForTesting = serviceCount;
- sSandboxedServicesNameForTesting = serviceName;
- }
-
- static int getNumberOfServices(Context context, boolean inSandbox, String packageName) {
- int numServices = -1;
- if (inSandbox && sSandboxedServicesCountForTesting != -1) {
- numServices = sSandboxedServicesCountForTesting;
- } else {
- try {
- PackageManager packageManager = context.getPackageManager();
- ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName,
- PackageManager.GET_META_DATA);
- if (appInfo.metaData != null) {
- numServices = appInfo.metaData.getInt(inSandbox
- ? NUM_SANDBOXED_SERVICES_KEY : NUM_PRIVILEGED_SERVICES_KEY, -1);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException("Could not get application info");
- }
- }
- if (numServices < 0) {
- throw new RuntimeException("Illegal meta data value for number of child services");
- }
- return numServices;
- }
-
- private static String getClassNameOfService(Context context, boolean inSandbox,
- String packageName) {
- if (!inSandbox) {
- return PrivilegedProcessService.class.getName();
- }
-
- if (!TextUtils.isEmpty(sSandboxedServicesNameForTesting)) {
- return sSandboxedServicesNameForTesting;
- }
-
- String serviceName = null;
- try {
- PackageManager packageManager = context.getPackageManager();
- ApplicationInfo appInfo =
- packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
- if (appInfo.metaData != null) {
- serviceName = appInfo.metaData.getString(SANDBOXED_SERVICES_NAME_KEY);
- }
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException("Could not get application info.");
- }
-
- if (serviceName != null) {
- // Check that the service exists.
- try {
- PackageManager packageManager = context.getPackageManager();
- // PackageManager#getServiceInfo() throws an exception if the service does not
- // exist.
- packageManager.getServiceInfo(new ComponentName(packageName, serviceName + "0"), 0);
- return serviceName;
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(
- "Illegal meta data value: the child service doesn't exist");
- }
- }
- return SandboxedProcessService.class.getName();
- }
-
- private static void initConnectionAllocatorsIfNecessary(
- Context context, boolean inSandbox, String packageName) {
- // TODO(mariakhomenko): Uses an Object to lock the access.
- synchronized (ChildProcessLauncher.class) {
- if (inSandbox) {
- if (sSandboxedChildConnectionAllocatorMap == null) {
- sSandboxedChildConnectionAllocatorMap =
- new ConcurrentHashMap<String, ChildConnectionAllocator>();
- }
- if (!sSandboxedChildConnectionAllocatorMap.containsKey(packageName)) {
- Log.w(TAG, "Create a new ChildConnectionAllocator with package name = %s,"
- + " inSandbox = true",
- packageName);
- sSandboxedChildConnectionAllocatorMap.put(packageName,
- new ChildConnectionAllocator(true,
- getNumberOfServices(context, true, packageName),
- getClassNameOfService(context, true, packageName)));
- }
- } else if (sPrivilegedChildConnectionAllocator == null) {
- sPrivilegedChildConnectionAllocator = new ChildConnectionAllocator(false,
- getNumberOfServices(context, false, packageName),
- getClassNameOfService(context, false, packageName));
- }
- // TODO(pkotwicz|hanxi): Figure out when old allocators should be removed from
- // {@code sSandboxedChildConnectionAllocatorMap}.
- }
- }
-
- /**
- * Note: please make sure that the Allocator has been initialized before calling this function.
- * Otherwise, always calls {@link initConnectionAllocatorsIfNecessary} first.
- */
- private static ChildConnectionAllocator getConnectionAllocator(
- String packageName, boolean inSandbox) {
- if (!inSandbox) {
- return sPrivilegedChildConnectionAllocator;
- }
- return sSandboxedChildConnectionAllocatorMap.get(packageName);
- }
-
- private static ChildConnectionAllocator getAllocatorForTesting(
- Context context, String packageName, boolean inSandbox) {
- initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
- return getConnectionAllocator(packageName, inSandbox);
- }
-
private static ChildProcessConnection allocateConnection(
- SpawnData spawnData, Bundle childProcessCommonParams) {
+ ChildSpawnData spawnData, Bundle childProcessCommonParams, boolean forWarmUp) {
ChildProcessConnection.DeathCallback deathCallback =
new ChildProcessConnection.DeathCallback() {
@Override
@@ -362,9 +58,8 @@ public class ChildProcessLauncher {
final boolean inSandbox = spawnData.isInSandbox();
String packageName =
creationParams != null ? creationParams.getPackageName() : context.getPackageName();
- initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
- return getConnectionAllocator(packageName, inSandbox)
- .allocate(spawnData, deathCallback, childProcessCommonParams);
+ return ChildConnectionAllocator.getAllocator(context, packageName, inSandbox)
+ .allocate(spawnData, deathCallback, childProcessCommonParams, !forWarmUp);
}
private static boolean sLinkerInitialized;
@@ -406,20 +101,21 @@ public class ChildProcessLauncher {
return commonParams;
}
- private static ChildProcessConnection allocateBoundConnection(
- SpawnData spawnData, ChildProcessConnection.StartCallback startCallback) {
+ private static ChildProcessConnection allocateBoundConnection(ChildSpawnData spawnData,
+ ChildProcessConnection.StartCallback startCallback, boolean forWarmUp) {
final Context context = spawnData.getContext();
final boolean inSandbox = spawnData.isInSandbox();
final ChildProcessCreationParams creationParams = spawnData.getCreationParams();
+
ChildProcessConnection connection = allocateConnection(
- spawnData, createCommonParamsBundle(spawnData.getCreationParams()));
+ spawnData, createCommonParamsBundle(spawnData.getCreationParams()), forWarmUp);
if (connection != null) {
connection.start(startCallback);
String packageName = creationParams != null ? creationParams.getPackageName()
: context.getPackageName();
if (inSandbox
- && !getConnectionAllocator(packageName, inSandbox)
+ && !ChildConnectionAllocator.getAllocator(context, 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
@@ -446,7 +142,7 @@ public class ChildProcessLauncher {
ThreadUtils.postOnUiThreadDelayed(new Runnable() {
@Override
public void run() {
- final SpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
+ final ChildSpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
if (pendingSpawn != null) {
LauncherThread.post(new Runnable() {
@Override
@@ -465,9 +161,14 @@ public class ChildProcessLauncher {
}, FREE_CONNECTION_DELAY_MILLIS);
}
- private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
- ChildConnectionAllocator allocator = getConnectionAllocator(
- conn.getPackageName(), conn.isInSandbox());
+ private static ChildSpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
+ // TODO(jcivelli): it should be safe to pass a null Context here as it is used to initialize
+ // the ChildConnectionAllocator object and if we are freeing a connection, we must have
+ // allocated one previously guaranteeing it is already initialized.
+ // When we consolidate ChildProcessLauncher and ChildProcessLauncherHelper, we'll have a
+ // context around that we can pass in there.
+ ChildConnectionAllocator allocator = ChildConnectionAllocator.getAllocator(
+ null /* context */, conn.getPackageName(), conn.isInSandbox());
assert allocator != null;
return allocator.free(conn);
}
@@ -533,8 +234,9 @@ public class ChildProcessLauncher {
* sent to the background.
*/
public static void startModerateBindingManagement(Context context) {
- sBindingManager.startModerateBindingManagement(
- context, getNumberOfServices(context, true, context.getPackageName()));
+ sBindingManager.startModerateBindingManagement(context,
+ ChildConnectionAllocator.getNumberOfServices(
+ context, true, context.getPackageName()));
}
/**
@@ -587,13 +289,13 @@ public class ChildProcessLauncher {
}
}
};
- SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context,
+ ChildSpawnData spawnData = new ChildSpawnData(context,
null /* commandLine */, -1 /* child process id */,
null /* filesToBeMapped */, null /* launchCallback */,
null /* child process callback */, true /* inSandbox */,
SPARE_CONNECTION_ALWAYS_IN_FOREGROUND, params);
- sSpareSandboxedConnection =
- allocateBoundConnection(spawnData, startCallback);
+ sSpareSandboxedConnection = allocateBoundConnection(
+ spawnData, startCallback, true /* forWarmUp */);
}
}
}
@@ -707,10 +409,11 @@ public class ChildProcessLauncher {
}
};
- SpawnData spawnData = new SpawnData(false /* forWarmUp */, context, commandLine,
- childProcessId, filesToBeMapped, launchCallback, childProcessCallback,
- inSandbox, alwaysInForeground, creationParams);
- allocatedConnection = allocateBoundConnection(spawnData, startCallback);
+ ChildSpawnData spawnData = new ChildSpawnData(context, commandLine, childProcessId,
+ filesToBeMapped, launchCallback, childProcessCallback, inSandbox,
+ alwaysInForeground, creationParams);
+ allocatedConnection =
+ allocateBoundConnection(spawnData, startCallback, false /* forWarmUp */);
if (allocatedConnection == null) {
return null;
}
@@ -798,22 +501,22 @@ public class ChildProcessLauncher {
static ChildProcessConnection allocateBoundConnectionForTesting(Context context,
ChildProcessCreationParams creationParams) {
return allocateBoundConnection(
- new SpawnData(false /* forWarmUp */, context, null /* commandLine */,
- 0 /* childProcessId */, null /* filesToBeMapped */,
- null /* LaunchCallback */, null /* childProcessCallback */,
- true /* inSandbox */, false /* alwaysInForeground */, creationParams),
- null /* startCallback */);
+ new ChildSpawnData(context, null /* commandLine */, 0 /* childProcessId */,
+ null /* filesToBeMapped */, null /* LaunchCallback */,
+ null /* childProcessCallback */, true /* inSandbox */,
+ false /* alwaysInForeground */, creationParams),
+ null /* startCallback */, false /* forWarmUp */);
}
@VisibleForTesting
static ChildProcessConnection allocateConnectionForTesting(
Context context, ChildProcessCreationParams creationParams) {
return allocateConnection(
- new SpawnData(false /* forWarmUp */, context, null /* commandLine */,
- 0 /* childProcessId */, null /* filesToBeMapped */,
- null /* launchCallback */, null /* childProcessCallback */,
- true /* inSandbox */, false /* alwaysInForeground */, creationParams),
- createCommonParamsBundle(creationParams));
+ new ChildSpawnData(context, null /* commandLine */, 0 /* childProcessId */,
+ null /* filesToBeMapped */, null /* launchCallback */,
+ null /* childProcessCallback */, true /* inSandbox */,
+ false /* alwaysInForeground */, creationParams),
+ createCommonParamsBundle(creationParams), false /* forWarmUp */);
}
/**
@@ -825,10 +528,10 @@ public class ChildProcessLauncher {
String packageName = creationParams != null ? creationParams.getPackageName()
: context.getPackageName();
ChildConnectionAllocator allocator =
- getAllocatorForTesting(context, packageName, inSandbox);
- allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp*/, context,
- commandLine, 1 /* childProcessId */, new FileDescriptorInfo[0],
- null /* launchCallback */, null /* childProcessCallback */, true /* inSandbox */,
+ ChildConnectionAllocator.getAllocator(context, packageName, inSandbox);
+ allocator.enqueuePendingQueueForTesting(new ChildSpawnData(context, commandLine,
+ 1 /* childProcessId */, new FileDescriptorInfo[0], null /* launchCallback */,
+ null /* childProcessCallback */, true /* inSandbox */,
false /* alwaysInForeground */, creationParams));
}
@@ -838,8 +541,7 @@ public class ChildProcessLauncher {
*/
@VisibleForTesting
static int allocatedSandboxedConnectionsCountForTesting(Context context, String packageName) {
- initConnectionAllocatorsIfNecessary(context, true, packageName);
- return sSandboxedChildConnectionAllocatorMap.get(packageName)
+ return ChildConnectionAllocator.getAllocator(context, packageName, true /*isSandboxed */)
.allocatedConnectionsCountForTesting();
}
@@ -847,8 +549,10 @@ public class ChildProcessLauncher {
* @return gets the service connection array for a specific package name.
*/
@VisibleForTesting
- static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(String packageName) {
- return sSandboxedChildConnectionAllocatorMap.get(packageName).connectionArrayForTesting();
+ static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(
+ Context context, String packageName) {
+ return ChildConnectionAllocator.getAllocator(context, packageName, true /*isSandboxed */)
+ .connectionArrayForTesting();
}
/** @return the count of services set up and working */
@@ -866,9 +570,8 @@ public class ChildProcessLauncher {
@VisibleForTesting
static int pendingSpawnsCountForTesting(
Context context, String packageName, boolean inSandbox) {
- ChildConnectionAllocator allocator =
- getAllocatorForTesting(context, packageName, inSandbox);
- return allocator.pendingSpawnsCountForTesting();
+ return ChildConnectionAllocator.getAllocator(context, packageName, inSandbox)
+ .pendingSpawnsCountForTesting();
}
/**

Powered by Google App Engine
This is Rietveld 408576698