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 |