Index: content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java |
diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a4d9e1f359357f9867839b5cc433d333a130728e |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java |
@@ -0,0 +1,162 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.content.browser; |
+ |
+import android.content.Context; |
+import android.os.Handler; |
+import android.util.Log; |
+ |
+import com.google.common.annotations.VisibleForTesting; |
+ |
+import org.chromium.base.CalledByNative; |
+import org.chromium.base.JNINamespace; |
+import org.chromium.base.ThreadUtils; |
+import org.chromium.content.common.ProcessInitException; |
+ |
+import java.util.ArrayList; |
+import java.util.List; |
+ |
+/** |
+ * This class controls how C++ browser main loop is run and ensures it happens only once. |
bulach
2013/08/15 15:09:12
s/is run/is started/
nyquist
2013/08/16 02:01:01
Done.
|
+ * |
+ * It supports kicking of the startup sequence in an asynchronous way. Startup can be called as many |
+ * times as needed, but the browser process will still only be initialized once. All requests to |
bulach
2013/08/15 15:09:12
times as needed (for instance, multiple activities
nyquist
2013/08/16 02:01:01
Done.
|
+ * start the browser will always get their callback executed; if the browser process has already |
+ * been started, the callback is called immediately, else it is called when initialization is |
+ * complete. |
+ * |
+ * All communication with this class must happen on the main thread. |
+ * |
+ * This is a singleton, and stores a reference to the application context. |
+ */ |
+@JNINamespace("content") |
+public class BrowserStartupController { |
+ public interface StartupCallback { |
+ void run(int startupResult); |
bulach
2013/08/15 15:09:12
nit: maybe "onStartupComplete" ?
nyquist
2013/08/16 02:01:01
Done. Split into two methods: onSuccess and onFail
|
+ } |
+ |
+ private static final String TAG = "BrowserStartupController"; |
+ |
+ private static final Object LOCK = new Object(); |
+ |
+ private static BrowserStartupController sInstance; |
+ |
+ private static boolean sBrowserMayStartAsynchronously = false; |
+ |
+ @CalledByNative |
+ private static boolean browserMayStartAsynchonously() { |
+ return sBrowserMayStartAsynchronously; |
+ } |
+ |
+ @CalledByNative |
+ private static void browserStartupComplete(int result) { |
+ BrowserStartupController instance = null; |
+ synchronized (LOCK) { |
+ if (sInstance != null) { |
+ instance = sInstance; |
+ } |
+ } |
+ if (instance != null) { |
+ instance.executeEnqueuedCallbacks(result); |
+ } |
+ } |
+ |
+ // A list of callbacks that should be called when the async startup of the browser process is |
+ // complete. |
+ private final List<StartupCallback> mAsyncStartupCallbacks; |
+ |
+ private final Context mContext; |
bulach
2013/08/15 15:09:12
nit: I heard rumors that this can cause leaks, spe
nyquist
2013/08/16 02:01:01
Done.
|
+ |
+ // Whether the async startup of the browser process has started. |
+ private boolean mHasStartedInitializingBrowserProcess; |
+ |
+ // Whether the async startup of the browser process is complete. |
+ private boolean mAsyncStartupDone; |
+ |
+ BrowserStartupController(Context context) { |
+ mContext = context; |
+ mAsyncStartupCallbacks = new ArrayList<StartupCallback>(); |
+ } |
+ |
+ public static BrowserStartupController get(Context context) { |
+ synchronized (LOCK) { |
+ if (sInstance == null) { |
+ sInstance = new BrowserStartupController(context.getApplicationContext()); |
+ } |
+ return sInstance; |
+ } |
+ } |
+ |
+ /** |
+ * Start the browser process asynchronously. This will set up a queue of UI thread tasks to |
+ * initialize the browser process. |
+ * <p/> |
+ * Note that this can only be called on the UI thread. |
+ * |
+ * @param callback the callback to be called when browser startup is complete. |
+ * @return Whether the queue of tasks was created successfully. |
bulach
2013/08/15 15:09:12
hmm... would it make sense to have this method "vo
nyquist
2013/08/16 02:01:01
Done.
|
+ */ |
+ public boolean startBrowserProcessesAsync(final StartupCallback callback) { |
+ assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread."; |
+ if (mAsyncStartupDone) { |
+ // Browser process is already fully started, so we can immediately post the callback. |
+ new Handler().post(new Runnable() { |
+ @Override |
+ public void run() { |
+ callback.run(-1); |
bulach
2013/08/15 15:09:12
nit: maybe define -1 as public static final int of
nyquist
2013/08/16 02:01:01
Done.
|
+ } |
+ }); |
+ return true; |
+ } |
+ |
+ // Browser process has not been fully started yet, so we defer executing the callback. |
+ mAsyncStartupCallbacks.add(callback); |
+ |
+ if (mHasStartedInitializingBrowserProcess) { |
+ // We only want to try to initialize the browser process once, so we just return here. |
+ return true; |
+ } else { |
+ // This is the first time we have been asked to start the browser process. We set the |
+ // flag that indicates that we have kicked off starting the browser process. |
+ mHasStartedInitializingBrowserProcess = true; |
+ |
+ enableAsynchronousStartup(); |
+ |
+ // We can now try to initialize the Android browser process. |
+ return initializeAndroidBrowserProcess(); |
+ } |
+ } |
+ |
+ @VisibleForTesting |
+ void executeEnqueuedCallbacks(int startupResult) { |
+ assert ThreadUtils.runningOnUiThread() : "Callback from browser startup from wrong thread."; |
+ mAsyncStartupDone = true; |
+ for (StartupCallback asyncStartupCallback : mAsyncStartupCallbacks) { |
+ asyncStartupCallback.run(startupResult); |
+ } |
+ // We don't want to hold on to any objects after we do not need them anymore. |
+ mAsyncStartupCallbacks.clear(); |
+ } |
+ |
+ /** |
+ * Ensure that the browser process will be asynchronously started up. This also ensures that we |
+ * get a call to {@link #browserStartupComplete} when the browser startup is complete. |
+ */ |
+ @VisibleForTesting |
+ void enableAsynchronousStartup() { |
+ sBrowserMayStartAsynchronously = true; |
bulach
2013/08/15 15:09:12
need to make find_bugs happy.
nyquist
2013/08/16 02:01:01
Done.
|
+ } |
+ |
+ @VisibleForTesting |
+ boolean initializeAndroidBrowserProcess() { |
+ try { |
+ AndroidBrowserProcess.init(mContext, AndroidBrowserProcess.MAX_RENDERERS_LIMIT); |
bulach
2013/08/15 15:09:12
nit:
Context context = mContext;
mContext = null;
nyquist
2013/08/16 02:01:01
Done.
|
+ } catch (ProcessInitException e) { |
+ Log.e(TAG, "Unable to start browser process.", e); |
+ return false; |
+ } |
+ return true; |
+ } |
+} |