| 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 be6e4f0bb7b919e5d27ef3dc3865ccc564ee0742..440978993fc28f09af0872d98ad3fc596de7a75c 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
|
| @@ -9,6 +9,7 @@ import android.content.Context;
|
| 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;
|
| @@ -20,8 +21,10 @@ 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.SandboxedProcessService;
|
| import org.chromium.content.common.ContentSwitches;
|
|
|
| +import java.util.HashMap;
|
| import java.util.Map;
|
| import java.util.concurrent.ConcurrentHashMap;
|
|
|
| @@ -35,6 +38,15 @@ import java.util.concurrent.ConcurrentHashMap;
|
| public class ChildProcessLauncher {
|
| private static final String TAG = "ChildProcLauncher";
|
|
|
| + private static final String NUM_SANDBOXED_SERVICES_KEY =
|
| + "org.chromium.content.browser.NUM_SANDBOXED_SERVICES";
|
| + private static final String SANDBOXED_SERVICES_NAME_KEY =
|
| + "org.chromium.content.browser.SANDBOXED_SERVICES_NAME";
|
| + private static final String NUM_PRIVILEGED_SERVICES_KEY =
|
| + "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES";
|
| + private static final String PRIVILEGED_SERVICES_NAME_KEY =
|
| + "org.chromium.content.browser.PRIVILEGED_SERVICES_NAME";
|
| +
|
| /**
|
| * Implemented by ChildProcessLauncherHelper.
|
| */
|
| @@ -44,6 +56,60 @@ public class ChildProcessLauncher {
|
|
|
| private static final boolean SPARE_CONNECTION_ALWAYS_IN_FOREGROUND = false;
|
|
|
| + // Map from package name to ChildConnectionAllocator.
|
| + private static final Map<String, ChildConnectionAllocator>
|
| + sSandboxedChildConnectionAllocatorMap = new HashMap<>();
|
| +
|
| + // Map from a connection to its ChildConnectionAllocator.
|
| + private static final Map<BaseChildProcessConnection, ChildConnectionAllocator>
|
| + sConnectionsToAllocatorMap = new HashMap<>();
|
| +
|
| + // Allocator used for non-sandboxed services.
|
| + private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator;
|
| +
|
| + // Used by test to override the default sandboxed service allocator settings.
|
| + private static int sSandboxedServicesCountForTesting = -1;
|
| + private static String sSandboxedServicesNameForTesting;
|
| +
|
| + @SuppressFBWarnings("LI_LAZY_INIT_STATIC") // Method is single thread.
|
| + public static ChildConnectionAllocator getConnectionAllocator(
|
| + Context context, String packageName, boolean sandboxed) {
|
| + assert LauncherThread.runningOnLauncherThread();
|
| + if (!sandboxed) {
|
| + if (sPrivilegedChildConnectionAllocator == null) {
|
| + sPrivilegedChildConnectionAllocator = ChildConnectionAllocator.create(context,
|
| + ImportantChildProcessConnection.FACTORY, packageName,
|
| + PRIVILEGED_SERVICES_NAME_KEY, NUM_PRIVILEGED_SERVICES_KEY);
|
| + }
|
| + return sPrivilegedChildConnectionAllocator;
|
| + }
|
| +
|
| + if (!sSandboxedChildConnectionAllocatorMap.containsKey(packageName)) {
|
| + Log.w(TAG,
|
| + "Create a new ChildConnectionAllocator with package name = %s,"
|
| + + " inSandbox = true",
|
| + packageName);
|
| + ChildConnectionAllocator connectionAllocator = null;
|
| + if (sSandboxedServicesCountForTesting != -1) {
|
| + // Testing case where allocator settings are overriden.
|
| + String serviceName = !TextUtils.isEmpty(sSandboxedServicesNameForTesting)
|
| + ? sSandboxedServicesNameForTesting
|
| + : SandboxedProcessService.class.getName();
|
| + connectionAllocator = ChildConnectionAllocator.createForTest(
|
| + ManagedChildProcessConnection.FACTORY, packageName, serviceName,
|
| + sSandboxedServicesCountForTesting);
|
| + } else {
|
| + connectionAllocator = ChildConnectionAllocator.create(context,
|
| + ManagedChildProcessConnection.FACTORY, packageName,
|
| + SANDBOXED_SERVICES_NAME_KEY, NUM_SANDBOXED_SERVICES_KEY);
|
| + }
|
| + sSandboxedChildConnectionAllocatorMap.put(packageName, connectionAllocator);
|
| + }
|
| + return sSandboxedChildConnectionAllocatorMap.get(packageName);
|
| + // TODO(pkotwicz|hanxi): Figure out when old allocators should be removed from
|
| + // {@code sSandboxedChildConnectionAllocatorMap}.
|
| + }
|
| +
|
| @VisibleForTesting
|
| static BaseChildProcessConnection allocateConnection(
|
| ChildSpawnData spawnData, Bundle childProcessCommonParams, boolean forWarmUp) {
|
| @@ -65,8 +131,12 @@ public class ChildProcessLauncher {
|
| final boolean inSandbox = spawnData.isInSandbox();
|
| String packageName =
|
| creationParams != null ? creationParams.getPackageName() : context.getPackageName();
|
| - return ChildConnectionAllocator.getAllocator(context, packageName, inSandbox)
|
| - .allocate(spawnData, deathCallback, childProcessCommonParams, !forWarmUp);
|
| + ChildConnectionAllocator allocator =
|
| + getConnectionAllocator(context, packageName, inSandbox);
|
| + BaseChildProcessConnection connection =
|
| + allocator.allocate(spawnData, deathCallback, childProcessCommonParams, !forWarmUp);
|
| + sConnectionsToAllocatorMap.put(connection, allocator);
|
| + return connection;
|
| }
|
|
|
| private static boolean sLinkerInitialized;
|
| @@ -125,8 +195,7 @@ public class ChildProcessLauncher {
|
| String packageName = creationParams != null ? creationParams.getPackageName()
|
| : context.getPackageName();
|
| if (inSandbox
|
| - && !ChildConnectionAllocator
|
| - .getAllocator(context, packageName, true /* sandboxed */)
|
| + && !getConnectionAllocator(context, packageName, true /* sandboxed */)
|
| .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
|
| @@ -152,14 +221,7 @@ public class ChildProcessLauncher {
|
| LauncherThread.postDelayed(new Runnable() {
|
| @Override
|
| public void run() {
|
| - // 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.isSandboxed());
|
| + ChildConnectionAllocator allocator = sConnectionsToAllocatorMap.remove(conn);
|
| assert allocator != null;
|
| final ChildSpawnData pendingSpawn = allocator.free(conn);
|
| if (pendingSpawn != null) {
|
| @@ -282,9 +344,10 @@ public class ChildProcessLauncher {
|
| LauncherThread.post(new Runnable() {
|
| @Override
|
| public void run() {
|
| - getBindingManager().startModerateBindingManagement(context,
|
| - ChildConnectionAllocator.getNumberOfServices(
|
| - context, true, context.getPackageName()));
|
| + ChildConnectionAllocator allocator = getConnectionAllocator(
|
| + context, context.getPackageName(), true /* sandboxed */);
|
| + getBindingManager().startModerateBindingManagement(
|
| + context, allocator.getNumberOfServices());
|
| }
|
| });
|
| }
|
| @@ -538,12 +601,27 @@ public class ChildProcessLauncher {
|
| freeConnection(connection);
|
| }
|
|
|
| + public static int getNumberOfSandboxedServices(Context context, String packageName) {
|
| + assert ThreadUtils.runningOnUiThread();
|
| + if (sSandboxedServicesCountForTesting != -1) {
|
| + return sSandboxedServicesCountForTesting;
|
| + }
|
| + return ChildConnectionAllocator.getNumberOfServices(
|
| + context, packageName, NUM_SANDBOXED_SERVICES_KEY);
|
| + }
|
| +
|
| /** @return the count of services set up and working */
|
| @VisibleForTesting
|
| static int connectedServicesCountForTesting() {
|
| return sServiceMap.size();
|
| }
|
|
|
| + @VisibleForTesting
|
| + public static void setSandboxServicesSettingsForTesting(int serviceCount, String serviceName) {
|
| + sSandboxedServicesCountForTesting = serviceCount;
|
| + sSandboxedServicesNameForTesting = serviceName;
|
| + }
|
| +
|
| /**
|
| * Kills the child process for testing.
|
| * @return true iff the process was killed as expected
|
|
|