| 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();
 | 
|      }
 | 
|  
 | 
|      /**
 | 
| 
 |