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

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

Issue 10541110: Added sandboxed process launcher (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed ProcessID and Sync Created 8 years, 6 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/org/chromium/content/browser/SandboxedProcessLauncher.java
diff --git a/content/public/android/java/org/chromium/content/browser/SandboxedProcessLauncher.java b/content/public/android/java/org/chromium/content/browser/SandboxedProcessLauncher.java
new file mode 100644
index 0000000000000000000000000000000000000000..4dd9f1f40e416643f65995f253f007f29d5ab327
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/SandboxedProcessLauncher.java
@@ -0,0 +1,305 @@
+// Copyright (c) 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.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.content.browser.CommandLine;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+
+/**
+ * This class provides the method to start/stop SandboxedProcess called by
+ * native.
+ */
+public class SandboxedProcessLauncher {
+ private static String TAG = "SandboxedProcessLauncher";
+
+ // The upper limit on the number of simultaneous service process instances supported.
+ // This must not exceed total number of SandboxedProcessServiceX classes declared in
+ // this package, and defined as services in the embedding application's manifest file.
+ // (See {@link SandboxedProcessService} for more details on defining the services.)
+ /* package */ static final int MAX_REGISTERED_SERVICES = 5;
+ private static final SandboxedProcessConnection[] mConnections =
+ new SandboxedProcessConnection[MAX_REGISTERED_SERVICES];
+
+ private static int sNumRegisteredServices = -1;
+
+ private static int getNumRegisteredServices() {
+ if (sNumRegisteredServices < 0) {
+ String s =
+ CommandLine.getInstance().getSwitchValue(CommandLine.SANDBOXED_SERVICE_LIMIT);
+ sNumRegisteredServices = MAX_REGISTERED_SERVICES;
+ if (s != null) {
+ try {
+ sNumRegisteredServices = Integer.parseInt(s);
+ } catch (java.lang.NumberFormatException e) {
+ // pass
+ }
+ }
+ }
+ return sNumRegisteredServices;
+ }
+
+ private static SandboxedProcessConnection allocateConnection(Context context) {
+ SandboxedProcessConnection.DeathCallback deathCallback =
+ new SandboxedProcessConnection.DeathCallback() {
+ @Override
+ public void onSandboxedProcessDied(int pid) {
+ stop(pid);
+ }
+ };
+ synchronized (mConnections) {
+ for (int i = 0; i < getNumRegisteredServices(); ++i) {
+ if (mConnections[i] == null) {
+ mConnections[i] = new SandboxedProcessConnection(context, i, deathCallback);
+ return mConnections[i];
+ }
+ }
+ }
+ Log.w(TAG, "Ran out of sandboxed services.");
+ return null;
+ }
+
+ private static SandboxedProcessConnection allocateBoundConnection(Context context,
+ String[] commandLine) {
+ SandboxedProcessConnection connection = allocateConnection(context);
+ if (connection != null) {
+ connection.bind(commandLine);
+ }
+ return connection;
+ }
+
+ private static void freeConnection(SandboxedProcessConnection connection) {
+ if (connection == null) {
+ return;
+ }
+ int slot = connection.getServiceNumber();
+ synchronized (mConnections) {
+ if (mConnections[slot] != connection) {
+ int occupier = mConnections[slot] == null ?
+ -1 : mConnections[slot].getServiceNumber();
+ Log.e(TAG, "Unable to find connection to free in slot: " + slot +
+ " already occupied by service: " + occupier);
+ assert false;
+ } else {
+ mConnections[slot] = null;
+ }
+ }
+ }
+
+ public static int getNumberOfConnections() {
+ int result = 0;
+ synchronized (mConnections) {
+ for (int i = 0; i < getNumRegisteredServices(); ++i) {
+ if (mConnections[i] != null)
+ ++result;
+ }
+ }
+ return result;
+ }
+
+ // Represents an invalid process handle; same as base/process.h kNullProcessHandle.
+ private static final int NULL_PROCESS_HANDLE = 0;
+
+ // Map from pid to SandboxedService connection.
+ private static Map<Integer, SandboxedProcessConnection> mServiceMap =
+ new ConcurrentHashMap<Integer, SandboxedProcessConnection>();
+
+ // A pre-allocated and pre-bound connection ready for connection setup, or null.
+ static SandboxedProcessConnection mSpareConnection = null;
+
+ /**
+ * Returns the sandboxed 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 ISandboxedProcessService or null if the service no longer exists.
+ */
+ public static ISandboxedProcessService getSandboxedService(int pid) {
+ SandboxedProcessConnection connection = mServiceMap.get(pid);
+ if (connection != null) {
+ return connection.getService();
+ }
+ return null;
+ }
+
+ /**
+ * Should be called early in startup so the work needed to spawn the sandboxed process can
+ * be done in parallel to other startup work.
+ * @param context the application context used for the connection.
+ */
+ public static synchronized void warmUp(Context context) {
+ if (mSpareConnection == null) {
+ mSpareConnection = allocateBoundConnection(context, null);
+ }
+ }
+
+ /**
+ * Spawns and connects to a sandboxed process. May be called on any thread. It will not
+ * block, but will instead callback to {@link #nativeOnSandboxedProcessStarted} 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 sandboxed process command line argv.
+ * @param ipcFd File descriptor used to set up IPC.
+ * @param clientContext Arbitrary parameter used by the client to distinguish this connection.
+ * @return Connection object which maybe used with subsequent call to {@link #cancelStart}
+ */
+ @CalledByNative
+ static SandboxedProcessConnection start(
+ Context context,
+ final String[] commandLine,
+ int ipcFd,
+ int crashFd,
+ final int clientContext) {
+ assert clientContext != 0;
+ SandboxedProcessConnection allocatedConnection;
+ synchronized (SandboxedProcessLauncher.class) {
+ allocatedConnection = mSpareConnection;
+ mSpareConnection = null;
+ }
+ if (allocatedConnection == null) {
+ allocatedConnection = allocateBoundConnection(context, commandLine);
+ if (allocatedConnection == null) {
+ return null;
+ }
+ }
+ final SandboxedProcessConnection connection = allocatedConnection;
+ Log.d(TAG, "Setting up connection to process: slot=" + connection.getServiceNumber());
+ // Note: This runnable will be executed when the sandboxed connection is setup.
+ final Runnable onConnect = new Runnable() {
+ @Override
+ public void run() {
+ final int pid = connection.getPid();
+ Log.d(TAG, "on connect callback, pid=" + pid + " context=" + clientContext);
+ if (pid != NULL_PROCESS_HANDLE) {
+ mServiceMap.put(pid, connection);
+ } else {
+ freeConnection(connection);
+ }
+ nativeOnSandboxedProcessStarted(clientContext, pid);
+ }
+ };
+ connection.setupConnection(commandLine, ipcFd, crashFd, createCallback(), onConnect);
+ return connection;
+ }
+
+ /**
+ * Cancels a pending connection to a sandboxed process. This may be called from any thread.
+ *
+ * @param connection the object that was returned from the corresponding call to {@link #start}.
+ */
+ @CalledByNative
+ static void cancelStart(SandboxedProcessConnection connection) {
+ assert connection != null;
+ assert !mServiceMap.containsValue(connection);
+ connection.unbind();
+ freeConnection(connection);
+ }
+
+ /**
+ * Terminates a sandboxed 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 sandboxed connection: pid=" + pid);
+
+ SandboxedProcessConnection connection = mServiceMap.remove(pid);
+ if (connection == null) {
+ Log.w(TAG, "Tried to stop non-existent connection to pid: " + pid);
+ return;
+ }
+ connection.unbind();
+ freeConnection(connection);
+ }
+
+ /**
+ * Bind a sandboxed process as a high priority process so that it has the same
+ * priority as the main process. This can be used for the foreground renderer
+ * process to distinguish it from the the background renderer process.
+ *
+ * @param pid The process handle of the service connection obtained from {@link #start}.
+ */
+ static void bindAsHighPriority(int pid) {
+ SandboxedProcessConnection connection = mServiceMap.get(pid);
+ if (connection == null) {
+ Log.w(TAG, "Tried to bind a non-existent connection to pid: " + pid);
+ return;
+ }
+ connection.bindHighPriority();
+ }
+
+ /**
+ * Unbind a high priority process which is bound by {@link #bindAsHighPriority}.
+ *
+ * @param pid The process handle of the service obtained from {@link #start}.
+ */
+ static void unbindAsHighPriority(int pid) {
+ SandboxedProcessConnection connection = mServiceMap.get(pid);
+ if (connection == null) {
+ Log.w(TAG, "Tried to unbind non-existent connection to pid: " + pid);
+ return;
+ }
+ connection.unbindHighPriority(false);
+ }
+
+ static void establishSurfacePeer(
+ int pid, int type, Surface surface, int primaryID, int secondaryID) {
+ Log.d(TAG, "establishSurfaceTexturePeer: pid = " + pid + ", " +
+ "type = " + type + ", " +
+ "primaryID = " + primaryID + ", " +
+ "secondaryID = " + secondaryID);
+ ISandboxedProcessService service = SandboxedProcessLauncher.getSandboxedService(pid);
+ if (service == null) {
+ Log.e(TAG, "Unable to get SandboxedProcessService from pid.");
+ return;
+ }
+ try {
+ service.setSurface(type, surface, primaryID, secondaryID);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to call setSurface: " + e);
+ }
+ }
+
+ /**
+ * This implementation is used to receive callbacks from the remote service.
+ */
+ private static ISandboxedProcessCallback createCallback() {
+ return new ISandboxedProcessCallback.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.
+ */
+ public void establishSurfacePeer(
+ int pid, int type, Surface surface, int primaryID, int secondaryID) {
+ SandboxedProcessLauncher.establishSurfacePeer(pid, type, surface,
+ primaryID, secondaryID);
+ // The SandboxProcessService now holds a reference to the
+ // Surface's resources, so we release our reference to it now to
+ // avoid waiting for the finalizer to get around to it.
+ if (surface != null) {
+ surface.release();
+ }
+ }
+ };
+ };
+
+ private static native void nativeOnSandboxedProcessStarted(int clientContext, int pid);
+}

Powered by Google App Engine
This is Rietveld 408576698