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

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

Issue 2822803002: android: Post onServiceConnected to launcher thread (Closed)
Patch Set: fix Created 3 years, 8 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
« no previous file with comments | « content/public/android/java/src/org/chromium/content/browser/ChildProcessConnectionImpl.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 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.Context; 7 import android.content.Context;
8 import android.os.Bundle; 8 import android.os.Bundle;
9 import android.os.IBinder; 9 import android.os.IBinder;
10 import android.os.RemoteException; 10 import android.os.RemoteException;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 sBindingManager.releaseAllModerateBindings(); 129 sBindingManager.releaseAllModerateBindings();
130 } 130 }
131 } 131 }
132 return connection; 132 return connection;
133 } 133 }
134 134
135 private static final long FREE_CONNECTION_DELAY_MILLIS = 1; 135 private static final long FREE_CONNECTION_DELAY_MILLIS = 1;
136 136
137 private static void freeConnection(ChildProcessConnection connection) { 137 private static void freeConnection(ChildProcessConnection connection) {
138 assert LauncherThread.runningOnLauncherThread(); 138 assert LauncherThread.runningOnLauncherThread();
139 synchronized (sSpareConnectionLock) { 139 if (connection == sSpareSandboxedConnection) clearSpareConnection();
140 if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedCon nection = null;
141 }
142 140
143 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the 141 // Freeing a service should be delayed. This is so that we avoid immedia tely reusing the
144 // freed service (see http://crbug.com/164069): the framework might keep a service process 142 // freed service (see http://crbug.com/164069): the framework might keep a service process
145 // alive when it's been unbound for a short time. If a new connection to the same service 143 // alive when it's been unbound for a short time. If a new connection to the same service
146 // is bound at that point, the process is reused and bad things happen ( mostly static 144 // is bound at that point, the process is reused and bad things happen ( mostly static
147 // variables are set when we don't expect them to). 145 // variables are set when we don't expect them to).
148 final ChildProcessConnection conn = connection; 146 final ChildProcessConnection conn = connection;
149 LauncherThread.postDelayed(new Runnable() { 147 LauncherThread.postDelayed(new Runnable() {
150 @Override 148 @Override
151 public void run() { 149 public void run() {
(...skipping 25 matching lines...) Expand all
177 }, FREE_CONNECTION_DELAY_MILLIS); 175 }, FREE_CONNECTION_DELAY_MILLIS);
178 } 176 }
179 177
180 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle. 178 // Represents an invalid process handle; same as base/process/process.h kNul lProcessHandle.
181 private static final int NULL_PROCESS_HANDLE = 0; 179 private static final int NULL_PROCESS_HANDLE = 0;
182 180
183 // Map from pid to ChildService connection. 181 // Map from pid to ChildService connection.
184 private static Map<Integer, ChildProcessConnection> sServiceMap = 182 private static Map<Integer, ChildProcessConnection> sServiceMap =
185 new ConcurrentHashMap<Integer, ChildProcessConnection>(); 183 new ConcurrentHashMap<Integer, ChildProcessConnection>();
186 184
187 // Lock and monitor for these members {{{ 185 // These variables are used for the warm up sandboxed connection.
188 private static final Object sSpareConnectionLock = new Object(); 186 // |sSpareSandboxedConnection| is non-null when there is a pending connectio n. Note it's cleared
189 // A pre-allocated and pre-bound connection ready for connection setup, or n ull. 187 // to null again after the connection is used for a real child process.
188 // |sSpareConnectionStarting| is true if ChildProcessConnection.StartCallbac k has not fired.
189 // This is used for a child process allocation to determine if StartCallback should be chained.
190 // |sSpareConnectionStartCallback| is the chained StartCallback. This is als o used to determine
191 // if there is already a child process launch that's used this this connecti on.
190 private static ChildProcessConnection sSpareSandboxedConnection; 192 private static ChildProcessConnection sSpareSandboxedConnection;
191 // If sSpareSandboxedConnection is not null, this indicates whether the serv ice is
192 // ready for connection setup. Wait on the monitor lock to be notified when this
193 // state changes. sSpareSandboxedConnection may be null after waiting, if st arting
194 // the service failed.
195 private static boolean sSpareConnectionStarting; 193 private static boolean sSpareConnectionStarting;
196 // }}} 194 private static ChildProcessConnection.StartCallback sSpareConnectionStartCal lback;
197 195
198 // Manages oom bindings used to bind chind services. 196 // Manages oom bindings used to bind chind services.
199 private static BindingManager sBindingManager = BindingManagerImpl.createBin dingManager(); 197 private static BindingManager sBindingManager = BindingManagerImpl.createBin dingManager();
200 198
201 // Whether the main application is currently brought to the foreground. 199 // Whether the main application is currently brought to the foreground.
202 private static boolean sApplicationInForeground = true; 200 private static boolean sApplicationInForeground = true;
203 201
204 // TODO(boliu): This should be internal to content. 202 // TODO(boliu): This should be internal to content.
205 public static BindingManager getBindingManager() { 203 public static BindingManager getBindingManager() {
206 return sBindingManager; 204 return sBindingManager;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 /** 259 /**
262 * Should be called early in startup so the work needed to spawn the child p rocess can be done 260 * Should be called early in startup so the work needed to spawn the child p rocess can be done
263 * in parallel to other startup work. Spare connection is created in sandbox ed child process. 261 * in parallel to other startup work. Spare connection is created in sandbox ed child process.
264 * @param context the application context used for the connection. 262 * @param context the application context used for the connection.
265 */ 263 */
266 public static void warmUp(final Context context) { 264 public static void warmUp(final Context context) {
267 assert ThreadUtils.runningOnUiThread(); 265 assert ThreadUtils.runningOnUiThread();
268 LauncherThread.post(new Runnable() { 266 LauncherThread.post(new Runnable() {
269 @Override 267 @Override
270 public void run() { 268 public void run() {
271 synchronized (sSpareConnectionLock) { 269 if (sSpareSandboxedConnection != null) return;
272 if (sSpareSandboxedConnection == null) { 270 ChildProcessCreationParams params = ChildProcessCreationParams.g etDefault();
273 ChildProcessCreationParams params = ChildProcessCreation Params.getDefault();
274 sSpareConnectionStarting = true;
275 271
276 ChildProcessConnection.StartCallback startCallback = 272 ChildProcessConnection.StartCallback startCallback =
277 new ChildProcessConnection.StartCallback() { 273 new ChildProcessConnection.StartCallback() {
278 @Override 274 @Override
279 public void onChildStarted() { 275 public void onChildStarted() {
280 synchronized (sSpareConnectionLock) { 276 assert LauncherThread.runningOnLauncherThread();
281 sSpareConnectionStarting = false; 277 sSpareConnectionStarting = false;
282 sSpareConnectionLock.notify(); 278 if (sSpareConnectionStartCallback != null) {
283 } 279 sSpareConnectionStartCallback.onChildStarted ();
284 } 280 clearSpareConnection();
Robert Sesek 2017/04/17 18:29:16 Why is this only done in the condition?
boliu 2017/04/17 18:34:18 If there is no chained callback, then it means onC
Robert Sesek 2017/04/17 18:37:04 Acknowledged. Might be worth leaving a note since
boliu 2017/04/17 18:57:13 Added a comment.
281 }
282 }
285 283
286 @Override 284 @Override
287 public void onChildStartFailed() { 285 public void onChildStartFailed() {
288 Log.e(TAG, "Failed to warm up the spare sandbox service"); 286 assert LauncherThread.runningOnLauncherThread();
289 synchronized (sSpareConnectionLock) { 287 Log.e(TAG, "Failed to warm up the spare sandbox service");
290 sSpareSandboxedConnection = null; 288 if (sSpareConnectionStartCallback != null) {
291 sSpareConnectionStarting = false; 289 sSpareConnectionStartCallback.onChildStartFa iled();
292 sSpareConnectionLock.notify(); 290 }
293 } 291 clearSpareConnection();
294 } 292 }
295 }; 293 };
296 ChildSpawnData spawnData = new ChildSpawnData(context, 294 ChildSpawnData spawnData = new ChildSpawnData(context, null /* c ommandLine */,
297 null /* commandLine */, -1 /* child process id * /, 295 -1 /* child process id */, null /* filesToBeMapped */,
298 null /* filesToBeMapped */, null /* launchCallba ck */, 296 null /* launchCallback */, null /* child process callbac k */,
299 null /* child process callback */, true /* inSan dbox */, 297 true /* inSandbox */, SPARE_CONNECTION_ALWAYS_IN_FOREGRO UND, params);
300 SPARE_CONNECTION_ALWAYS_IN_FOREGROUND, params); 298 sSpareSandboxedConnection =
301 sSpareSandboxedConnection = allocateBoundConnection( 299 allocateBoundConnection(spawnData, startCallback, true / * forWarmUp */);
302 spawnData, startCallback, true /* forWarmUp */); 300 sSpareConnectionStarting = sSpareSandboxedConnection != null;
303 }
304 }
305 } 301 }
306 }); 302 });
307 } 303 }
308 304
305 private static void clearSpareConnection() {
306 assert LauncherThread.runningOnLauncherThread();
307 sSpareSandboxedConnection = null;
308 sSpareConnectionStarting = false;
309 sSpareConnectionStartCallback = null;
310 }
311
309 /** 312 /**
310 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but 313 * Spawns and connects to a child process. May be called on any thread. It w ill not block, but
311 * will instead callback to {@link #nativeOnChildProcessStarted} when the co nnection is 314 * will instead callback to {@link #nativeOnChildProcessStarted} when the co nnection is
312 * established. Note this callback will not necessarily be from the same thr ead (currently it 315 * established. Note this callback will not necessarily be from the same thr ead (currently it
313 * always comes from the main thread). 316 * always comes from the main thread).
314 * 317 *
315 * @param context Context used to obtain the application context. 318 * @param context Context used to obtain the application context.
316 * @param paramId Key used to retrieve ChildProcessCreationParams. 319 * @param paramId Key used to retrieve ChildProcessCreationParams.
317 * @param commandLine The child process command line argv. 320 * @param commandLine The child process command line argv.
318 * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass throug h. 321 * @param filesToBeMapped File IDs, FDs, offsets, and lengths to pass throug h.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback lau nchCallback, 368 final FileDescriptorInfo[] filesToBeMapped, final LaunchCallback lau nchCallback,
366 final IBinder childProcessCallback, final boolean inSandbox, 369 final IBinder childProcessCallback, final boolean inSandbox,
367 final boolean alwaysInForeground, final ChildProcessCreationParams c reationParams) { 370 final boolean alwaysInForeground, final ChildProcessCreationParams c reationParams) {
368 assert LauncherThread.runningOnLauncherThread(); 371 assert LauncherThread.runningOnLauncherThread();
369 try { 372 try {
370 TraceEvent.begin("ChildProcessLauncher.startInternal"); 373 TraceEvent.begin("ChildProcessLauncher.startInternal");
371 374
372 ChildProcessConnection allocatedConnection = null; 375 ChildProcessConnection allocatedConnection = null;
373 String packageName = creationParams != null ? creationParams.getPack ageName() 376 String packageName = creationParams != null ? creationParams.getPack ageName()
374 : context.getPackageName(); 377 : context.getPackageName();
375 synchronized (sSpareConnectionLock) { 378 ChildProcessConnection.StartCallback startCallback =
376 if (inSandbox && sSpareSandboxedConnection != null 379 new ChildProcessConnection.StartCallback() {
377 && SPARE_CONNECTION_ALWAYS_IN_FOREGROUND == alwaysInFore ground 380 @Override
378 && sSpareSandboxedConnection.getPackageName().equals(pac kageName) 381 public void onChildStarted() {}
379 // Object identity check for getDefault should be enough . The default is 382
380 // not supposed to change once set. 383 @Override
381 && creationParams == ChildProcessCreationParams.getDefau lt()) { 384 public void onChildStartFailed() {
382 while (sSpareConnectionStarting) { 385 assert LauncherThread.runningOnLauncherThread();
383 try { 386 Log.e(TAG, "ChildProcessConnection.start failed, try ing again");
384 sSpareConnectionLock.wait(); 387 LauncherThread.post(new Runnable() {
385 } catch (InterruptedException ex) { 388 @Override
389 public void run() {
390 // The child process may already be bound to another client
391 // (this can happen if multi-process WebView is used in more
392 // than one process), so try starting the pr ocess again.
393 // This connection that failed to start has not been freed,
394 // so a new bound connection will be allocat ed.
395 startInternal(context, commandLine, childPro cessId,
396 filesToBeMapped, launchCallback, chi ldProcessCallback,
397 inSandbox, alwaysInForeground, creat ionParams);
398 }
399 });
386 } 400 }
387 } 401 };
388 allocatedConnection = sSpareSandboxedConnection; 402
389 sSpareSandboxedConnection = null; 403 if (inSandbox && sSpareSandboxedConnection != null
404 && sSpareConnectionStartCallback == null
405 && SPARE_CONNECTION_ALWAYS_IN_FOREGROUND == alwaysInForegrou nd
406 && sSpareSandboxedConnection.getPackageName().equals(package Name)
407 // Object identity check for getDefault should be enough. Th e default is
408 // not supposed to change once set.
409 && creationParams == ChildProcessCreationParams.getDefault() ) {
410 allocatedConnection = sSpareSandboxedConnection;
411 if (sSpareConnectionStarting) {
412 sSpareConnectionStartCallback = startCallback;
413 } else {
414 clearSpareConnection();
390 } 415 }
391 } 416 }
392 if (allocatedConnection == null) { 417 if (allocatedConnection == null) {
393 ChildProcessConnection.StartCallback startCallback =
394 new ChildProcessConnection.StartCallback() {
395 @Override
396 public void onChildStarted() {}
397
398 @Override
399 public void onChildStartFailed() {
400 Log.e(TAG, "ChildProcessConnection.start failed, trying again");
401 LauncherThread.post(new Runnable() {
402 @Override
403 public void run() {
404 // The child process may already be boun d to another client
405 // (this can happen if multi-process Web View is used in more
406 // than one process), so try starting th e process again.
407 // This connection that failed to start has not been freed,
408 // so a new bound connection will be all ocated.
409 startInternal(context, commandLine, chil dProcessId,
410 filesToBeMapped, launchCallback,
411 childProcessCallback, inSandbox, alwaysInForeground,
412 creationParams);
413 }
414 });
415 }
416 };
417 418
418 ChildSpawnData spawnData = new ChildSpawnData(context, commandLi ne, childProcessId, 419 ChildSpawnData spawnData = new ChildSpawnData(context, commandLi ne, childProcessId,
419 filesToBeMapped, launchCallback, childProcessCallback, i nSandbox, 420 filesToBeMapped, launchCallback, childProcessCallback, i nSandbox,
420 alwaysInForeground, creationParams); 421 alwaysInForeground, creationParams);
421 allocatedConnection = 422 allocatedConnection =
422 allocateBoundConnection(spawnData, startCallback, false /* forWarmUp */); 423 allocateBoundConnection(spawnData, startCallback, false /* forWarmUp */);
423 if (allocatedConnection == null) { 424 if (allocatedConnection == null) {
424 return null; 425 return null;
425 } 426 }
426 } 427 }
427 428
428 Log.d(TAG, "Setting up connection to process: slot=%d",
429 allocatedConnection.getServiceNumber());
430 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId, 429 triggerConnectionSetup(allocatedConnection, commandLine, childProces sId,
431 filesToBeMapped, childProcessCallback, launchCallback); 430 filesToBeMapped, childProcessCallback, launchCallback);
432 return allocatedConnection; 431 return allocatedConnection;
433 } finally { 432 } finally {
434 TraceEvent.end("ChildProcessLauncher.startInternal"); 433 TraceEvent.end("ChildProcessLauncher.startInternal");
435 } 434 }
436 } 435 }
437 436
438 /** 437 /**
439 * Create the common bundle to be passed to child processes. 438 * Create the common bundle to be passed to child processes.
(...skipping 10 matching lines...) Expand all
450 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask()); 449 bundle.putLong(ChildProcessConstants.EXTRA_CPU_FEATURES, CpuFeatures.get Mask());
451 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros()); 450 bundle.putBundle(Linker.EXTRA_LINKER_SHARED_RELROS, Linker.getInstance() .getSharedRelros());
452 return bundle; 451 return bundle;
453 } 452 }
454 453
455 @VisibleForTesting 454 @VisibleForTesting
456 static void triggerConnectionSetup(final ChildProcessConnection connection, 455 static void triggerConnectionSetup(final ChildProcessConnection connection,
457 String[] commandLine, int childProcessId, FileDescriptorInfo[] files ToBeMapped, 456 String[] commandLine, int childProcessId, FileDescriptorInfo[] files ToBeMapped,
458 final IBinder childProcessCallback, final LaunchCallback launchCallb ack) { 457 final IBinder childProcessCallback, final LaunchCallback launchCallb ack) {
459 assert LauncherThread.runningOnLauncherThread(); 458 assert LauncherThread.runningOnLauncherThread();
459 Log.d(TAG, "Setting up connection to process: slot=%d", connection.getSe rviceNumber());
460 ChildProcessConnection.ConnectionCallback connectionCallback = 460 ChildProcessConnection.ConnectionCallback connectionCallback =
461 new ChildProcessConnection.ConnectionCallback() { 461 new ChildProcessConnection.ConnectionCallback() {
462 @Override 462 @Override
463 public void onConnected(int pid) { 463 public void onConnected(int pid) {
464 Log.d(TAG, "on connect callback, pid=%d", pid); 464 Log.d(TAG, "on connect callback, pid=%d", pid);
465 if (pid != NULL_PROCESS_HANDLE) { 465 if (pid != NULL_PROCESS_HANDLE) {
466 sBindingManager.addNewConnection(pid, connection); 466 sBindingManager.addNewConnection(pid, connection);
467 sServiceMap.put(pid, connection); 467 sServiceMap.put(pid, connection);
468 } 468 }
469 // If the connection fails and pid == 0, the Java-side c leanup was already 469 // If the connection fails and pid == 0, the Java-side c leanup was already
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 513
514 try { 514 try {
515 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting(); 515 ((ChildProcessConnectionImpl) sServiceMap.get(pid)).crashServiceForT esting();
516 } catch (RemoteException ex) { 516 } catch (RemoteException ex) {
517 return false; 517 return false;
518 } 518 }
519 519
520 return true; 520 return true;
521 } 521 }
522 } 522 }
OLDNEW
« no previous file with comments | « content/public/android/java/src/org/chromium/content/browser/ChildProcessConnectionImpl.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698