| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
| 6 | 6 |
| 7 import android.content.ComponentName; | 7 import android.content.ComponentName; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.ServiceConnection; | 10 import android.content.ServiceConnection; |
| 11 import android.os.AsyncTask; | 11 import android.os.AsyncTask; |
| 12 import android.os.Bundle; | 12 import android.os.Bundle; |
| 13 import android.os.Handler; | 13 import android.os.Handler; |
| 14 import android.os.IBinder; | 14 import android.os.IBinder; |
| 15 import android.os.Looper; | 15 import android.os.Looper; |
| 16 import android.os.ParcelFileDescriptor; | 16 import android.os.ParcelFileDescriptor; |
| 17 import android.util.Log; | 17 import android.util.Log; |
| 18 | 18 |
| 19 import java.io.IOException; | 19 import java.io.IOException; |
| 20 import java.util.concurrent.atomic.AtomicBoolean; | 20 import java.util.concurrent.atomic.AtomicBoolean; |
| 21 | 21 |
| 22 import org.chromium.base.CalledByNative; | 22 import org.chromium.base.CalledByNative; |
| 23 import org.chromium.base.CpuFeatures; | 23 import org.chromium.base.CpuFeatures; |
| 24 import org.chromium.base.ThreadUtils; | 24 import org.chromium.base.ThreadUtils; |
| 25 import org.chromium.content.common.CommandLine; | 25 import org.chromium.content.common.CommandLine; |
| 26 import org.chromium.content.common.ISandboxedProcessCallback; | 26 import org.chromium.content.common.IChildProcessCallback; |
| 27 import org.chromium.content.common.ISandboxedProcessService; | 27 import org.chromium.content.common.IChildProcessService; |
| 28 import org.chromium.content.common.TraceEvent; | 28 import org.chromium.content.common.TraceEvent; |
| 29 | 29 |
| 30 public class SandboxedProcessConnection implements ServiceConnection { | 30 public class ChildProcessConnection implements ServiceConnection { |
| 31 interface DeathCallback { | 31 interface DeathCallback { |
| 32 void onSandboxedProcessDied(int pid); | 32 void onChildProcessDied(int pid); |
| 33 } | 33 } |
| 34 | 34 |
| 35 // Names of items placed in the bind intent or connection bundle. | 35 // Names of items placed in the bind intent or connection bundle. |
| 36 public static final String EXTRA_COMMAND_LINE = | 36 public static final String EXTRA_COMMAND_LINE = |
| 37 "com.google.android.apps.chrome.extra.sandbox_command_line"; | 37 "com.google.android.apps.chrome.extra.command_line"; |
| 38 public static final String EXTRA_NATIVE_LIBRARY_NAME = | 38 public static final String EXTRA_NATIVE_LIBRARY_NAME = |
| 39 "com.google.android.apps.chrome.extra.sandbox_native_library_name"; | 39 "com.google.android.apps.chrome.extra.native_library_name"; |
| 40 // Note the FDs may only be passed in the connection bundle. | 40 // Note the FDs may only be passed in the connection bundle. |
| 41 public static final String EXTRA_FILES_PREFIX = | 41 public static final String EXTRA_FILES_PREFIX = |
| 42 "com.google.android.apps.chrome.extra.sandbox_extraFile_"; | 42 "com.google.android.apps.chrome.extra.extraFile_"; |
| 43 public static final String EXTRA_FILES_ID_SUFFIX = "_id"; | 43 public static final String EXTRA_FILES_ID_SUFFIX = "_id"; |
| 44 public static final String EXTRA_FILES_FD_SUFFIX = "_fd"; | 44 public static final String EXTRA_FILES_FD_SUFFIX = "_fd"; |
| 45 | 45 |
| 46 // Used to pass the CPU core count to sandboxed processes. | 46 // Used to pass the CPU core count to child processes. |
| 47 public static final String EXTRA_CPU_COUNT = | 47 public static final String EXTRA_CPU_COUNT = |
| 48 "com.google.android.apps.chrome.extra.cpu_count"; | 48 "com.google.android.apps.chrome.extra.cpu_count"; |
| 49 // Used to pass the CPU features mask to sandboxed processes. | 49 // Used to pass the CPU features mask to child processes. |
| 50 public static final String EXTRA_CPU_FEATURES = | 50 public static final String EXTRA_CPU_FEATURES = |
| 51 "com.google.android.apps.chrome.extra.cpu_features"; | 51 "com.google.android.apps.chrome.extra.cpu_features"; |
| 52 | 52 |
| 53 private final Context mContext; | 53 private final Context mContext; |
| 54 private final int mServiceNumber; | 54 private final int mServiceNumber; |
| 55 private final SandboxedProcessConnection.DeathCallback mDeathCallback; | 55 private final ChildProcessConnection.DeathCallback mDeathCallback; |
| 56 | 56 |
| 57 // Synchronization: While most internal flow occurs on the UI thread, the pu
blic API | 57 // Synchronization: While most internal flow occurs on the UI thread, the pu
blic API |
| 58 // (specifically bind and unbind) may be called from any thread, hence all e
ntry point methods | 58 // (specifically bind and unbind) may be called from any thread, hence all e
ntry point methods |
| 59 // into the class are synchronized on the SandboxedProcessConnection instanc
e to protect access | 59 // into the class are synchronized on the ChildProcessConnection instance to
protect access |
| 60 // to these members. But see also the TODO where AsyncBoundServiceConnection
is created. | 60 // to these members. But see also the TODO where AsyncBoundServiceConnection
is created. |
| 61 private ISandboxedProcessService mService = null; | 61 private IChildProcessService mService = null; |
| 62 private boolean mServiceConnectComplete = false; | 62 private boolean mServiceConnectComplete = false; |
| 63 private int mPID = 0; // Process ID of the corresponding sandboxed process. | 63 private int mPID = 0; // Process ID of the corresponding child process. |
| 64 private HighPriorityConnection mHighPriorityConnection = null; | 64 private HighPriorityConnection mHighPriorityConnection = null; |
| 65 private int mHighPriorityConnectionCount = 0; | 65 private int mHighPriorityConnectionCount = 0; |
| 66 | 66 |
| 67 private static final String TAG = "SandboxedProcessConnection"; | 67 private static final String TAG = "ChildProcessConnection"; |
| 68 | 68 |
| 69 private static class ConnectionParams { | 69 private static class ConnectionParams { |
| 70 final String[] mCommandLine; | 70 final String[] mCommandLine; |
| 71 final FileDescriptorInfo[] mFilesToBeMapped; | 71 final FileDescriptorInfo[] mFilesToBeMapped; |
| 72 final ISandboxedProcessCallback mCallback; | 72 final IChildProcessCallback mCallback; |
| 73 final Runnable mOnConnectionCallback; | 73 final Runnable mOnConnectionCallback; |
| 74 | 74 |
| 75 ConnectionParams( | 75 ConnectionParams( |
| 76 String[] commandLine, | 76 String[] commandLine, |
| 77 FileDescriptorInfo[] filesToBeMapped, | 77 FileDescriptorInfo[] filesToBeMapped, |
| 78 ISandboxedProcessCallback callback, | 78 IChildProcessCallback callback, |
| 79 Runnable onConnectionCallback) { | 79 Runnable onConnectionCallback) { |
| 80 mCommandLine = commandLine; | 80 mCommandLine = commandLine; |
| 81 mFilesToBeMapped = filesToBeMapped; | 81 mFilesToBeMapped = filesToBeMapped; |
| 82 mCallback = callback; | 82 mCallback = callback; |
| 83 mOnConnectionCallback = onConnectionCallback; | 83 mOnConnectionCallback = onConnectionCallback; |
| 84 } | 84 } |
| 85 } | 85 } |
| 86 | 86 |
| 87 // This is only valid while the connection is being established. | 87 // This is only valid while the connection is being established. |
| 88 private ConnectionParams mConnectionParams; | 88 private ConnectionParams mConnectionParams; |
| 89 private boolean mIsBound; | 89 private boolean mIsBound; |
| 90 | 90 |
| 91 SandboxedProcessConnection(Context context, int number, | 91 ChildProcessConnection(Context context, int number, |
| 92 SandboxedProcessConnection.DeathCallback deathCallback) { | 92 ChildProcessConnection.DeathCallback deathCallback) { |
| 93 mContext = context; | 93 mContext = context; |
| 94 mServiceNumber = number; | 94 mServiceNumber = number; |
| 95 mDeathCallback = deathCallback; | 95 mDeathCallback = deathCallback; |
| 96 } | 96 } |
| 97 | 97 |
| 98 int getServiceNumber() { | 98 int getServiceNumber() { |
| 99 return mServiceNumber; | 99 return mServiceNumber; |
| 100 } | 100 } |
| 101 | 101 |
| 102 synchronized ISandboxedProcessService getService() { | 102 synchronized IChildProcessService getService() { |
| 103 return mService; | 103 return mService; |
| 104 } | 104 } |
| 105 | 105 |
| 106 private Intent createServiceBindIntent() { | 106 private Intent createServiceBindIntent() { |
| 107 Intent intent = new Intent(); | 107 Intent intent = new Intent(); |
| 108 String n = org.chromium.content.app.SandboxedProcessService.class.getNam
e(); | 108 String n = org.chromium.content.app.SandboxedProcessService0.class.getNa
me() |
| 109 .replaceAll("[0-9]*$", ""); |
| 109 intent.setClassName(mContext, n + mServiceNumber); | 110 intent.setClassName(mContext, n + mServiceNumber); |
| 110 intent.setPackage(mContext.getPackageName()); | 111 intent.setPackage(mContext.getPackageName()); |
| 111 return intent; | 112 return intent; |
| 112 } | 113 } |
| 113 | 114 |
| 114 /** | 115 /** |
| 115 * Bind to an ISandboxedProcessService. This must be followed by a call to s
etupConnection() | 116 * Bind to an IChildProcessService. This must be followed by a call to setup
Connection() |
| 116 * to setup the connection parameters. (These methods are separated to allow
the client | 117 * to setup the connection parameters. (These methods are separated to allow
the client |
| 117 * to pass whatever parameters they have available here, and complete the re
mainder | 118 * to pass whatever parameters they have available here, and complete the re
mainder |
| 118 * later while reducing the connection setup latency). | 119 * later while reducing the connection setup latency). |
| 119 * @param nativeLibraryName The name of the shared native library to be load
ed for the | 120 * @param nativeLibraryName The name of the shared native library to be load
ed for the |
| 120 * sandboxed process. | 121 * child process. |
| 121 * @param commandLine (Optional) Command line for the sandboxed process. If
omitted, then | 122 * @param commandLine (Optional) Command line for the child process. If omit
ted, then |
| 122 * the command line parameters must instead be passed to
setupConnection(). | 123 * the command line parameters must instead be passed to
setupConnection(). |
| 123 */ | 124 */ |
| 124 synchronized void bind(String nativeLibraryName, String[] commandLine) { | 125 synchronized void bind(String nativeLibraryName, String[] commandLine) { |
| 125 TraceEvent.begin(); | 126 TraceEvent.begin(); |
| 126 assert !ThreadUtils.runningOnUiThread(); | 127 assert !ThreadUtils.runningOnUiThread(); |
| 127 | 128 |
| 128 final Intent intent = createServiceBindIntent(); | 129 final Intent intent = createServiceBindIntent(); |
| 129 | 130 |
| 130 intent.putExtra(EXTRA_NATIVE_LIBRARY_NAME, nativeLibraryName); | 131 intent.putExtra(EXTRA_NATIVE_LIBRARY_NAME, nativeLibraryName); |
| 131 if (commandLine != null) { | 132 if (commandLine != null) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 143 * | 144 * |
| 144 * This establishes the parameters that were not already supplied in bind. | 145 * This establishes the parameters that were not already supplied in bind. |
| 145 * @param commandLine (Optional) will be ignored if the command line was alr
eady sent in bind() | 146 * @param commandLine (Optional) will be ignored if the command line was alr
eady sent in bind() |
| 146 * @param fileToBeMapped a list of file descriptors that should be registere
d | 147 * @param fileToBeMapped a list of file descriptors that should be registere
d |
| 147 * @param callback Used for status updates regarding this process connection
. | 148 * @param callback Used for status updates regarding this process connection
. |
| 148 * @param onConnectionCallback will be run when the connection is setup and
ready to use. | 149 * @param onConnectionCallback will be run when the connection is setup and
ready to use. |
| 149 */ | 150 */ |
| 150 synchronized void setupConnection( | 151 synchronized void setupConnection( |
| 151 String[] commandLine, | 152 String[] commandLine, |
| 152 FileDescriptorInfo[] filesToBeMapped, | 153 FileDescriptorInfo[] filesToBeMapped, |
| 153 ISandboxedProcessCallback callback, | 154 IChildProcessCallback callback, |
| 154 Runnable onConnectionCallback) { | 155 Runnable onConnectionCallback) { |
| 155 TraceEvent.begin(); | 156 TraceEvent.begin(); |
| 156 assert mConnectionParams == null; | 157 assert mConnectionParams == null; |
| 157 mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, c
allback, | 158 mConnectionParams = new ConnectionParams(commandLine, filesToBeMapped, c
allback, |
| 158 onConnectionCallback); | 159 onConnectionCallback); |
| 159 if (mServiceConnectComplete) { | 160 if (mServiceConnectComplete) { |
| 160 doConnectionSetup(); | 161 doConnectionSetup(); |
| 161 } | 162 } |
| 162 TraceEvent.end(); | 163 TraceEvent.end(); |
| 163 } | 164 } |
| 164 | 165 |
| 165 /** | 166 /** |
| 166 * Unbind the ISandboxedProcessService. It is safe to call this multiple tim
es. | 167 * Unbind the IChildProcessService. It is safe to call this multiple times. |
| 167 */ | 168 */ |
| 168 synchronized void unbind() { | 169 synchronized void unbind() { |
| 169 if (mIsBound) { | 170 if (mIsBound) { |
| 170 mContext.unbindService(this); | 171 mContext.unbindService(this); |
| 171 mIsBound = false; | 172 mIsBound = false; |
| 172 } | 173 } |
| 173 if (mService != null) { | 174 if (mService != null) { |
| 174 if (mHighPriorityConnection != null) { | 175 if (mHighPriorityConnection != null) { |
| 175 unbindHighPriority(true); | 176 unbindHighPriority(true); |
| 176 } | 177 } |
| 177 mService = null; | 178 mService = null; |
| 178 mPID = 0; | 179 mPID = 0; |
| 179 } | 180 } |
| 180 mConnectionParams = null; | 181 mConnectionParams = null; |
| 181 mServiceConnectComplete = false; | 182 mServiceConnectComplete = false; |
| 182 } | 183 } |
| 183 | 184 |
| 184 // Called on the main thread to notify that the service is connected. | 185 // Called on the main thread to notify that the service is connected. |
| 185 @Override | 186 @Override |
| 186 public void onServiceConnected(ComponentName className, IBinder service) { | 187 public void onServiceConnected(ComponentName className, IBinder service) { |
| 187 TraceEvent.begin(); | 188 TraceEvent.begin(); |
| 188 mServiceConnectComplete = true; | 189 mServiceConnectComplete = true; |
| 189 mService = ISandboxedProcessService.Stub.asInterface(service); | 190 mService = IChildProcessService.Stub.asInterface(service); |
| 190 if (mConnectionParams != null) { | 191 if (mConnectionParams != null) { |
| 191 doConnectionSetup(); | 192 doConnectionSetup(); |
| 192 } | 193 } |
| 193 TraceEvent.end(); | 194 TraceEvent.end(); |
| 194 } | 195 } |
| 195 | 196 |
| 196 // Called on the main thread to notify that the bindService() call failed (r
eturned false). | 197 // Called on the main thread to notify that the bindService() call failed (r
eturned false). |
| 197 private void onBindFailed() { | 198 private void onBindFailed() { |
| 198 mServiceConnectComplete = true; | 199 mServiceConnectComplete = true; |
| 199 if (mConnectionParams != null) { | 200 if (mConnectionParams != null) { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 Log.w(TAG, "Failed to close FD.", ioe); | 264 Log.w(TAG, "Failed to close FD.", ioe); |
| 264 } | 265 } |
| 265 } | 266 } |
| 266 mConnectionParams = null; | 267 mConnectionParams = null; |
| 267 if (onConnectionCallback != null) { | 268 if (onConnectionCallback != null) { |
| 268 onConnectionCallback.run(); | 269 onConnectionCallback.run(); |
| 269 } | 270 } |
| 270 TraceEvent.end(); | 271 TraceEvent.end(); |
| 271 } | 272 } |
| 272 | 273 |
| 273 // Called on the main thread to notify that the sandboxed service did not di
sconnect gracefully. | 274 // Called on the main thread to notify that the child service did not discon
nect gracefully. |
| 274 @Override | 275 @Override |
| 275 public void onServiceDisconnected(ComponentName className) { | 276 public void onServiceDisconnected(ComponentName className) { |
| 276 int pid = mPID; // Stash pid & connection callback since unbind() will
clear them. | 277 int pid = mPID; // Stash pid & connection callback since unbind() will
clear them. |
| 277 Runnable onConnectionCallback = | 278 Runnable onConnectionCallback = |
| 278 mConnectionParams != null ? mConnectionParams.mOnConnectionCallback
: null; | 279 mConnectionParams != null ? mConnectionParams.mOnConnectionCallback
: null; |
| 279 Log.w(TAG, "onServiceDisconnected (crash?): pid=" + pid); | 280 Log.w(TAG, "onServiceDisconnected (crash?): pid=" + pid); |
| 280 unbind(); // We don't want to auto-restart on crash. Let the browser do
that. | 281 unbind(); // We don't want to auto-restart on crash. Let the browser do
that. |
| 281 if (pid != 0) { | 282 if (pid != 0) { |
| 282 mDeathCallback.onSandboxedProcessDied(pid); | 283 mDeathCallback.onChildProcessDied(pid); |
| 283 } | 284 } |
| 284 if (onConnectionCallback != null) { | 285 if (onConnectionCallback != null) { |
| 285 onConnectionCallback.run(); | 286 onConnectionCallback.run(); |
| 286 } | 287 } |
| 287 } | 288 } |
| 288 | 289 |
| 289 /** | 290 /** |
| 290 * Bind the service with a new high priority connection. This will make the
service | 291 * Bind the service with a new high priority connection. This will make the
service |
| 291 * as important as the main process. | 292 * as important as the main process. |
| 292 */ | 293 */ |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 } | 345 } |
| 345 } | 346 } |
| 346 | 347 |
| 347 /** | 348 /** |
| 348 * @return The connection PID, or 0 if not yet connected. | 349 * @return The connection PID, or 0 if not yet connected. |
| 349 */ | 350 */ |
| 350 synchronized public int getPid() { | 351 synchronized public int getPid() { |
| 351 return mPID; | 352 return mPID; |
| 352 } | 353 } |
| 353 } | 354 } |
| OLD | NEW |