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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/SandboxedProcessConnection.java

Issue 10696025: Upstream ChildProcessLauncher changes for Android. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add additional assert and comments Created 8 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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.util.concurrent.atomic.AtomicBoolean; 20 import java.util.concurrent.atomic.AtomicBoolean;
20 21
21 import org.chromium.base.CalledByNative; 22 import org.chromium.base.CalledByNative;
22 import org.chromium.content.app.SandboxedProcessService; 23 import org.chromium.base.ThreadUtils;
23 import org.chromium.content.common.CommandLine; 24 import org.chromium.content.common.CommandLine;
24 import org.chromium.content.common.ISandboxedProcessCallback; 25 import org.chromium.content.common.ISandboxedProcessCallback;
25 import org.chromium.content.common.ISandboxedProcessService; 26 import org.chromium.content.common.ISandboxedProcessService;
26 import org.chromium.content.common.TraceEvent; 27 import org.chromium.content.common.TraceEvent;
27 28
28 public class SandboxedProcessConnection { 29 public class SandboxedProcessConnection implements ServiceConnection {
29 interface DeathCallback { 30 interface DeathCallback {
30 void onSandboxedProcessDied(int pid); 31 void onSandboxedProcessDied(int pid);
31 } 32 }
32 33
33 // Names of items placed in the bind intent or connection bundle. 34 // Names of items placed in the bind intent or connection bundle.
34 public static final String EXTRA_COMMAND_LINE = 35 public static final String EXTRA_COMMAND_LINE =
35 "com.google.android.apps.chrome.extra.sandbox_command_line"; 36 "com.google.android.apps.chrome.extra.sandbox_command_line";
37 public static final String EXTRA_NATIVE_LIBRARY_NAME =
38 "com.google.android.apps.chrome.extra.sandbox_native_library_name";
36 // Note the FD may only be passed in the connection bundle. 39 // Note the FD may only be passed in the connection bundle.
37 public static final String EXTRA_IPC_FD = "com.google.android.apps.chrome.ex tra.sandbox_ipcFd"; 40 public static final String EXTRA_IPC_FD = "com.google.android.apps.chrome.ex tra.sandbox_ipcFd";
38 public static final String EXTRA_CRASH_FD = 41 public static final String EXTRA_FILES_PREFIX =
39 "com.google.android.apps.chrome.extra.sandbox_crashFd"; 42 "com.google.android.apps.chrome.extra.sandbox_extraFile_";
40 public static final String EXTRA_CHROME_PAK_FD = 43 public static final String EXTRA_FILES_ID_SUFFIX = "_id";
41 "com.google.android.apps.chrome.extra.sandbox_chromePakFd"; 44 public static final String EXTRA_FILES_FD_SUFFIX = "_fd";
42 public static final String EXTRA_LOCALE_PAK_FD =
43 "com.google.android.apps.chrome.extra.sandbox_localePakFd";
44 45
45 private final Context mContext; 46 private final Context mContext;
46 private final int mServiceNumber; 47 private final int mServiceNumber;
47 private final SandboxedProcessConnection.DeathCallback mDeathCallback; 48 private final SandboxedProcessConnection.DeathCallback mDeathCallback;
48 49
49 // Synchronization: While most internal flow occurs on the UI thread, the pu blic API 50 // Synchronization: While most internal flow occurs on the UI thread, the pu blic API
50 // (specifically bind and unbind) may be called from any thread, hence all e ntry point methods 51 // (specifically bind and unbind) may be called from any thread, hence all e ntry point methods
51 // into the class are synchronized on the SandboxedProcessConnection instanc e to protect access 52 // into the class are synchronized on the SandboxedProcessConnection instanc e to protect access
52 // to these members. But see also the TODO where AsyncBoundServiceConnection is created. 53 // to these members. But see also the TODO where AsyncBoundServiceConnection is created.
53 private ISandboxedProcessService mService = null; 54 private ISandboxedProcessService mService = null;
54 private boolean mServiceConnectComplete = false; 55 private boolean mServiceConnectComplete = false;
55 private int mPID = 0; // Process ID of the corresponding sandboxed process. 56 private int mPID = 0; // Process ID of the corresponding sandboxed process.
56 private HighPriorityConnection mHighPriorityConnection = null; 57 private HighPriorityConnection mHighPriorityConnection = null;
57 private int mHighPriorityConnectionCount = 0; 58 private int mHighPriorityConnectionCount = 0;
58 59
59 private static final String TAG = "SandboxedProcessConnection"; 60 private static final String TAG = "SandboxedProcessConnection";
60 61
61 private static class ConnectionParams { 62 private static class ConnectionParams {
62 final String[] mCommandLine; 63 final String[] mCommandLine;
63 final int mIpcFd; 64 final int mIpcFd;
64 final int mCrashFd; 65 final int[] mExtraFileIdsAndFds;
65 final ISandboxedProcessCallback mCallback; 66 final ISandboxedProcessCallback mCallback;
66 final Runnable mOnConnectionCallback; 67 final Runnable mOnConnectionCallback;
67 68
68 ConnectionParams( 69 ConnectionParams(
69 String[] commandLine, 70 String[] commandLine,
70 int ipcFd, 71 int ipcFd,
71 int crashFd, 72 int[] idsAndFds,
72 ISandboxedProcessCallback callback, 73 ISandboxedProcessCallback callback,
73 Runnable onConnectionCallback) { 74 Runnable onConnectionCallback) {
74 mCommandLine = commandLine; 75 mCommandLine = commandLine;
75 mIpcFd = ipcFd; 76 mIpcFd = ipcFd;
76 mCrashFd = crashFd; 77 mExtraFileIdsAndFds = idsAndFds;
77 mCallback = callback; 78 mCallback = callback;
78 mOnConnectionCallback = onConnectionCallback; 79 mOnConnectionCallback = onConnectionCallback;
79 } 80 }
80 };
81
82 // Implement the ServiceConnection as an inner class, so it can stem the ser vice
83 // callbacks when cancelled or unbound.
84 class AsyncBoundServiceConnection extends AsyncTask<Intent, Void, Boolean>
85 implements ServiceConnection {
86 private boolean mIsDestroyed = false;
87 private AtomicBoolean mIsBound = new AtomicBoolean(false);
88
89 // AsyncTask
90 @Override
91 protected Boolean doInBackground(Intent... intents) {
92 boolean isBound = mContext.bindService(intents[0], this, Context.BIN D_AUTO_CREATE);
93 mIsBound.set(isBound);
94 return isBound;
95 }
96
97 @Override
98 protected void onPostExecute(Boolean boundOK) {
99 synchronized (SandboxedProcessConnection.this) {
100 if (!boundOK && !mIsDestroyed) {
101 SandboxedProcessConnection.this.onBindFailed();
102 }
103 // else: bind will complete asynchronously with a callback to on ServiceConnected().
104 }
105 }
106
107 @Override
108 protected void onCancelled(Boolean boundOK) {
109 // According to {@link AsyncTask#onCancelled(Object)}, the Object ca n be null.
110 if (boundOK != null && boundOK) {
111 unBindIfAble();
112 }
113 }
114
115 /**
116 * Unbinds this connection if it hasn't already been unbound. There's a guard to check that
117 * we haven't already been unbound because the Browser process cancellin g a connection can
118 * race with something else (Android?) cancelling the connection.
119 */
120 private void unBindIfAble() {
121 if (mIsBound.getAndSet(false)) {
122 mContext.unbindService(this);
123 }
124 }
125
126 // ServiceConnection
127 @Override
128 public void onServiceConnected(ComponentName name, IBinder service) {
129 synchronized (SandboxedProcessConnection.this) {
130 if (!mIsDestroyed) {
131 SandboxedProcessConnection.this.onServiceConnected(name, ser vice);
132 }
133 }
134 }
135
136 @Override
137 public void onServiceDisconnected(ComponentName name) {
138 synchronized (SandboxedProcessConnection.this) {
139 if (!mIsDestroyed) {
140 SandboxedProcessConnection.this.onServiceDisconnected(name);
141 }
142 }
143 }
144
145 public void destroy() {
146 assert Thread.holdsLock(SandboxedProcessConnection.this);
147 if (!cancel(false)) {
148 unBindIfAble();
149 }
150 mIsDestroyed = true;
151 }
152 } 81 }
153 82
154 // This is only valid while the connection is being established. 83 // This is only valid while the connection is being established.
155 private ConnectionParams mConnectionParams; 84 private ConnectionParams mConnectionParams;
156 private AsyncBoundServiceConnection mServiceConnection; 85 private boolean mIsBound;
157 86
158 SandboxedProcessConnection(Context context, int number, 87 SandboxedProcessConnection(Context context, int number,
159 SandboxedProcessConnection.DeathCallback deathCallback) { 88 SandboxedProcessConnection.DeathCallback deathCallback) {
160 mContext = context; 89 mContext = context;
161 mServiceNumber = number; 90 mServiceNumber = number;
162 mDeathCallback = deathCallback; 91 mDeathCallback = deathCallback;
163 } 92 }
164 93
165 int getServiceNumber() { 94 int getServiceNumber() {
166 return mServiceNumber; 95 return mServiceNumber;
167 } 96 }
168 97
169 synchronized ISandboxedProcessService getService() { 98 synchronized ISandboxedProcessService getService() {
170 return mService; 99 return mService;
171 } 100 }
172 101
173 private Intent createServiceBindIntent() { 102 private Intent createServiceBindIntent() {
174 Intent intent = new Intent(); 103 Intent intent = new Intent();
175 String n = SandboxedProcessService.class.getName(); 104 String n = org.chromium.content.app.SandboxedProcessService.class.getNam e();
176 intent.setClassName(mContext, n + mServiceNumber); 105 intent.setClassName(mContext, n + mServiceNumber);
177 intent.setPackage(mContext.getPackageName()); 106 intent.setPackage(mContext.getPackageName());
178 return intent; 107 return intent;
179 } 108 }
180 109
181 /** 110 /**
182 * Bind to an ISandboxedProcessService. This must be followed by a call to s etupConnection() 111 * Bind to an ISandboxedProcessService. This must be followed by a call to s etupConnection()
183 * to setup the connection parameters. (These methods are separated to allow the client 112 * to setup the connection parameters. (These methods are separated to allow the client
184 * to pass whatever parameters they have available here, and complete the re mainder 113 * to pass whatever parameters they have available here, and complete the re mainder
185 * later while reducing the connection setup latency). 114 * later while reducing the connection setup latency).
186 * 115 * @param nativeLibraryName The name of the shared native library to be load ed for the
116 * sandboxed process.
187 * @param commandLine (Optional) Command line for the sandboxed process. If omitted, then 117 * @param commandLine (Optional) Command line for the sandboxed process. If omitted, then
188 * the command line parameters must instead be passed to setupConnection(). 118 * the command line parameters must instead be passed to setupConnection().
189 */ 119 */
190 synchronized void bind(String[] commandLine) { 120 synchronized void bind(String nativeLibraryName, String[] commandLine) {
191 TraceEvent.begin(); 121 TraceEvent.begin();
122 assert !ThreadUtils.runningOnUiThread();
123
192 final Intent intent = createServiceBindIntent(); 124 final Intent intent = createServiceBindIntent();
193 125
126 intent.putExtra(EXTRA_NATIVE_LIBRARY_NAME, nativeLibraryName);
194 if (commandLine != null) { 127 if (commandLine != null) {
195 intent.putExtra(EXTRA_COMMAND_LINE, commandLine); 128 intent.putExtra(EXTRA_COMMAND_LINE, commandLine);
196 } 129 }
197 // TODO(joth): By the docs, AsyncTasks should only be created on the UI thread, but 130
198 // bind() currently 'may' be called on any thread. In practice it's only ever called 131 mIsBound = mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
199 // from UI, but it's not guaranteed. See http://b/5694925. 132 if (!mIsBound) {
200 Looper mainLooper = Looper.getMainLooper(); 133 onBindFailed();
201 if (Looper.myLooper() == mainLooper) {
202 mServiceConnection = new AsyncBoundServiceConnection();
203 // On completion this will call back to onServiceConnected().
204 mServiceConnection.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, intent);
205 } else {
206 // TODO(jcivelli): http://b/5694925 we only have to post to the UI t hread because we use
207 // an AsyncTask and it requires it. Replace that AsyncTask by runnin g our own thread and
208 // change this so we run directly from the current thread.
209 new Handler(mainLooper).postAtFrontOfQueue(new Runnable() {
210 public void run() {
211 mServiceConnection = new AsyncBoundServiceConnection ();
212 // On completion this will call back to onServiceCon nected().
213 mServiceConnection.executeOnExecutor(AsyncTask.THREA D_POOL_EXECUTOR,
214 intent);
215 }
216 });
217 } 134 }
218 TraceEvent.end(); 135 TraceEvent.end();
219 } 136 }
220 137
221 /** Setup a connection previous bound via a call to bind(). 138 /** Setup a connection previous bound via a call to bind().
222 * 139 *
223 * This establishes the parameters that were not already supplied in bind. 140 * This establishes the parameters that were not already supplied in bind.
224 * @param commandLine (Optional) will be ignored if the command line was alr eady sent in bind() 141 * @param commandLine (Optional) will be ignored if the command line was alr eady sent in bind()
225 * @param ipcFd The file descriptor that will be used by the sandbox process for IPC. 142 * @param ipcFd The file descriptor that will be used by the sandbox process for IPC.
226 * @param crashFd (Optional) file descriptor that will be used for crash dum ps. 143 * @param fileToRegisterIdFds (Optional) a list of pair of IDs and FDs that should be
144 * registered
227 * @param callback Used for status updates regarding this process connection . 145 * @param callback Used for status updates regarding this process connection .
228 * @param onConnectionCallback will be run when the connection is setup and ready to use. 146 * @param onConnectionCallback will be run when the connection is setup and ready to use.
229 */ 147 */
230 synchronized void setupConnection( 148 synchronized void setupConnection(
231 String[] commandLine, 149 String[] commandLine,
232 int ipcFd, 150 int ipcFd,
233 int crashFd, 151 int[] fileToRegisterIdFds,
234 ISandboxedProcessCallback callback, 152 ISandboxedProcessCallback callback,
235 Runnable onConnectionCallback) { 153 Runnable onConnectionCallback) {
236 TraceEvent.begin(); 154 TraceEvent.begin();
237 assert mConnectionParams == null; 155 assert mConnectionParams == null;
238 mConnectionParams = new ConnectionParams(commandLine, ipcFd, crashFd, ca llback, 156 mConnectionParams = new ConnectionParams(commandLine, ipcFd, fileToRegis terIdFds, callback,
239 onConnectionCallback); 157 onConnectionCallback);
240 if (mServiceConnectComplete) { 158 if (mServiceConnectComplete) {
241 doConnectionSetup(); 159 doConnectionSetup();
242 } 160 }
243 TraceEvent.end(); 161 TraceEvent.end();
244 } 162 }
245 163
246 /** 164 /**
247 * Unbind the ISandboxedProcessService. It is safe to call this multiple tim es. 165 * Unbind the ISandboxedProcessService. It is safe to call this multiple tim es.
248 */ 166 */
249 synchronized void unbind() { 167 synchronized void unbind() {
250 if (mServiceConnection != null) { 168 if (mIsBound) {
251 mServiceConnection.destroy(); 169 mContext.unbindService(this);
252 mServiceConnection = null; 170 mIsBound = false;
253 } 171 }
254 if (mService != null) { 172 if (mService != null) {
255 if (mHighPriorityConnection != null) { 173 if (mHighPriorityConnection != null) {
256 unbindHighPriority(true); 174 unbindHighPriority(true);
257 } 175 }
258 mService = null; 176 mService = null;
259 mPID = 0; 177 mPID = 0;
260 } 178 }
261 mConnectionParams = null; 179 mConnectionParams = null;
262 mServiceConnectComplete = false; 180 mServiceConnectComplete = false;
263 } 181 }
264 182
265 // Called on the main thread to notify that the service is connected. 183 // Called on the main thread to notify that the service is connected.
266 private void onServiceConnected(ComponentName className, IBinder service) { 184 @Override
267 assert Thread.holdsLock(this); 185 public void onServiceConnected(ComponentName className, IBinder service) {
268 TraceEvent.begin(); 186 TraceEvent.begin();
269 mServiceConnectComplete = true; 187 mServiceConnectComplete = true;
270 mService = ISandboxedProcessService.Stub.asInterface(service); 188 mService = ISandboxedProcessService.Stub.asInterface(service);
271 if (mConnectionParams != null) { 189 if (mConnectionParams != null) {
272 doConnectionSetup(); 190 doConnectionSetup();
273 } 191 }
274 TraceEvent.end(); 192 TraceEvent.end();
275 } 193 }
276 194
277 // Called on the main thread to notify that the bindService() call failed (r eturned false). 195 // Called on the main thread to notify that the bindService() call failed (r eturned false).
278 private void onBindFailed() { 196 private void onBindFailed() {
279 assert Thread.holdsLock(this);
280 mServiceConnectComplete = true; 197 mServiceConnectComplete = true;
281 if (mConnectionParams != null) { 198 if (mConnectionParams != null) {
282 doConnectionSetup(); 199 doConnectionSetup();
283 } 200 }
284 } 201 }
285 202
286 /** 203 /**
287 * Called when the connection parameters have been set, and a connection has been established 204 * Called when the connection parameters have been set, and a connection has been established
288 * (as signaled by onServiceConnected), or if the connection failed (mServic e will be false). 205 * (as signaled by onServiceConnected), or if the connection failed (mServic e will be false).
289 */ 206 */
290 private void doConnectionSetup() { 207 private void doConnectionSetup() {
291 TraceEvent.begin(); 208 TraceEvent.begin();
292 assert mServiceConnectComplete && mConnectionParams != null; 209 assert mServiceConnectComplete && mConnectionParams != null;
293 // Capture the callback before it is potentially nulled in unbind(). 210 // Capture the callback before it is potentially nulled in unbind().
294 Runnable onConnectionCallback = 211 Runnable onConnectionCallback =
295 mConnectionParams != null ? mConnectionParams.mOnConnectionCallback : null; 212 mConnectionParams != null ? mConnectionParams.mOnConnectionCallback : null;
296 if (onConnectionCallback == null) { 213 if (onConnectionCallback == null) {
297 unbind(); 214 unbind();
298 } else if (mService != null) { 215 } else if (mService != null) {
216 ParcelFileDescriptor ipcFdParcel;
299 try { 217 try {
300 ParcelFileDescriptor ipcFdParcel = 218 ipcFdParcel = ParcelFileDescriptor.fromFd(mConnectionParams.mIpc Fd);
301 ParcelFileDescriptor.fromFd(mConnectionParams.mIpcFd); 219 } catch(IOException e) {
302 Bundle bundle = new Bundle(); 220 Log.e(TAG, "Invalid IPC FD, aborting connection.", e);
303 bundle.putStringArray(EXTRA_COMMAND_LINE, mConnectionParams.mCom mandLine); 221 return;
304 bundle.putParcelable(EXTRA_IPC_FD, ipcFdParcel); 222 }
223 Bundle bundle = new Bundle();
224 bundle.putStringArray(EXTRA_COMMAND_LINE, mConnectionParams.mCommand Line);
225 bundle.putParcelable(EXTRA_IPC_FD, ipcFdParcel);
305 226
227 int[] idsAndFds = mConnectionParams.mExtraFileIdsAndFds;
228 assert idsAndFds.length % 2 == 0;
229 int pairLength = idsAndFds.length / 2;
230 for (int i = 0; i < pairLength; i++) {
231 String idName = EXTRA_FILES_PREFIX + i + EXTRA_FILES_ID_SUFFIX;
232 String fdName = EXTRA_FILES_PREFIX + i + EXTRA_FILES_FD_SUFFIX;
233 ParcelFileDescriptor parcelFile;
306 try { 234 try {
307 ParcelFileDescriptor crashFdParcel = 235 parcelFile = ParcelFileDescriptor.fromFd(idsAndFds[(2 * i) + 1]);
308 ParcelFileDescriptor.fromFd(mConnectionParams.mCrashFd); 236 bundle.putParcelable(fdName, parcelFile);
309 bundle.putParcelable(EXTRA_CRASH_FD, crashFdParcel); 237 bundle.putInt(idName, idsAndFds[2 * i]);
310 // We will let the GC close the crash ParcelFileDescriptor. 238 } catch (IOException e) {
311 } catch (java.io.IOException e) { 239 Log.e(TAG, "Invalid extra file FD: id=" + idsAndFds[ 2 * i] + " fd="
312 Log.w(TAG, "Invalid crash Fd. Native crash reporting will be disabled."); 240 + idsAndFds[(2 * i) + 1]);
313 } 241 }
314 242 }
243 try {
315 mPID = mService.setupConnection(bundle, mConnectionParams.mCallb ack); 244 mPID = mService.setupConnection(bundle, mConnectionParams.mCallb ack);
316 ipcFdParcel.close(); // We proactivley close now rather than wa it for GC & 245 } catch (android.os.RemoteException re) {
317 // finalizer. 246 Log.e(TAG, "Failed to setup connection.", re);
318 } catch(java.io.IOException e) { 247 }
319 Log.w(TAG, "Invalid ipc FD."); 248 try {
320 } catch(android.os.RemoteException e) { 249 // We proactivley close now rather than wait for GC & finalizer.
321 Log.w(TAG, "Exception when trying to call service method: " 250 ipcFdParcel.close();
322 + e); 251 } catch (IOException ioe) {
252 Log.w(TAG, "Failed to close IPC FD.", ioe);
323 } 253 }
324 } 254 }
325 mConnectionParams = null; 255 mConnectionParams = null;
326 if (onConnectionCallback != null) { 256 if (onConnectionCallback != null) {
327 onConnectionCallback.run(); 257 onConnectionCallback.run();
328 } 258 }
329 TraceEvent.end(); 259 TraceEvent.end();
330 } 260 }
331 261
332 // Called on the main thread to notify that the sandboxed service did not di sconnect gracefully. 262 // Called on the main thread to notify that the sandboxed service did not di sconnect gracefully.
333 private void onServiceDisconnected(ComponentName className) { 263 @Override
334 assert Thread.holdsLock(this); 264 public void onServiceDisconnected(ComponentName className) {
335 int pid = mPID; // Stash pid & connection callback since unbind() will clear them. 265 int pid = mPID; // Stash pid & connection callback since unbind() will clear them.
336 Runnable onConnectionCallback = 266 Runnable onConnectionCallback =
337 mConnectionParams != null ? mConnectionParams.mOnConnectionCallback : null; 267 mConnectionParams != null ? mConnectionParams.mOnConnectionCallback : null;
338 Log.w(TAG, "onServiceDisconnected (crash?): pid=" + pid); 268 Log.w(TAG, "onServiceDisconnected (crash?): pid=" + pid);
339 unbind(); // We don't want to auto-restart on crash. Let the browser do that. 269 unbind(); // We don't want to auto-restart on crash. Let the browser do that.
340 if (pid != 0) { 270 if (pid != 0) {
341 mDeathCallback.onSandboxedProcessDied(pid); 271 mDeathCallback.onSandboxedProcessDied(pid);
342 } 272 }
343 if (onConnectionCallback != null) { 273 if (onConnectionCallback != null) {
344 onConnectionCallback.run(); 274 onConnectionCallback.run();
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 } 333 }
404 } 334 }
405 335
406 /** 336 /**
407 * @return The connection PID, or 0 if not yet connected. 337 * @return The connection PID, or 0 if not yet connected.
408 */ 338 */
409 synchronized public int getPid() { 339 synchronized public int getPid() {
410 return mPID; 340 return mPID;
411 } 341 }
412 } 342 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698