Chromium Code Reviews| 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; |
| + } |
| +} |