OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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.content.pm.PackageManager; | 11 import android.content.pm.PackageManager; |
12 import android.content.pm.ServiceInfo; | 12 import android.content.pm.ServiceInfo; |
13 import android.os.Build; | 13 import android.os.Build; |
14 import android.os.Bundle; | 14 import android.os.Bundle; |
15 import android.os.IBinder; | 15 import android.os.IBinder; |
16 import android.os.RemoteException; | 16 import android.os.RemoteException; |
17 | 17 |
18 import org.chromium.base.Log; | 18 import org.chromium.base.Log; |
19 import org.chromium.base.TraceEvent; | 19 import org.chromium.base.TraceEvent; |
20 import org.chromium.base.VisibleForTesting; | 20 import org.chromium.base.VisibleForTesting; |
21 import org.chromium.base.process_launcher.ChildProcessCreationParams; | 21 import org.chromium.base.process_launcher.ChildProcessCreationParams; |
22 import org.chromium.base.process_launcher.FileDescriptorInfo; | |
23 import org.chromium.base.process_launcher.ICallbackInt; | 22 import org.chromium.base.process_launcher.ICallbackInt; |
24 import org.chromium.base.process_launcher.IChildProcessService; | 23 import org.chromium.base.process_launcher.IChildProcessService; |
25 | 24 |
26 import java.io.IOException; | |
27 import java.util.HashMap; | 25 import java.util.HashMap; |
28 import java.util.Map; | 26 import java.util.Map; |
29 | 27 |
30 import javax.annotation.Nullable; | 28 import javax.annotation.Nullable; |
31 | 29 |
32 /** | 30 /** |
33 * Manages a connection between the browser activity and a child service. | 31 * Manages a connection between the browser activity and a child service. |
34 */ | 32 */ |
35 public class ChildProcessConnection { | 33 public class ChildProcessConnection { |
36 private static final String TAG = "ChildProcessConn"; | 34 private static final String TAG = "ChildProcessConn"; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
159 private final ComponentName mServiceName; | 157 private final ComponentName mServiceName; |
160 | 158 |
161 // Parameters passed to the child process through the service binding intent . | 159 // Parameters passed to the child process through the service binding intent . |
162 // If the service gets recreated by the framework the intent will be reused, so these parameters | 160 // If the service gets recreated by the framework the intent will be reused, so these parameters |
163 // should be common to all processes of that type. | 161 // should be common to all processes of that type. |
164 private final Bundle mChildProcessCommonParameters; | 162 private final Bundle mChildProcessCommonParameters; |
165 | 163 |
166 private final ChildProcessCreationParams mCreationParams; | 164 private final ChildProcessCreationParams mCreationParams; |
167 | 165 |
168 private static class ConnectionParams { | 166 private static class ConnectionParams { |
169 final String[] mCommandLine; | 167 final Bundle mBundle; |
boliu
2017/05/15 21:38:22
name this mConnectionBundle
Jay Civelli
2017/05/17 16:42:50
Done.
| |
170 final FileDescriptorInfo[] mFilesToBeMapped; | |
171 final IBinder mCallback; | 168 final IBinder mCallback; |
172 | 169 |
173 ConnectionParams( | 170 ConnectionParams(Bundle bundle, IBinder callback) { |
174 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, IBin der callback) { | 171 mBundle = bundle; |
175 mCommandLine = commandLine; | |
176 mFilesToBeMapped = filesToBeMapped; | |
177 mCallback = callback; | 172 mCallback = callback; |
178 } | 173 } |
179 } | 174 } |
180 | 175 |
181 // This is set in start() and is used in onServiceConnected(). | 176 // This is set in start() and is used in onServiceConnected(). |
182 private StartCallback mStartCallback; | 177 private StartCallback mStartCallback; |
183 | 178 |
184 // This is set in setupConnection() and is later used in doConnectionSetupLo cked(), after which | 179 // This is set in setupConnection() and is later used in doConnectionSetup() , after which the |
185 // the variable is cleared. Therefore this is only valid while the connectio n is being set up. | 180 // variable is cleared. Therefore this is only valid while the connection is being set up. |
186 private ConnectionParams mConnectionParams; | 181 private ConnectionParams mConnectionParams; |
187 | 182 |
188 // Callback provided in setupConnection() that will communicate the result t o the caller. This | 183 // Callback provided in setupConnection() that will communicate the result t o the caller. This |
189 // has to be called exactly once after setupConnection(), even if setup fail s, so that the | 184 // has to be called exactly once after setupConnection(), even if setup fail s, so that the |
190 // caller can free up resources associated with the setup attempt. This is s et to null after the | 185 // caller can free up resources associated with the setup attempt. This is s et to null after the |
191 // call. | 186 // call. |
192 private ConnectionCallback mConnectionCallback; | 187 private ConnectionCallback mConnectionCallback; |
193 | 188 |
194 private IChildProcessService mService; | 189 private IChildProcessService mService; |
195 | 190 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 * Starts a connection to an IChildProcessService. This must be followed by a call to | 283 * Starts a connection to an IChildProcessService. This must be followed by a call to |
289 * setupConnection() to setup the connection parameters. start() and setupCo nnection() are | 284 * setupConnection() to setup the connection parameters. start() and setupCo nnection() are |
290 * separate to allow to pass whatever parameters are available in start(), a nd complete the | 285 * separate to allow to pass whatever parameters are available in start(), a nd complete the |
291 * remainder addStrongBinding while reducing the connection setup latency. | 286 * remainder addStrongBinding while reducing the connection setup latency. |
292 * @param useStrongBinding whether a strong binding should be bound by defau lt. If false, an | 287 * @param useStrongBinding whether a strong binding should be bound by defau lt. If false, an |
293 * initial moderate binding is used. | 288 * initial moderate binding is used. |
294 * @param startCallback (optional) callback when the child process starts or fails to start. | 289 * @param startCallback (optional) callback when the child process starts or fails to start. |
295 */ | 290 */ |
296 public void start(boolean useStrongBinding, StartCallback startCallback) { | 291 public void start(boolean useStrongBinding, StartCallback startCallback) { |
297 assert LauncherThread.runningOnLauncherThread(); | 292 assert LauncherThread.runningOnLauncherThread(); |
293 | |
298 try { | 294 try { |
299 TraceEvent.begin("ChildProcessConnection.start"); | 295 TraceEvent.begin("ChildProcessConnection.start"); |
300 assert LauncherThread.runningOnLauncherThread(); | 296 assert LauncherThread.runningOnLauncherThread(); |
301 assert mConnectionParams | 297 assert mConnectionParams |
302 == null : "setupConnection() called before start() in ChildP rocessConnection."; | 298 == null : "setupConnection() called before start() in ChildP rocessConnection."; |
303 | 299 |
304 mStartCallback = startCallback; | 300 mStartCallback = startCallback; |
305 | 301 |
306 if (!bind(useStrongBinding)) { | 302 if (!bind(useStrongBinding)) { |
307 Log.e(TAG, "Failed to establish the service connection."); | 303 Log.e(TAG, "Failed to establish the service connection."); |
308 // We have to notify the caller so that they can free-up associa ted resources. | 304 // We have to notify the caller so that they can free-up associa ted resources. |
309 // TODO(ppi): Can we hard-fail here? | 305 // TODO(ppi): Can we hard-fail here? |
310 mDeathCallback.onChildProcessDied(ChildProcessConnection.this); | 306 mDeathCallback.onChildProcessDied(ChildProcessConnection.this); |
311 } | 307 } |
312 } finally { | 308 } finally { |
313 TraceEvent.end("ChildProcessConnection.start"); | 309 TraceEvent.end("ChildProcessConnection.start"); |
314 } | 310 } |
315 } | 311 } |
316 | 312 |
317 /** | 313 /** |
318 * Setups the connection after it was started with start(). | 314 * Sets-up the connection after it was started with start(). |
319 * @param commandLine (optional) will be ignored if the command line was alr eady sent in start() | 315 * @param connectionBundle a bundle passed to the service that can be used t o pass various |
320 * @param filesToBeMapped a list of file descriptors that should be register ed | 316 * parameters to the service |
321 * @param callback optional client specified callbacks that the child can us e to communicate | 317 * @param callback optional client specified callbacks that the child can us e to communicate |
322 * with the parent process | 318 * with the parent process |
323 * @param connectionCallback will be called exactly once after the connectio n is set up or the | 319 * @param connectionCallback will be called exactly once after the connectio n is set up or the |
324 * setup fails | 320 * setup fails |
325 */ | 321 */ |
326 public void setupConnection(String[] commandLine, FileDescriptorInfo[] files ToBeMapped, | 322 public void setupConnection(Bundle connectionBundle, @Nullable IBinder callb ack, |
327 @Nullable IBinder callback, ConnectionCallback connectionCallback) { | 323 ConnectionCallback connectionCallback) { |
328 assert LauncherThread.runningOnLauncherThread(); | 324 assert LauncherThread.runningOnLauncherThread(); |
329 assert mConnectionParams == null; | 325 assert mConnectionParams == null; |
330 if (mServiceDisconnected) { | 326 if (mServiceDisconnected) { |
331 Log.w(TAG, "Tried to setup a connection that already disconnected.") ; | 327 Log.w(TAG, "Tried to setup a connection that already disconnected.") ; |
332 connectionCallback.onConnected(null); | 328 connectionCallback.onConnected(null); |
333 return; | 329 return; |
334 } | 330 } |
335 try { | 331 try { |
336 TraceEvent.begin("ChildProcessConnection.setupConnection"); | 332 TraceEvent.begin("ChildProcessConnection.setupConnection"); |
337 mConnectionCallback = connectionCallback; | 333 mConnectionCallback = connectionCallback; |
338 mConnectionParams = new ConnectionParams(commandLine, filesToBeMappe d, callback); | 334 mConnectionParams = new ConnectionParams(connectionBundle, callback) ; |
339 // Run the setup if the service is already connected. If not, | 335 // Run the setup if the service is already connected. If not, doConn ectionSetup() will |
340 // doConnectionSetupLocked() will be called from onServiceConnected( ). | 336 // be called from onServiceConnected(). |
341 if (mServiceConnectComplete) { | 337 if (mServiceConnectComplete) { |
342 doConnectionSetupLocked(); | 338 doConnectionSetup(); |
343 } | 339 } |
344 } finally { | 340 } finally { |
345 TraceEvent.end("ChildProcessConnection.setupConnection"); | 341 TraceEvent.end("ChildProcessConnection.setupConnection"); |
346 } | 342 } |
347 } | 343 } |
348 | 344 |
349 /** | 345 /** |
350 * Terminates the connection to IChildProcessService, closing all bindings. It is safe to call | 346 * Terminates the connection to IChildProcessService, closing all bindings. It is safe to call |
351 * this multiple times. | 347 * this multiple times. |
352 */ | 348 */ |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
392 } | 388 } |
393 } | 389 } |
394 | 390 |
395 if (!boundToUs) { | 391 if (!boundToUs) { |
396 return; | 392 return; |
397 } | 393 } |
398 | 394 |
399 mServiceConnectComplete = true; | 395 mServiceConnectComplete = true; |
400 | 396 |
401 // Run the setup if the connection parameters have already been prov ided. If | 397 // Run the setup if the connection parameters have already been prov ided. If |
402 // not, doConnectionSetupLocked() will be called from setupConnectio n(). | 398 // not, doConnectionSetup() will be called from setupConnection(). |
403 if (mConnectionParams != null) { | 399 if (mConnectionParams != null) { |
404 doConnectionSetupLocked(); | 400 doConnectionSetup(); |
405 } | 401 } |
406 } finally { | 402 } finally { |
407 TraceEvent.end("ChildProcessConnection.ChildServiceConnection.onServ iceConnected"); | 403 TraceEvent.end("ChildProcessConnection.ChildServiceConnection.onServ iceConnected"); |
408 } | 404 } |
409 } | 405 } |
410 | 406 |
411 private void onServiceDisconnectedOnLauncherThread() { | 407 private void onServiceDisconnectedOnLauncherThread() { |
412 assert LauncherThread.runningOnLauncherThread(); | 408 assert LauncherThread.runningOnLauncherThread(); |
413 // Ensure that the disconnection logic runs only once (instead of once p er each | 409 // Ensure that the disconnection logic runs only once (instead of once p er each |
414 // ChildServiceConnection). | 410 // ChildServiceConnection). |
(...skipping 18 matching lines...) Expand all Loading... | |
433 | 429 |
434 if (mConnectionCallback != null) { | 430 if (mConnectionCallback != null) { |
435 mConnectionCallback.onConnected(this); | 431 mConnectionCallback.onConnected(this); |
436 } | 432 } |
437 mConnectionCallback = null; | 433 mConnectionCallback = null; |
438 } | 434 } |
439 | 435 |
440 /** | 436 /** |
441 * Called after the connection parameters have been set (in setupConnection( )) *and* a | 437 * Called after the connection parameters have been set (in setupConnection( )) *and* a |
442 * connection has been established (as signaled by onServiceConnected()). Th ese two events can | 438 * connection has been established (as signaled by onServiceConnected()). Th ese two events can |
443 * happen in any order. Has to be called with mLock. | 439 * happen in any order. |
444 */ | 440 */ |
445 private void doConnectionSetupLocked() { | 441 private void doConnectionSetup() { |
446 try { | 442 try { |
447 TraceEvent.begin("ChildProcessConnection.doConnectionSetupLocked"); | 443 TraceEvent.begin("ChildProcessConnection.doConnectionSetup"); |
448 assert mServiceConnectComplete && mService != null; | 444 assert mServiceConnectComplete && mService != null; |
449 assert mConnectionParams != null; | 445 assert mConnectionParams != null; |
450 | 446 |
451 Bundle bundle = ChildProcessLauncher.createsServiceBundle( | |
452 mConnectionParams.mCommandLine, mConnectionParams.mFilesToBe Mapped); | |
453 ICallbackInt pidCallback = new ICallbackInt.Stub() { | 447 ICallbackInt pidCallback = new ICallbackInt.Stub() { |
454 @Override | 448 @Override |
455 public void call(final int pid) { | 449 public void call(final int pid) { |
456 LauncherThread.post(new Runnable() { | 450 LauncherThread.post(new Runnable() { |
457 @Override | 451 @Override |
458 public void run() { | 452 public void run() { |
459 onSetupConnectionResult(pid); | 453 onSetupConnectionResult(pid); |
460 } | 454 } |
461 }); | 455 }); |
462 } | 456 } |
463 }; | 457 }; |
464 try { | 458 try { |
465 mService.setupConnection(bundle, pidCallback, mConnectionParams. mCallback); | 459 mService.setupConnection( |
460 mConnectionParams.mBundle, pidCallback, mConnectionParam s.mCallback); | |
466 } catch (RemoteException re) { | 461 } catch (RemoteException re) { |
467 Log.e(TAG, "Failed to setup connection.", re); | 462 Log.e(TAG, "Failed to setup connection.", re); |
468 } | 463 } |
469 // We proactively close the FDs rather than wait for GC & finalizer. | |
470 try { | |
471 for (FileDescriptorInfo fileInfo : mConnectionParams.mFilesToBeM apped) { | |
472 fileInfo.fd.close(); | |
473 } | |
474 } catch (IOException ioe) { | |
475 Log.w(TAG, "Failed to close FD.", ioe); | |
476 } | |
477 mConnectionParams = null; | 464 mConnectionParams = null; |
478 } finally { | 465 } finally { |
479 TraceEvent.end("ChildProcessConnection.doConnectionSetupLocked"); | 466 TraceEvent.end("ChildProcessConnection.doConnectionSetup"); |
480 } | 467 } |
481 } | 468 } |
482 | 469 |
483 private boolean bind(boolean useStrongBinding) { | 470 private boolean bind(boolean useStrongBinding) { |
484 assert LauncherThread.runningOnLauncherThread(); | 471 assert LauncherThread.runningOnLauncherThread(); |
485 assert !mUnbound; | 472 assert !mUnbound; |
486 | 473 |
487 boolean success = useStrongBinding ? mStrongBinding.bind() : mInitialBin ding.bind(); | 474 boolean success = useStrongBinding ? mStrongBinding.bind() : mInitialBin ding.bind(); |
488 if (!success) return false; | 475 if (!success) return false; |
489 | 476 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
636 protected ChildServiceConnection createServiceConnection(int bindFlags) { | 623 protected ChildServiceConnection createServiceConnection(int bindFlags) { |
637 assert LauncherThread.runningOnLauncherThread(); | 624 assert LauncherThread.runningOnLauncherThread(); |
638 return new ChildServiceConnectionImpl(bindFlags); | 625 return new ChildServiceConnectionImpl(bindFlags); |
639 } | 626 } |
640 | 627 |
641 @VisibleForTesting | 628 @VisibleForTesting |
642 public void crashServiceForTesting() throws RemoteException { | 629 public void crashServiceForTesting() throws RemoteException { |
643 mService.crashIntentionallyForTesting(); | 630 mService.crashIntentionallyForTesting(); |
644 } | 631 } |
645 } | 632 } |
OLD | NEW |