| 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
|
| deleted file mode 100644
|
| index 01ec12adabab908e4692c261ccaf17558727783b..0000000000000000000000000000000000000000
|
| --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
|
| +++ /dev/null
|
| @@ -1,439 +0,0 @@
|
| -// Copyright 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package org.chromium.content.browser;
|
| -
|
| -import android.content.Context;
|
| -import android.util.Log;
|
| -import android.view.Surface;
|
| -
|
| -import com.google.common.annotations.VisibleForTesting;
|
| -
|
| -import org.chromium.base.CalledByNative;
|
| -import org.chromium.base.JNINamespace;
|
| -import org.chromium.base.ThreadUtils;
|
| -import org.chromium.content.app.ChildProcessService;
|
| -import org.chromium.content.app.Linker;
|
| -import org.chromium.content.app.LinkerParams;
|
| -import org.chromium.content.app.PrivilegedProcessService;
|
| -import org.chromium.content.app.SandboxedProcessService;
|
| -import org.chromium.content.common.IChildProcessCallback;
|
| -import org.chromium.content.common.IChildProcessService;
|
| -
|
| -import java.util.ArrayList;
|
| -import java.util.Map;
|
| -import java.util.concurrent.ConcurrentHashMap;
|
| -
|
| -/**
|
| - * This class provides the method to start/stop ChildProcess called by native.
|
| - */
|
| -@JNINamespace("content")
|
| -public class ChildProcessLauncher {
|
| - private static final String TAG = "ChildProcessLauncher";
|
| -
|
| - private static final int CALLBACK_FOR_UNKNOWN_PROCESS = 0;
|
| - private static final int CALLBACK_FOR_GPU_PROCESS = 1;
|
| - private static final int CALLBACK_FOR_RENDERER_PROCESS = 2;
|
| -
|
| - private static final String SWITCH_PROCESS_TYPE = "type";
|
| - private static final String SWITCH_PPAPI_BROKER_PROCESS = "ppapi-broker";
|
| - private static final String SWITCH_RENDERER_PROCESS = "renderer";
|
| - private static final String SWITCH_GPU_PROCESS = "gpu-process";
|
| -
|
| - // The upper limit on the number of simultaneous sandboxed and privileged child service process
|
| - // instances supported. Each limit must not exceed total number of SandboxedProcessServiceX
|
| - // classes and PrivilegedProcessServiceX classes declared in this package and defined as
|
| - // services in the embedding application's manifest file.
|
| - // (See {@link ChildProcessService} for more details on defining the services.)
|
| - /* package */ static final int MAX_REGISTERED_SANDBOXED_SERVICES = 13;
|
| - /* package */ static final int MAX_REGISTERED_PRIVILEGED_SERVICES = 3;
|
| -
|
| - 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. When looking for a free service, the first
|
| - // index in that list should be used. When a service is unbound, its index is added to the
|
| - // end of the list. This is so that we avoid immediately reusing the freed service (see
|
| - // http://crbug.com/164069): the framework might keep a service process alive when it's been
|
| - // unbound for a short time. If a new connection to the same service is bound at that point,
|
| - // the process is reused and bad things happen (mostly static variables are set when we
|
| - // don't expect them to).
|
| - // SHOULD BE ACCESSED WITH mConnectionLock.
|
| - private final ArrayList<Integer> mFreeConnectionIndices;
|
| - private final Object mConnectionLock = new Object();
|
| -
|
| - private Class<? extends ChildProcessService> mChildClass;
|
| - private final boolean mInSandbox;
|
| -
|
| - public ChildConnectionAllocator(boolean inSandbox) {
|
| - int numChildServices = inSandbox ?
|
| - MAX_REGISTERED_SANDBOXED_SERVICES : MAX_REGISTERED_PRIVILEGED_SERVICES;
|
| - mChildProcessConnections = new ChildProcessConnectionImpl[numChildServices];
|
| - mFreeConnectionIndices = new ArrayList<Integer>(numChildServices);
|
| - for (int i = 0; i < numChildServices; i++) {
|
| - mFreeConnectionIndices.add(i);
|
| - }
|
| - setServiceClass(inSandbox ?
|
| - SandboxedProcessService.class : PrivilegedProcessService.class);
|
| - mInSandbox = inSandbox;
|
| - }
|
| -
|
| - public void setServiceClass(Class<? extends ChildProcessService> childClass) {
|
| - mChildClass = childClass;
|
| - }
|
| -
|
| - public ChildProcessConnection allocate(
|
| - Context context, ChildProcessConnection.DeathCallback deathCallback,
|
| - LinkerParams linkerParams) {
|
| - synchronized (mConnectionLock) {
|
| - if (mFreeConnectionIndices.isEmpty()) {
|
| - Log.w(TAG, "Ran out of service.");
|
| - return null;
|
| - }
|
| - int slot = mFreeConnectionIndices.remove(0);
|
| - assert mChildProcessConnections[slot] == null;
|
| - mChildProcessConnections[slot] = new ChildProcessConnectionImpl(context, slot,
|
| - mInSandbox, deathCallback, mChildClass, linkerParams);
|
| - return mChildProcessConnections[slot];
|
| - }
|
| - }
|
| -
|
| - public void 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: " + slot +
|
| - " already occupied by service: " + occupier);
|
| - assert false;
|
| - } else {
|
| - mChildProcessConnections[slot] = null;
|
| - assert !mFreeConnectionIndices.contains(slot);
|
| - mFreeConnectionIndices.add(slot);
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Service class for child process. As the default value it uses SandboxedProcessService0 and
|
| - // PrivilegedProcessService0.
|
| - private static final ChildConnectionAllocator sSandboxedChildConnectionAllocator =
|
| - new ChildConnectionAllocator(true);
|
| - private static final ChildConnectionAllocator sPrivilegedChildConnectionAllocator =
|
| - new ChildConnectionAllocator(false);
|
| -
|
| - private static boolean sConnectionAllocated = false;
|
| -
|
| - /**
|
| - * Sets service class for sandboxed service and privileged service.
|
| - */
|
| - public static void setChildProcessClass(
|
| - Class<? extends SandboxedProcessService> sandboxedServiceClass,
|
| - Class<? extends PrivilegedProcessService> privilegedServiceClass) {
|
| - // We should guarantee this is called before allocating connection.
|
| - assert !sConnectionAllocated;
|
| - sSandboxedChildConnectionAllocator.setServiceClass(sandboxedServiceClass);
|
| - sPrivilegedChildConnectionAllocator.setServiceClass(privilegedServiceClass);
|
| - }
|
| -
|
| - private static ChildConnectionAllocator getConnectionAllocator(boolean inSandbox) {
|
| - return inSandbox ?
|
| - sSandboxedChildConnectionAllocator : sPrivilegedChildConnectionAllocator;
|
| - }
|
| -
|
| - private static ChildProcessConnection allocateConnection(Context context,
|
| - boolean inSandbox, LinkerParams linkerParams) {
|
| - ChildProcessConnection.DeathCallback deathCallback =
|
| - new ChildProcessConnection.DeathCallback() {
|
| - @Override
|
| - public void onChildProcessDied(int pid) {
|
| - stop(pid);
|
| - }
|
| - };
|
| - sConnectionAllocated = true;
|
| - return getConnectionAllocator(inSandbox).allocate(context, deathCallback, linkerParams);
|
| - }
|
| -
|
| - private static boolean sLinkerInitialized = false;
|
| - private static long sLinkerLoadAddress = 0;
|
| -
|
| - private static LinkerParams getLinkerParamsForNewConnection() {
|
| - if (!sLinkerInitialized) {
|
| - if (Linker.isUsed()) {
|
| - sLinkerLoadAddress = Linker.getBaseLoadAddress();
|
| - if (sLinkerLoadAddress == 0) {
|
| - Log.i(TAG, "Shared RELRO support disabled!");
|
| - }
|
| - }
|
| - sLinkerInitialized = true;
|
| - }
|
| -
|
| - if (sLinkerLoadAddress == 0)
|
| - return null;
|
| -
|
| - // Always wait for the shared RELROs in service processes.
|
| - final boolean waitForSharedRelros = true;
|
| - return new LinkerParams(sLinkerLoadAddress,
|
| - waitForSharedRelros,
|
| - Linker.getTestRunnerClassName());
|
| - }
|
| -
|
| - private static ChildProcessConnection allocateBoundConnection(Context context,
|
| - String[] commandLine, boolean inSandbox) {
|
| - LinkerParams linkerParams = getLinkerParamsForNewConnection();
|
| - ChildProcessConnection connection = allocateConnection(context, inSandbox, linkerParams);
|
| - if (connection != null) {
|
| - connection.start(commandLine);
|
| - }
|
| - return connection;
|
| - }
|
| -
|
| - private static void freeConnection(ChildProcessConnection connection) {
|
| - if (connection == null) {
|
| - return;
|
| - }
|
| - getConnectionAllocator(connection.isInSandbox()).free(connection);
|
| - return;
|
| - }
|
| -
|
| - // Represents an invalid process handle; same as base/process/process.h kNullProcessHandle.
|
| - private static final int NULL_PROCESS_HANDLE = 0;
|
| -
|
| - // Map from pid to ChildService connection.
|
| - private static Map<Integer, ChildProcessConnection> sServiceMap =
|
| - new ConcurrentHashMap<Integer, ChildProcessConnection>();
|
| -
|
| - // A pre-allocated and pre-bound connection ready for connection setup, or null.
|
| - private static ChildProcessConnection sSpareSandboxedConnection = null;
|
| -
|
| - // Manages oom bindings used to bind chind services.
|
| - private static BindingManager sBindingManager = BindingManagerImpl.createBindingManager();
|
| -
|
| - static BindingManager getBindingManager() {
|
| - return sBindingManager;
|
| - }
|
| -
|
| - @VisibleForTesting
|
| - public static void setBindingManagerForTesting(BindingManager manager) {
|
| - sBindingManager = manager;
|
| - }
|
| -
|
| - @CalledByNative
|
| - private static boolean isOomProtected(int pid) {
|
| - return sBindingManager.isOomProtected(pid);
|
| - }
|
| -
|
| - /**
|
| - * Called when the embedding application is sent to background.
|
| - */
|
| - public static void onSentToBackground() {
|
| - sBindingManager.onSentToBackground();
|
| - }
|
| -
|
| - /**
|
| - * Called when the embedding application is brought to foreground.
|
| - */
|
| - public static void onBroughtToForeground() {
|
| - sBindingManager.onBroughtToForeground();
|
| - }
|
| -
|
| - /**
|
| - * Returns the child process service interface for the given pid. This may be called on
|
| - * any thread, but the caller must assume that the service can disconnect at any time. All
|
| - * service calls should catch and handle android.os.RemoteException.
|
| - *
|
| - * @param pid The pid (process handle) of the service obtained from {@link #start}.
|
| - * @return The IChildProcessService or null if the service no longer exists.
|
| - */
|
| - public static IChildProcessService getChildService(int pid) {
|
| - ChildProcessConnection connection = sServiceMap.get(pid);
|
| - if (connection != null) {
|
| - return connection.getService();
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Should be called early in startup so the work needed to spawn the child process can be done
|
| - * in parallel to other startup work. Must not be called on the UI thread. Spare connection is
|
| - * created in sandboxed child process.
|
| - * @param context the application context used for the connection.
|
| - */
|
| - public static void warmUp(Context context) {
|
| - synchronized (ChildProcessLauncher.class) {
|
| - assert !ThreadUtils.runningOnUiThread();
|
| - if (sSpareSandboxedConnection == null) {
|
| - sSpareSandboxedConnection = allocateBoundConnection(context, null, true);
|
| - }
|
| - }
|
| - }
|
| -
|
| - private static String getSwitchValue(final String[] commandLine, String switchKey) {
|
| - if (commandLine == null || switchKey == null) {
|
| - return null;
|
| - }
|
| - // This format should be matched with the one defined in command_line.h.
|
| - final String switchKeyPrefix = "--" + switchKey + "=";
|
| - for (String command : commandLine) {
|
| - if (command != null && command.startsWith(switchKeyPrefix)) {
|
| - return command.substring(switchKeyPrefix.length());
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Spawns and connects to a child process. May be called on any thread. It will not block, but
|
| - * will instead callback to {@link #nativeOnChildProcessStarted} when the connection is
|
| - * established. Note this callback will not necessarily be from the same thread (currently it
|
| - * always comes from the main thread).
|
| - *
|
| - * @param context Context used to obtain the application context.
|
| - * @param commandLine The child process command line argv.
|
| - * @param fileIds The ID that should be used when mapping files in the created process.
|
| - * @param fileFds The file descriptors that should be mapped in the created process.
|
| - * @param fileAutoClose Whether the file descriptors should be closed once they were passed to
|
| - * the created process.
|
| - * @param clientContext Arbitrary parameter used by the client to distinguish this connection.
|
| - */
|
| - @CalledByNative
|
| - static void start(
|
| - Context context,
|
| - final String[] commandLine,
|
| - int[] fileIds,
|
| - int[] fileFds,
|
| - boolean[] fileAutoClose,
|
| - final long clientContext) {
|
| - assert fileIds.length == fileFds.length && fileFds.length == fileAutoClose.length;
|
| - FileDescriptorInfo[] filesToBeMapped = new FileDescriptorInfo[fileFds.length];
|
| - for (int i = 0; i < fileFds.length; i++) {
|
| - filesToBeMapped[i] =
|
| - new FileDescriptorInfo(fileIds[i], fileFds[i], fileAutoClose[i]);
|
| - }
|
| - assert clientContext != 0;
|
| -
|
| - int callbackType = CALLBACK_FOR_UNKNOWN_PROCESS;
|
| - boolean inSandbox = true;
|
| - String processType = getSwitchValue(commandLine, SWITCH_PROCESS_TYPE);
|
| - if (SWITCH_RENDERER_PROCESS.equals(processType)) {
|
| - callbackType = CALLBACK_FOR_RENDERER_PROCESS;
|
| - } else if (SWITCH_GPU_PROCESS.equals(processType)) {
|
| - callbackType = CALLBACK_FOR_GPU_PROCESS;
|
| - } else if (SWITCH_PPAPI_BROKER_PROCESS.equals(processType)) {
|
| - inSandbox = false;
|
| - }
|
| -
|
| - ChildProcessConnection allocatedConnection = null;
|
| - synchronized (ChildProcessLauncher.class) {
|
| - if (inSandbox) {
|
| - allocatedConnection = sSpareSandboxedConnection;
|
| - sSpareSandboxedConnection = null;
|
| - }
|
| - }
|
| - if (allocatedConnection == null) {
|
| - allocatedConnection = allocateBoundConnection(context, commandLine, inSandbox);
|
| - if (allocatedConnection == null) {
|
| - // Notify the native code so it can free the heap allocated callback.
|
| - nativeOnChildProcessStarted(clientContext, 0);
|
| - return;
|
| - }
|
| - }
|
| - final ChildProcessConnection connection = allocatedConnection;
|
| - Log.d(TAG, "Setting up connection to process: slot=" + connection.getServiceNumber());
|
| -
|
| - ChildProcessConnection.ConnectionCallback connectionCallback =
|
| - new ChildProcessConnection.ConnectionCallback() {
|
| - @Override
|
| - public void onConnected(int pid) {
|
| - Log.d(TAG, "on connect callback, pid=" + pid + " context=" + clientContext);
|
| - if (pid != NULL_PROCESS_HANDLE) {
|
| - sBindingManager.addNewConnection(pid, connection);
|
| - sServiceMap.put(pid, connection);
|
| - } else {
|
| - freeConnection(connection);
|
| - }
|
| - nativeOnChildProcessStarted(clientContext, pid);
|
| - }
|
| - };
|
| -
|
| - // TODO(sievers): Revisit this as it doesn't correctly handle the utility process
|
| - // assert callbackType != CALLBACK_FOR_UNKNOWN_PROCESS;
|
| -
|
| - connection.setupConnection(commandLine,
|
| - filesToBeMapped,
|
| - createCallback(callbackType),
|
| - connectionCallback,
|
| - Linker.getSharedRelros());
|
| - }
|
| -
|
| - /**
|
| - * Terminates a child process. This may be called from any thread.
|
| - *
|
| - * @param pid The pid (process handle) of the service connection obtained from {@link #start}.
|
| - */
|
| - @CalledByNative
|
| - static void stop(int pid) {
|
| - Log.d(TAG, "stopping child connection: pid=" + pid);
|
| - ChildProcessConnection connection = sServiceMap.remove(pid);
|
| - if (connection == null) {
|
| - logPidWarning(pid, "Tried to stop non-existent connection");
|
| - return;
|
| - }
|
| - sBindingManager.clearConnection(pid);
|
| - connection.stop();
|
| - freeConnection(connection);
|
| - }
|
| -
|
| - /**
|
| - * This implementation is used to receive callbacks from the remote service.
|
| - */
|
| - private static IChildProcessCallback createCallback(final int callbackType) {
|
| - return new IChildProcessCallback.Stub() {
|
| - /**
|
| - * This is called by the remote service regularly to tell us about new values. Note that
|
| - * IPC calls are dispatched through a thread pool running in each process, so the code
|
| - * executing here will NOT be running in our main thread -- so, to update the UI, we
|
| - * need to use a Handler.
|
| - */
|
| - @Override
|
| - public void establishSurfacePeer(
|
| - int pid, Surface surface, int primaryID, int secondaryID) {
|
| - // Do not allow a malicious renderer to connect to a producer. This is only used
|
| - // from stream textures managed by the GPU process.
|
| - if (callbackType != CALLBACK_FOR_GPU_PROCESS) {
|
| - Log.e(TAG, "Illegal callback for non-GPU process.");
|
| - return;
|
| - }
|
| -
|
| - nativeEstablishSurfacePeer(pid, surface, primaryID, secondaryID);
|
| - }
|
| -
|
| - @Override
|
| - public Surface getViewSurface(int surfaceId) {
|
| - // Do not allow a malicious renderer to get to our view surface.
|
| - if (callbackType != CALLBACK_FOR_GPU_PROCESS) {
|
| - Log.e(TAG, "Illegal callback for non-GPU process.");
|
| - return null;
|
| - }
|
| -
|
| - return nativeGetViewSurface(surfaceId);
|
| - }
|
| - };
|
| - }
|
| -
|
| - static void logPidWarning(int pid, String message) {
|
| - // This class is effectively a no-op in single process mode, so don't log warnings there.
|
| - if (pid > 0 && !nativeIsSingleProcess()) {
|
| - Log.w(TAG, message + ", pid=" + pid);
|
| - }
|
| - }
|
| -
|
| - private static native void nativeOnChildProcessStarted(long clientContext, int pid);
|
| - private static native Surface nativeGetViewSurface(int surfaceId);
|
| - private static native void nativeEstablishSurfacePeer(
|
| - int pid, Surface surface, int primaryID, int secondaryID);
|
| - private static native boolean nativeIsSingleProcess();
|
| -}
|
|
|