Index: content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java |
index aed55c3f5328b61e80ea44f357b26f3418a24258..935d1c3a2b8c193e85507ebf6eccb2641acf83c2 100644 |
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java |
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java |
@@ -8,6 +8,7 @@ import android.content.ComponentName; |
import android.content.Context; |
import android.content.pm.ApplicationInfo; |
import android.content.pm.PackageManager; |
+import android.os.AsyncTask; |
import android.os.Bundle; |
import android.os.ParcelFileDescriptor; |
import android.os.RemoteException; |
@@ -413,12 +414,13 @@ public class ChildProcessLauncher { |
private static ChildProcessConnection allocateBoundConnection(Context context, |
String[] commandLine, boolean inSandbox, boolean alwaysInForeground, |
- ChildProcessCreationParams creationParams) { |
+ ChildProcessCreationParams creationParams, |
+ ChildProcessConnection.StartCallback startCallback) { |
ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnection(); |
ChildProcessConnection connection = allocateConnection( |
context, inSandbox, chromiumLinkerParams, alwaysInForeground, creationParams); |
if (connection != null) { |
- connection.start(commandLine); |
+ connection.start(commandLine, startCallback); |
String packageName = creationParams != null ? creationParams.getPackageName() |
: context.getPackageName(); |
@@ -436,7 +438,7 @@ public class ChildProcessLauncher { |
private static final long FREE_CONNECTION_DELAY_MILLIS = 1; |
private static void freeConnection(ChildProcessConnection connection) { |
- synchronized (ChildProcessLauncher.class) { |
+ synchronized (sSpareConnectionLock) { |
if (connection.equals(sSpareSandboxedConnection)) sSpareSandboxedConnection = null; |
} |
@@ -483,8 +485,16 @@ public class ChildProcessLauncher { |
private static Map<Integer, ChildProcessConnection> sServiceMap = |
new ConcurrentHashMap<Integer, ChildProcessConnection>(); |
+ // Lock and monitor for these members {{{ |
+ private static final Object sSpareConnectionLock = new Object(); |
// A pre-allocated and pre-bound connection ready for connection setup, or null. |
private static ChildProcessConnection sSpareSandboxedConnection; |
+ // If sSpareSandboxedConnection is not null, this indicates whether the service is |
+ // ready for connection setup. Wait on the monitor lock to be notified when this |
+ // state changes. sSpareSandboxedConnection may be null after waiting, if starting |
+ // the service failed. |
+ private static boolean sSpareConnectionStarting; |
+ // }}} |
// Manages oom bindings used to bind chind services. |
private static BindingManager sBindingManager = BindingManagerImpl.createBindingManager(); |
@@ -567,15 +577,38 @@ public class ChildProcessLauncher { |
* @param context the application context used for the connection. |
*/ |
public static void warmUp(Context context) { |
- synchronized (ChildProcessLauncher.class) { |
+ synchronized (sSpareConnectionLock) { |
assert !ThreadUtils.runningOnUiThread(); |
if (sSpareSandboxedConnection == null) { |
ChildProcessCreationParams params = ChildProcessCreationParams.get(); |
if (params != null) { |
params = params.copy(); |
} |
+ |
Tobias Sargeant
2017/01/14 23:24:58
Presumably the fact that warmUp doesn't retry mean
Robert Sesek
2017/01/17 19:51:22
Since warmUp is only used for the first connection
|
+ sSpareConnectionStarting = true; |
+ |
+ ChildProcessConnection.StartCallback startCallback = |
+ new ChildProcessConnection.StartCallback() { |
+ @Override |
+ public void onChildStarted() { |
+ synchronized (sSpareConnectionLock) { |
+ sSpareConnectionStarting = false; |
+ sSpareConnectionLock.notify(); |
+ } |
+ } |
+ |
+ @Override |
+ public void onChildStartFailed() { |
+ Log.e(TAG, "Failed to warm up the spare sandbox service"); |
+ synchronized (sSpareConnectionLock) { |
+ sSpareSandboxedConnection = null; |
+ sSpareConnectionStarting = false; |
+ sSpareConnectionLock.notify(); |
+ } |
+ } |
+ }; |
sSpareSandboxedConnection = allocateBoundConnection(context, null, true, false, |
- params); |
+ params, startCallback); |
} |
} |
} |
@@ -654,23 +687,29 @@ public class ChildProcessLauncher { |
} |
private static void startInternal( |
- Context context, |
+ final Context context, |
final String[] commandLine, |
- int childProcessId, |
- FileDescriptorInfo[] filesToBeMapped, |
- long clientContext, |
- int callbackType, |
- boolean inSandbox, |
- ChildProcessCreationParams creationParams) { |
+ final int childProcessId, |
+ final FileDescriptorInfo[] filesToBeMapped, |
+ final long clientContext, |
+ final int callbackType, |
+ final boolean inSandbox, |
+ final ChildProcessCreationParams creationParams) { |
try { |
TraceEvent.begin("ChildProcessLauncher.startInternal"); |
ChildProcessConnection allocatedConnection = null; |
String packageName = creationParams != null ? creationParams.getPackageName() |
: context.getPackageName(); |
- synchronized (ChildProcessLauncher.class) { |
+ synchronized (sSpareConnectionLock) { |
if (inSandbox && sSpareSandboxedConnection != null |
&& sSpareSandboxedConnection.getPackageName().equals(packageName)) { |
+ while (sSpareConnectionStarting) { |
+ try { |
+ sSpareConnectionLock.wait(); |
+ } catch (InterruptedException ex) { |
+ } |
+ } |
allocatedConnection = sSpareSandboxedConnection; |
sSpareSandboxedConnection = null; |
} |
@@ -680,9 +719,29 @@ public class ChildProcessLauncher { |
if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true; |
PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue( |
context, packageName, inSandbox); |
+ ChildProcessConnection.StartCallback startCallback = |
+ new ChildProcessConnection.StartCallback() { |
+ @Override |
+ public void onChildStarted() {} |
+ |
+ @Override |
+ public void onChildStartFailed() { |
+ Log.e(TAG, "ChildProcessConnection.start failed, trying again"); |
+ new AsyncTask<Void, Void, Void>() { |
Torne
2017/01/16 12:44:43
If the asynctask only has a doInBackground and is
Robert Sesek
2017/01/17 19:51:22
Done.
|
+ @Override |
+ protected Void doInBackground(Void... params) { |
+ startInternal(context, commandLine, childProcessId, |
+ filesToBeMapped, clientContext, callbackType, |
+ inSandbox, creationParams); |
+ return null; |
+ } |
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
+ } |
+ }; |
synchronized (pendingSpawnQueue.mPendingSpawnsLock) { |
allocatedConnection = allocateBoundConnection( |
- context, commandLine, inSandbox, alwaysInForeground, creationParams); |
+ context, commandLine, inSandbox, alwaysInForeground, creationParams, |
+ startCallback); |
if (allocatedConnection == null) { |
Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn."); |
pendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine, |
@@ -836,7 +895,7 @@ public class ChildProcessLauncher { |
@VisibleForTesting |
static ChildProcessConnection allocateBoundConnectionForTesting(Context context, |
ChildProcessCreationParams creationParams) { |
- return allocateBoundConnection(context, null, true, false, creationParams); |
+ return allocateBoundConnection(context, null, true, false, creationParams, null); |
} |
@VisibleForTesting |