| 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 mConnectionBundle; |
| 170 final FileDescriptorInfo[] mFilesToBeMapped; | |
| 171 final IBinder mCallback; | 168 final IBinder mCallback; |
| 172 | 169 |
| 173 ConnectionParams( | 170 ConnectionParams(Bundle connectionBundle, IBinder callback) { |
| 174 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, IBin
der callback) { | 171 mConnectionBundle = connectionBundle; |
| 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 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 // We have to notify the caller so that they can free-up associa
ted resources. | 303 // We have to notify the caller so that they can free-up associa
ted resources. |
| 309 // TODO(ppi): Can we hard-fail here? | 304 // TODO(ppi): Can we hard-fail here? |
| 310 mDeathCallback.onChildProcessDied(ChildProcessConnection.this); | 305 mDeathCallback.onChildProcessDied(ChildProcessConnection.this); |
| 311 } | 306 } |
| 312 } finally { | 307 } finally { |
| 313 TraceEvent.end("ChildProcessConnection.start"); | 308 TraceEvent.end("ChildProcessConnection.start"); |
| 314 } | 309 } |
| 315 } | 310 } |
| 316 | 311 |
| 317 /** | 312 /** |
| 318 * Setups the connection after it was started with start(). | 313 * 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() | 314 * @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 | 315 * parameters to the service |
| 321 * @param callback optional client specified callbacks that the child can us
e to communicate | 316 * @param callback optional client specified callbacks that the child can us
e to communicate |
| 322 * with the parent process | 317 * with the parent process |
| 323 * @param connectionCallback will be called exactly once after the connectio
n is set up or the | 318 * @param connectionCallback will be called exactly once after the connectio
n is set up or the |
| 324 * setup fails | 319 * setup fails |
| 325 */ | 320 */ |
| 326 public void setupConnection(String[] commandLine, FileDescriptorInfo[] files
ToBeMapped, | 321 public void setupConnection(Bundle connectionBundle, @Nullable IBinder callb
ack, |
| 327 @Nullable IBinder callback, ConnectionCallback connectionCallback) { | 322 ConnectionCallback connectionCallback) { |
| 328 assert LauncherThread.runningOnLauncherThread(); | 323 assert LauncherThread.runningOnLauncherThread(); |
| 329 assert mConnectionParams == null; | 324 assert mConnectionParams == null; |
| 330 if (mServiceDisconnected) { | 325 if (mServiceDisconnected) { |
| 331 Log.w(TAG, "Tried to setup a connection that already disconnected.")
; | 326 Log.w(TAG, "Tried to setup a connection that already disconnected.")
; |
| 332 connectionCallback.onConnected(null); | 327 connectionCallback.onConnected(null); |
| 333 return; | 328 return; |
| 334 } | 329 } |
| 335 try { | 330 try { |
| 336 TraceEvent.begin("ChildProcessConnection.setupConnection"); | 331 TraceEvent.begin("ChildProcessConnection.setupConnection"); |
| 337 mConnectionCallback = connectionCallback; | 332 mConnectionCallback = connectionCallback; |
| 338 mConnectionParams = new ConnectionParams(commandLine, filesToBeMappe
d, callback); | 333 mConnectionParams = new ConnectionParams(connectionBundle, callback)
; |
| 339 // Run the setup if the service is already connected. If not, | 334 // Run the setup if the service is already connected. If not, doConn
ectionSetup() will |
| 340 // doConnectionSetupLocked() will be called from onServiceConnected(
). | 335 // be called from onServiceConnected(). |
| 341 if (mServiceConnectComplete) { | 336 if (mServiceConnectComplete) { |
| 342 doConnectionSetupLocked(); | 337 doConnectionSetup(); |
| 343 } | 338 } |
| 344 } finally { | 339 } finally { |
| 345 TraceEvent.end("ChildProcessConnection.setupConnection"); | 340 TraceEvent.end("ChildProcessConnection.setupConnection"); |
| 346 } | 341 } |
| 347 } | 342 } |
| 348 | 343 |
| 349 /** | 344 /** |
| 350 * Terminates the connection to IChildProcessService, closing all bindings.
It is safe to call | 345 * Terminates the connection to IChildProcessService, closing all bindings.
It is safe to call |
| 351 * this multiple times. | 346 * this multiple times. |
| 352 */ | 347 */ |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 } | 387 } |
| 393 } | 388 } |
| 394 | 389 |
| 395 if (!boundToUs) { | 390 if (!boundToUs) { |
| 396 return; | 391 return; |
| 397 } | 392 } |
| 398 | 393 |
| 399 mServiceConnectComplete = true; | 394 mServiceConnectComplete = true; |
| 400 | 395 |
| 401 // Run the setup if the connection parameters have already been prov
ided. If | 396 // Run the setup if the connection parameters have already been prov
ided. If |
| 402 // not, doConnectionSetupLocked() will be called from setupConnectio
n(). | 397 // not, doConnectionSetup() will be called from setupConnection(). |
| 403 if (mConnectionParams != null) { | 398 if (mConnectionParams != null) { |
| 404 doConnectionSetupLocked(); | 399 doConnectionSetup(); |
| 405 } | 400 } |
| 406 } finally { | 401 } finally { |
| 407 TraceEvent.end("ChildProcessConnection.ChildServiceConnection.onServ
iceConnected"); | 402 TraceEvent.end("ChildProcessConnection.ChildServiceConnection.onServ
iceConnected"); |
| 408 } | 403 } |
| 409 } | 404 } |
| 410 | 405 |
| 411 private void onServiceDisconnectedOnLauncherThread() { | 406 private void onServiceDisconnectedOnLauncherThread() { |
| 412 assert LauncherThread.runningOnLauncherThread(); | 407 assert LauncherThread.runningOnLauncherThread(); |
| 413 // Ensure that the disconnection logic runs only once (instead of once p
er each | 408 // Ensure that the disconnection logic runs only once (instead of once p
er each |
| 414 // ChildServiceConnection). | 409 // ChildServiceConnection). |
| (...skipping 18 matching lines...) Expand all Loading... |
| 433 | 428 |
| 434 if (mConnectionCallback != null) { | 429 if (mConnectionCallback != null) { |
| 435 mConnectionCallback.onConnected(this); | 430 mConnectionCallback.onConnected(this); |
| 436 } | 431 } |
| 437 mConnectionCallback = null; | 432 mConnectionCallback = null; |
| 438 } | 433 } |
| 439 | 434 |
| 440 /** | 435 /** |
| 441 * Called after the connection parameters have been set (in setupConnection(
)) *and* a | 436 * 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 | 437 * connection has been established (as signaled by onServiceConnected()). Th
ese two events can |
| 443 * happen in any order. Has to be called with mLock. | 438 * happen in any order. |
| 444 */ | 439 */ |
| 445 private void doConnectionSetupLocked() { | 440 private void doConnectionSetup() { |
| 446 try { | 441 try { |
| 447 TraceEvent.begin("ChildProcessConnection.doConnectionSetupLocked"); | 442 TraceEvent.begin("ChildProcessConnection.doConnectionSetup"); |
| 448 assert mServiceConnectComplete && mService != null; | 443 assert mServiceConnectComplete && mService != null; |
| 449 assert mConnectionParams != null; | 444 assert mConnectionParams != null; |
| 450 | 445 |
| 451 Bundle bundle = ChildProcessLauncher.createsServiceBundle( | |
| 452 mConnectionParams.mCommandLine, mConnectionParams.mFilesToBe
Mapped); | |
| 453 ICallbackInt pidCallback = new ICallbackInt.Stub() { | 446 ICallbackInt pidCallback = new ICallbackInt.Stub() { |
| 454 @Override | 447 @Override |
| 455 public void call(final int pid) { | 448 public void call(final int pid) { |
| 456 LauncherThread.post(new Runnable() { | 449 LauncherThread.post(new Runnable() { |
| 457 @Override | 450 @Override |
| 458 public void run() { | 451 public void run() { |
| 459 onSetupConnectionResult(pid); | 452 onSetupConnectionResult(pid); |
| 460 } | 453 } |
| 461 }); | 454 }); |
| 462 } | 455 } |
| 463 }; | 456 }; |
| 464 try { | 457 try { |
| 465 mService.setupConnection(bundle, pidCallback, mConnectionParams.
mCallback); | 458 mService.setupConnection(mConnectionParams.mConnectionBundle, pi
dCallback, |
| 459 mConnectionParams.mCallback); |
| 466 } catch (RemoteException re) { | 460 } catch (RemoteException re) { |
| 467 Log.e(TAG, "Failed to setup connection.", re); | 461 Log.e(TAG, "Failed to setup connection.", re); |
| 468 } | 462 } |
| 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; | 463 mConnectionParams = null; |
| 478 } finally { | 464 } finally { |
| 479 TraceEvent.end("ChildProcessConnection.doConnectionSetupLocked"); | 465 TraceEvent.end("ChildProcessConnection.doConnectionSetup"); |
| 480 } | 466 } |
| 481 } | 467 } |
| 482 | 468 |
| 483 private boolean bind(boolean useStrongBinding) { | 469 private boolean bind(boolean useStrongBinding) { |
| 484 assert LauncherThread.runningOnLauncherThread(); | 470 assert LauncherThread.runningOnLauncherThread(); |
| 485 assert !mUnbound; | 471 assert !mUnbound; |
| 486 | 472 |
| 487 boolean success = useStrongBinding ? mStrongBinding.bind() : mInitialBin
ding.bind(); | 473 boolean success = useStrongBinding ? mStrongBinding.bind() : mInitialBin
ding.bind(); |
| 488 if (!success) return false; | 474 if (!success) return false; |
| 489 | 475 |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 protected ChildServiceConnection createServiceConnection(int bindFlags) { | 622 protected ChildServiceConnection createServiceConnection(int bindFlags) { |
| 637 assert LauncherThread.runningOnLauncherThread(); | 623 assert LauncherThread.runningOnLauncherThread(); |
| 638 return new ChildServiceConnectionImpl(bindFlags); | 624 return new ChildServiceConnectionImpl(bindFlags); |
| 639 } | 625 } |
| 640 | 626 |
| 641 @VisibleForTesting | 627 @VisibleForTesting |
| 642 public void crashServiceForTesting() throws RemoteException { | 628 public void crashServiceForTesting() throws RemoteException { |
| 643 mService.crashIntentionallyForTesting(); | 629 mService.crashIntentionallyForTesting(); |
| 644 } | 630 } |
| 645 } | 631 } |
| OLD | NEW |