| 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; | 22 import org.chromium.base.process_launcher.FileDescriptorInfo; |
| 23 import org.chromium.base.process_launcher.ICallbackInt; | 23 import org.chromium.base.process_launcher.ICallbackInt; |
| 24 import org.chromium.base.process_launcher.IChildProcessService; | 24 import org.chromium.base.process_launcher.IChildProcessService; |
| 25 | 25 |
| 26 import java.io.IOException; | 26 import java.io.IOException; |
| 27 | 27 |
| 28 import javax.annotation.Nullable; | 28 import javax.annotation.Nullable; |
| 29 import javax.annotation.concurrent.GuardedBy; | |
| 30 | 29 |
| 31 /** | 30 /** |
| 32 * Manages a connection between the browser activity and a child service. | 31 * Manages a connection between the browser activity and a child service. |
| 33 */ | 32 */ |
| 34 public abstract class BaseChildProcessConnection { | 33 public abstract class BaseChildProcessConnection { |
| 35 private static final String TAG = "BaseChildProcessConn"; | 34 private static final String TAG = "BaseChildProcessConn"; |
| 36 | 35 |
| 37 /** | 36 /** |
| 38 * Used to notify the consumer about disconnection of the service. This call
back is provided | 37 * Used to notify the consumer about disconnection of the service. This call
back is provided |
| 39 * earlier than ConnectionCallbacks below, as a child process might die befo
re the connection is | 38 * earlier than ConnectionCallbacks below, as a child process might die befo
re the connection is |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 final IBinder mCallback; | 180 final IBinder mCallback; |
| 182 | 181 |
| 183 ConnectionParams( | 182 ConnectionParams( |
| 184 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, IBin
der callback) { | 183 String[] commandLine, FileDescriptorInfo[] filesToBeMapped, IBin
der callback) { |
| 185 mCommandLine = commandLine; | 184 mCommandLine = commandLine; |
| 186 mFilesToBeMapped = filesToBeMapped; | 185 mFilesToBeMapped = filesToBeMapped; |
| 187 mCallback = callback; | 186 mCallback = callback; |
| 188 } | 187 } |
| 189 } | 188 } |
| 190 | 189 |
| 191 // Synchronization: While most internal flow occurs on the UI thread, the pu
blic API | |
| 192 // (specifically start and stop) may be called from any thread, hence all en
try point methods | |
| 193 // into the class are synchronized on the lock to protect access to these me
mbers. | |
| 194 // TODO(jcivelli): crbug.com/714657 remove this lock. | |
| 195 private final Object mLock = new Object(); | |
| 196 | |
| 197 // This is set in start() and is used in onServiceConnected(). | 190 // This is set in start() and is used in onServiceConnected(). |
| 198 @GuardedBy("mLock") | |
| 199 private StartCallback mStartCallback; | 191 private StartCallback mStartCallback; |
| 200 | 192 |
| 201 // This is set in setupConnection() and is later used in doConnectionSetupLo
cked(), after which | 193 // This is set in setupConnection() and is later used in doConnectionSetupLo
cked(), after which |
| 202 // the variable is cleared. Therefore this is only valid while the connectio
n is being set up. | 194 // the variable is cleared. Therefore this is only valid while the connectio
n is being set up. |
| 203 @GuardedBy("mLock") | |
| 204 private ConnectionParams mConnectionParams; | 195 private ConnectionParams mConnectionParams; |
| 205 | 196 |
| 206 // Callback provided in setupConnection() that will communicate the result t
o the caller. This | 197 // Callback provided in setupConnection() that will communicate the result t
o the caller. This |
| 207 // has to be called exactly once after setupConnection(), even if setup fail
s, so that the | 198 // has to be called exactly once after setupConnection(), even if setup fail
s, so that the |
| 208 // caller can free up resources associated with the setup attempt. This is s
et to null after the | 199 // caller can free up resources associated with the setup attempt. This is s
et to null after the |
| 209 // call. | 200 // call. |
| 210 @GuardedBy("mLock") | |
| 211 private ConnectionCallback mConnectionCallback; | 201 private ConnectionCallback mConnectionCallback; |
| 212 | 202 |
| 213 @GuardedBy("mLock") | |
| 214 private IChildProcessService mService; | 203 private IChildProcessService mService; |
| 215 | 204 |
| 216 // Set to true when the service connection callback runs. This differs from | 205 // Set to true when the service connection callback runs. This differs from |
| 217 // mServiceConnectComplete, which tracks that the connection completed succe
ssfully. | 206 // mServiceConnectComplete, which tracks that the connection completed succe
ssfully. |
| 218 @GuardedBy("mLock") | |
| 219 private boolean mDidOnServiceConnected; | 207 private boolean mDidOnServiceConnected; |
| 220 | 208 |
| 221 // Set to true when the service connected successfully. | 209 // Set to true when the service connected successfully. |
| 222 @GuardedBy("mLock") | |
| 223 private boolean mServiceConnectComplete; | 210 private boolean mServiceConnectComplete; |
| 224 | 211 |
| 225 // Set to true when the service disconnects, as opposed to being properly cl
osed. This happens | 212 // Set to true when the service disconnects, as opposed to being properly cl
osed. This happens |
| 226 // when the process crashes or gets killed by the system out-of-memory kille
r. | 213 // when the process crashes or gets killed by the system out-of-memory kille
r. |
| 227 @GuardedBy("mLock") | |
| 228 private boolean mServiceDisconnected; | 214 private boolean mServiceDisconnected; |
| 229 | 215 |
| 230 // Process ID of the corresponding child process. | 216 // Process ID of the corresponding child process. |
| 231 @GuardedBy("mLock") | |
| 232 private int mPid; | 217 private int mPid; |
| 233 | 218 |
| 234 protected BaseChildProcessConnection(Context context, int number, boolean sa
ndboxed, | 219 protected BaseChildProcessConnection(Context context, int number, boolean sa
ndboxed, |
| 235 DeathCallback deathCallback, String serviceClassName, | 220 DeathCallback deathCallback, String serviceClassName, |
| 236 Bundle childProcessCommonParameters, ChildProcessCreationParams crea
tionParams) { | 221 Bundle childProcessCommonParameters, ChildProcessCreationParams crea
tionParams) { |
| 222 assert LauncherThread.runningOnLauncherThread(); |
| 237 mContext = context; | 223 mContext = context; |
| 238 mServiceNumber = number; | 224 mServiceNumber = number; |
| 239 mSandboxed = sandboxed; | 225 mSandboxed = sandboxed; |
| 240 mDeathCallback = deathCallback; | 226 mDeathCallback = deathCallback; |
| 241 String packageName = | 227 String packageName = |
| 242 creationParams != null ? creationParams.getPackageName() : conte
xt.getPackageName(); | 228 creationParams != null ? creationParams.getPackageName() : conte
xt.getPackageName(); |
| 243 mServiceName = new ComponentName(packageName, serviceClassName + mServic
eNumber); | 229 mServiceName = new ComponentName(packageName, serviceClassName + mServic
eNumber); |
| 244 mChildProcessCommonParameters = childProcessCommonParameters; | 230 mChildProcessCommonParameters = childProcessCommonParameters; |
| 245 mCreationParams = creationParams; | 231 mCreationParams = creationParams; |
| 246 } | 232 } |
| 247 | 233 |
| 248 public final Context getContext() { | 234 public final Context getContext() { |
| 235 assert LauncherThread.runningOnLauncherThread(); |
| 249 return mContext; | 236 return mContext; |
| 250 } | 237 } |
| 251 | 238 |
| 252 public final int getServiceNumber() { | 239 public final int getServiceNumber() { |
| 240 assert LauncherThread.runningOnLauncherThread(); |
| 253 return mServiceNumber; | 241 return mServiceNumber; |
| 254 } | 242 } |
| 255 | 243 |
| 256 public final boolean isSandboxed() { | 244 public final boolean isSandboxed() { |
| 245 assert LauncherThread.runningOnLauncherThread(); |
| 257 return mSandboxed; | 246 return mSandboxed; |
| 258 } | 247 } |
| 259 | 248 |
| 260 public final String getPackageName() { | 249 public final String getPackageName() { |
| 250 assert LauncherThread.runningOnLauncherThread(); |
| 261 return mCreationParams != null ? mCreationParams.getPackageName() | 251 return mCreationParams != null ? mCreationParams.getPackageName() |
| 262 : mContext.getPackageName(); | 252 : mContext.getPackageName(); |
| 263 } | 253 } |
| 264 | 254 |
| 265 public final ChildProcessCreationParams getCreationParams() { | 255 public final ChildProcessCreationParams getCreationParams() { |
| 256 assert LauncherThread.runningOnLauncherThread(); |
| 266 return mCreationParams; | 257 return mCreationParams; |
| 267 } | 258 } |
| 268 | 259 |
| 269 public final IChildProcessService getService() { | 260 public final IChildProcessService getService() { |
| 270 synchronized (mLock) { | 261 assert LauncherThread.runningOnLauncherThread(); |
| 271 return mService; | 262 return mService; |
| 272 } | |
| 273 } | 263 } |
| 274 | 264 |
| 275 public final ComponentName getServiceName() { | 265 public final ComponentName getServiceName() { |
| 266 assert LauncherThread.runningOnLauncherThread(); |
| 276 return mServiceName; | 267 return mServiceName; |
| 277 } | 268 } |
| 278 | 269 |
| 279 /** | 270 /** |
| 280 * @return the connection pid, or 0 if not yet connected | 271 * @return the connection pid, or 0 if not yet connected |
| 281 */ | 272 */ |
| 282 public int getPid() { | 273 public int getPid() { |
| 283 synchronized (mLock) { | 274 assert LauncherThread.runningOnLauncherThread(); |
| 284 return mPid; | 275 return mPid; |
| 285 } | |
| 286 } | 276 } |
| 287 | 277 |
| 288 /** | 278 /** |
| 289 * Starts a connection to an IChildProcessService. This must be followed by
a call to | 279 * Starts a connection to an IChildProcessService. This must be followed by
a call to |
| 290 * setupConnection() to setup the connection parameters. start() and setupCo
nnection() are | 280 * setupConnection() to setup the connection parameters. start() and setupCo
nnection() are |
| 291 * separate to allow to pass whatever parameters are available in start(), a
nd complete the | 281 * separate to allow to pass whatever parameters are available in start(), a
nd complete the |
| 292 * remainder later while reducing the connection setup latency. | 282 * remainder later while reducing the connection setup latency. |
| 293 * @param startCallback (optional) callback when the child process starts or
fails to start. | 283 * @param startCallback (optional) callback when the child process starts or
fails to start. |
| 294 */ | 284 */ |
| 295 public void start(StartCallback startCallback) { | 285 public void start(StartCallback startCallback) { |
| 286 assert LauncherThread.runningOnLauncherThread(); |
| 296 try { | 287 try { |
| 297 TraceEvent.begin("BaseChildProcessConnection.start"); | 288 TraceEvent.begin("BaseChildProcessConnection.start"); |
| 298 assert LauncherThread.runningOnLauncherThread(); | 289 assert LauncherThread.runningOnLauncherThread(); |
| 299 synchronized (mLock) { | 290 assert mConnectionParams |
| 300 assert mConnectionParams | 291 == null |
| 301 == null | 292 : "setupConnection() called before start() in BaseChildProce
ssConnection."; |
| 302 : "setupConnection() called before start() in BaseChildP
rocessConnection."; | |
| 303 | 293 |
| 304 mStartCallback = startCallback; | 294 mStartCallback = startCallback; |
| 305 | 295 |
| 306 if (!bind()) { | 296 if (!bind()) { |
| 307 Log.e(TAG, "Failed to establish the service connection."); | 297 Log.e(TAG, "Failed to establish the service connection."); |
| 308 // We have to notify the caller so that they can free-up ass
ociated resources. | 298 // We have to notify the caller so that they can free-up associa
ted resources. |
| 309 // TODO(ppi): Can we hard-fail here? | 299 // TODO(ppi): Can we hard-fail here? |
| 310 mDeathCallback.onChildProcessDied(BaseChildProcessConnection
.this); | 300 mDeathCallback.onChildProcessDied(BaseChildProcessConnection.thi
s); |
| 311 } | |
| 312 } | 301 } |
| 313 } finally { | 302 } finally { |
| 314 TraceEvent.end("BaseChildProcessConnection.start"); | 303 TraceEvent.end("BaseChildProcessConnection.start"); |
| 315 } | 304 } |
| 316 } | 305 } |
| 317 | 306 |
| 318 /** | 307 /** |
| 319 * Setups the connection after it was started with start(). | 308 * Setups the connection after it was started with start(). |
| 320 * @param commandLine (optional) will be ignored if the command line was alr
eady sent in start() | 309 * @param commandLine (optional) will be ignored if the command line was alr
eady sent in start() |
| 321 * @param filesToBeMapped a list of file descriptors that should be register
ed | 310 * @param filesToBeMapped a list of file descriptors that should be register
ed |
| 322 * @param callback optional client specified callbacks that the child can us
e to communicate | 311 * @param callback optional client specified callbacks that the child can us
e to communicate |
| 323 * with the parent process | 312 * with the parent process |
| 324 * @param connectionCallback will be called exactly once after the connectio
n is set up or the | 313 * @param connectionCallback will be called exactly once after the connectio
n is set up or the |
| 325 * setup fails | 314 * setup fails |
| 326 */ | 315 */ |
| 327 public void setupConnection(String[] commandLine, FileDescriptorInfo[] files
ToBeMapped, | 316 public void setupConnection(String[] commandLine, FileDescriptorInfo[] files
ToBeMapped, |
| 328 @Nullable IBinder callback, ConnectionCallback connectionCallback) { | 317 @Nullable IBinder callback, ConnectionCallback connectionCallback) { |
| 329 assert LauncherThread.runningOnLauncherThread(); | 318 assert LauncherThread.runningOnLauncherThread(); |
| 330 synchronized (mLock) { | 319 assert mConnectionParams == null; |
| 331 assert mConnectionParams == null; | 320 if (mServiceDisconnected) { |
| 332 if (mServiceDisconnected) { | 321 Log.w(TAG, "Tried to setup a connection that already disconnected.")
; |
| 333 Log.w(TAG, "Tried to setup a connection that already disconnecte
d."); | 322 connectionCallback.onConnected(null); |
| 334 connectionCallback.onConnected(null); | 323 return; |
| 335 return; | 324 } |
| 325 try { |
| 326 TraceEvent.begin("BaseChildProcessConnection.setupConnection"); |
| 327 mConnectionCallback = connectionCallback; |
| 328 mConnectionParams = new ConnectionParams(commandLine, filesToBeMappe
d, callback); |
| 329 // Run the setup if the service is already connected. If not, |
| 330 // doConnectionSetupLocked() will be called from onServiceConnected(
). |
| 331 if (mServiceConnectComplete) { |
| 332 doConnectionSetupLocked(); |
| 336 } | 333 } |
| 337 try { | 334 } finally { |
| 338 TraceEvent.begin("BaseChildProcessConnection.setupConnection"); | 335 TraceEvent.end("BaseChildProcessConnection.setupConnection"); |
| 339 mConnectionCallback = connectionCallback; | |
| 340 mConnectionParams = new ConnectionParams(commandLine, filesToBeM
apped, callback); | |
| 341 // Run the setup if the service is already connected. If not, | |
| 342 // doConnectionSetupLocked() will be called from onServiceConnec
ted(). | |
| 343 if (mServiceConnectComplete) { | |
| 344 doConnectionSetupLocked(); | |
| 345 } | |
| 346 } finally { | |
| 347 TraceEvent.end("BaseChildProcessConnection.setupConnection"); | |
| 348 } | |
| 349 } | 336 } |
| 350 } | 337 } |
| 351 | 338 |
| 352 /** | 339 /** |
| 353 * Terminates the connection to IChildProcessService, closing all bindings.
It is safe to call | 340 * Terminates the connection to IChildProcessService, closing all bindings.
It is safe to call |
| 354 * this multiple times. | 341 * this multiple times. |
| 355 */ | 342 */ |
| 356 public void stop() { | 343 public void stop() { |
| 357 synchronized (mLock) { | 344 assert LauncherThread.runningOnLauncherThread(); |
| 358 unbind(); | 345 unbind(); |
| 359 mService = null; | 346 mService = null; |
| 360 mConnectionParams = null; | 347 mConnectionParams = null; |
| 361 } | |
| 362 } | 348 } |
| 363 | 349 |
| 364 private void onServiceConnectedOnLauncherThread(IBinder service) { | 350 private void onServiceConnectedOnLauncherThread(IBinder service) { |
| 365 assert LauncherThread.runningOnLauncherThread(); | 351 assert LauncherThread.runningOnLauncherThread(); |
| 366 synchronized (mLock) { | 352 // A flag from the parent class ensures we run the post-connection logic
only once |
| 367 // A flag from the parent class ensures we run the post-connection l
ogic only once | 353 // (instead of once per each ChildServiceConnection). |
| 368 // (instead of once per each ChildServiceConnection). | 354 if (mDidOnServiceConnected) { |
| 369 if (mDidOnServiceConnected) { | 355 return; |
| 356 } |
| 357 try { |
| 358 TraceEvent.begin( |
| 359 "BaseChildProcessConnection.ChildServiceConnection.onService
Connected"); |
| 360 mDidOnServiceConnected = true; |
| 361 mService = IChildProcessService.Stub.asInterface(service); |
| 362 |
| 363 StartCallback startCallback = mStartCallback; |
| 364 mStartCallback = null; |
| 365 |
| 366 final boolean bindCheck = |
| 367 mCreationParams != null && mCreationParams.getBindToCallerCh
eck(); |
| 368 boolean boundToUs = false; |
| 369 try { |
| 370 boundToUs = bindCheck ? mService.bindToCaller() : true; |
| 371 } catch (RemoteException ex) { |
| 372 // Do not trigger the StartCallback here, since the service is a
lready |
| 373 // dead and the DeathCallback will run from onServiceDisconnecte
d(). |
| 374 Log.e(TAG, "Failed to bind service to connection.", ex); |
| 370 return; | 375 return; |
| 371 } | 376 } |
| 372 try { | |
| 373 TraceEvent.begin( | |
| 374 "BaseChildProcessConnection.ChildServiceConnection.onSer
viceConnected"); | |
| 375 mDidOnServiceConnected = true; | |
| 376 mService = IChildProcessService.Stub.asInterface(service); | |
| 377 | 377 |
| 378 StartCallback startCallback = mStartCallback; | 378 if (startCallback != null) { |
| 379 mStartCallback = null; | 379 if (boundToUs) { |
| 380 startCallback.onChildStarted(); |
| 381 } else { |
| 382 startCallback.onChildStartFailed(); |
| 383 } |
| 384 } |
| 380 | 385 |
| 381 final boolean bindCheck = | 386 if (!boundToUs) { |
| 382 mCreationParams != null && mCreationParams.getBindToCall
erCheck(); | 387 return; |
| 383 boolean boundToUs = false; | 388 } |
| 384 try { | |
| 385 boundToUs = bindCheck ? mService.bindToCaller() : true; | |
| 386 } catch (RemoteException ex) { | |
| 387 // Do not trigger the StartCallback here, since the service
is already | |
| 388 // dead and the DeathCallback will run from onServiceDisconn
ected(). | |
| 389 Log.e(TAG, "Failed to bind service to connection.", ex); | |
| 390 return; | |
| 391 } | |
| 392 | 389 |
| 393 if (startCallback != null) { | 390 mServiceConnectComplete = true; |
| 394 if (boundToUs) { | |
| 395 startCallback.onChildStarted(); | |
| 396 } else { | |
| 397 startCallback.onChildStartFailed(); | |
| 398 } | |
| 399 } | |
| 400 | 391 |
| 401 if (!boundToUs) { | 392 // Run the setup if the connection parameters have already been prov
ided. If |
| 402 return; | 393 // not, doConnectionSetupLocked() will be called from setupConnectio
n(). |
| 403 } | 394 if (mConnectionParams != null) { |
| 404 | 395 doConnectionSetupLocked(); |
| 405 mServiceConnectComplete = true; | |
| 406 | |
| 407 // Run the setup if the connection parameters have already been
provided. If | |
| 408 // not, doConnectionSetupLocked() will be called from setupConne
ction(). | |
| 409 if (mConnectionParams != null) { | |
| 410 doConnectionSetupLocked(); | |
| 411 } | |
| 412 } finally { | |
| 413 TraceEvent.end( | |
| 414 "BaseChildProcessConnection.ChildServiceConnection.onSer
viceConnected"); | |
| 415 } | 396 } |
| 397 } finally { |
| 398 TraceEvent.end("BaseChildProcessConnection.ChildServiceConnection.on
ServiceConnected"); |
| 416 } | 399 } |
| 417 } | 400 } |
| 418 | 401 |
| 419 private void onServiceDisconnectedOnLauncherThread() { | 402 private void onServiceDisconnectedOnLauncherThread() { |
| 420 assert LauncherThread.runningOnLauncherThread(); | 403 assert LauncherThread.runningOnLauncherThread(); |
| 421 synchronized (mLock) { | 404 // Ensure that the disconnection logic runs only once (instead of once p
er each |
| 422 // Ensure that the disconnection logic runs only once (instead of on
ce per each | 405 // ChildServiceConnection). |
| 423 // ChildServiceConnection). | 406 if (mServiceDisconnected) { |
| 424 if (mServiceDisconnected) { | 407 return; |
| 425 return; | |
| 426 } | |
| 427 mServiceDisconnected = true; | |
| 428 Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d",
mPid); | |
| 429 stop(); // We don't want to auto-restart on crash. Let the browser d
o that. | |
| 430 mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); | |
| 431 // If we have a pending connection callback, we need to communicate
the failure to | |
| 432 // the caller. | |
| 433 if (mConnectionCallback != null) { | |
| 434 mConnectionCallback.onConnected(null); | |
| 435 } | |
| 436 mConnectionCallback = null; | |
| 437 } | 408 } |
| 409 mServiceDisconnected = true; |
| 410 Log.w(TAG, "onServiceDisconnected (crash or killed by oom): pid=%d", mPi
d); |
| 411 stop(); // We don't want to auto-restart on crash. Let the browser do th
at. |
| 412 mDeathCallback.onChildProcessDied(BaseChildProcessConnection.this); |
| 413 // If we have a pending connection callback, we need to communicate the
failure to |
| 414 // the caller. |
| 415 if (mConnectionCallback != null) { |
| 416 mConnectionCallback.onConnected(null); |
| 417 } |
| 418 mConnectionCallback = null; |
| 438 } | 419 } |
| 439 | 420 |
| 440 private void onSetupConnectionResult(int pid) { | 421 private void onSetupConnectionResult(int pid) { |
| 441 synchronized (mLock) { | 422 mPid = pid; |
| 442 mPid = pid; | 423 assert mPid != 0 : "Child service claims to be run by a process of pid=0
."; |
| 443 assert mPid != 0 : "Child service claims to be run by a process of p
id=0."; | |
| 444 | 424 |
| 445 if (mConnectionCallback != null) { | 425 if (mConnectionCallback != null) { |
| 446 mConnectionCallback.onConnected(this); | 426 mConnectionCallback.onConnected(this); |
| 447 } | |
| 448 mConnectionCallback = null; | |
| 449 } | 427 } |
| 428 mConnectionCallback = null; |
| 450 } | 429 } |
| 451 | 430 |
| 452 /** | 431 /** |
| 453 * Called after the connection parameters have been set (in setupConnection(
)) *and* a | 432 * Called after the connection parameters have been set (in setupConnection(
)) *and* a |
| 454 * connection has been established (as signaled by onServiceConnected()). Th
ese two events can | 433 * connection has been established (as signaled by onServiceConnected()). Th
ese two events can |
| 455 * happen in any order. Has to be called with mLock. | 434 * happen in any order. Has to be called with mLock. |
| 456 */ | 435 */ |
| 457 @GuardedBy("mLock") | |
| 458 private void doConnectionSetupLocked() { | 436 private void doConnectionSetupLocked() { |
| 459 try { | 437 try { |
| 460 TraceEvent.begin("BaseChildProcessConnection.doConnectionSetupLocked
"); | 438 TraceEvent.begin("BaseChildProcessConnection.doConnectionSetupLocked
"); |
| 461 assert mServiceConnectComplete && mService != null; | 439 assert mServiceConnectComplete && mService != null; |
| 462 assert mConnectionParams != null; | 440 assert mConnectionParams != null; |
| 463 | 441 |
| 464 Bundle bundle = ChildProcessLauncher.createsServiceBundle( | 442 Bundle bundle = ChildProcessLauncher.createsServiceBundle( |
| 465 mConnectionParams.mCommandLine, mConnectionParams.mFilesToBe
Mapped); | 443 mConnectionParams.mCommandLine, mConnectionParams.mFilesToBe
Mapped); |
| 466 ICallbackInt pidCallback = new ICallbackInt.Stub() { | 444 ICallbackInt pidCallback = new ICallbackInt.Stub() { |
| 467 @Override | 445 @Override |
| (...skipping 23 matching lines...) Expand all Loading... |
| 491 } finally { | 469 } finally { |
| 492 TraceEvent.end("BaseChildProcessConnection.doConnectionSetupLocked")
; | 470 TraceEvent.end("BaseChildProcessConnection.doConnectionSetupLocked")
; |
| 493 } | 471 } |
| 494 } | 472 } |
| 495 | 473 |
| 496 /** Subclasses should implement this method to bind/unbind to the actual ser
vice. */ | 474 /** Subclasses should implement this method to bind/unbind to the actual ser
vice. */ |
| 497 protected abstract boolean bind(); | 475 protected abstract boolean bind(); |
| 498 protected abstract void unbind(); | 476 protected abstract void unbind(); |
| 499 | 477 |
| 500 protected ChildServiceConnection createServiceConnection(int bindFlags) { | 478 protected ChildServiceConnection createServiceConnection(int bindFlags) { |
| 479 assert LauncherThread.runningOnLauncherThread(); |
| 501 return new ChildServiceConnectionImpl(bindFlags); | 480 return new ChildServiceConnectionImpl(bindFlags); |
| 502 } | 481 } |
| 503 | 482 |
| 504 protected boolean shouldBindAsExportedService() { | 483 protected boolean shouldBindAsExportedService() { |
| 484 assert LauncherThread.runningOnLauncherThread(); |
| 505 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getCreationPara
ms() != null | 485 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && getCreationPara
ms() != null |
| 506 && getCreationParams().getIsExternalService() | 486 && getCreationParams().getIsExternalService() |
| 507 && isExportedService(isSandboxed(), getContext(), getServiceName
()); | 487 && isExportedService(isSandboxed(), getContext(), getServiceName
()); |
| 508 } | 488 } |
| 509 | 489 |
| 510 private static boolean isExportedService( | 490 private static boolean isExportedService( |
| 511 boolean inSandbox, Context context, ComponentName serviceName) { | 491 boolean inSandbox, Context context, ComponentName serviceName) { |
| 512 // Check for the cached value first. It is assumed that all pooled child
services | 492 // Check for the cached value first. It is assumed that all pooled child
services |
| 513 // have identical attributes in the manifest. | 493 // have identical attributes in the manifest. |
| 514 final int arrayIndex = inSandbox ? 1 : 0; | 494 final int arrayIndex = inSandbox ? 1 : 0; |
| 515 if (sNeedsExtrabindFlags[arrayIndex] != null) { | 495 if (sNeedsExtrabindFlags[arrayIndex] != null) { |
| 516 return sNeedsExtrabindFlags[arrayIndex].booleanValue(); | 496 return sNeedsExtrabindFlags[arrayIndex].booleanValue(); |
| 517 } | 497 } |
| 518 boolean result = false; | 498 boolean result = false; |
| 519 try { | 499 try { |
| 520 PackageManager packageManager = context.getPackageManager(); | 500 PackageManager packageManager = context.getPackageManager(); |
| 521 ServiceInfo serviceInfo = packageManager.getServiceInfo(serviceName,
0); | 501 ServiceInfo serviceInfo = packageManager.getServiceInfo(serviceName,
0); |
| 522 result = serviceInfo.exported; | 502 result = serviceInfo.exported; |
| 523 } catch (PackageManager.NameNotFoundException e) { | 503 } catch (PackageManager.NameNotFoundException e) { |
| 524 Log.e(TAG, "Could not retrieve info about service %s", serviceName,
e); | 504 Log.e(TAG, "Could not retrieve info about service %s", serviceName,
e); |
| 525 } | 505 } |
| 526 sNeedsExtrabindFlags[arrayIndex] = Boolean.valueOf(result); | 506 sNeedsExtrabindFlags[arrayIndex] = Boolean.valueOf(result); |
| 527 return result; | 507 return result; |
| 528 } | 508 } |
| 529 | 509 |
| 530 @VisibleForTesting | 510 @VisibleForTesting |
| 531 public void crashServiceForTesting() throws RemoteException { | 511 public void crashServiceForTesting() throws RemoteException { |
| 532 synchronized (mLock) { | 512 mService.crashIntentionallyForTesting(); |
| 533 mService.crashIntentionallyForTesting(); | |
| 534 } | |
| 535 } | 513 } |
| 536 | 514 |
| 537 @VisibleForTesting | 515 @VisibleForTesting |
| 538 public boolean isConnected() { | 516 boolean isConnected() { |
| 539 synchronized (mLock) { | 517 return mService != null; |
| 540 return mService != null; | |
| 541 } | |
| 542 } | 518 } |
| 543 } | 519 } |
| OLD | NEW |