BrowserStartupController.java revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)package org.chromium.content.browser;
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.content.Context;
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.os.Handler;
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.util.Log;
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import com.google.common.annotations.VisibleForTesting;
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.CalledByNative;
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.JNINamespace;
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.ThreadUtils;
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import org.chromium.content.app.ContentMain;
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import org.chromium.content.app.LibraryLoader;
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.content.common.ProcessInitException;
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.ArrayList;
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.List;
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/**
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * This class controls how C++ browser main loop is started and ensures it happens only once.
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * It supports kicking off the startup sequence in an asynchronous way. Startup can be called as
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * many times as needed (for instance, multiple activities for the same application), but the
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * browser process will still only be initialized once. All requests to start the browser will
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * always get their callback executed; if the browser process has already been started, the callback
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * is called immediately, else it is called when initialization is complete.
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * All communication with this class must happen on the main thread.
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * This is a singleton, and stores a reference to the application context.
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)@JNINamespace("content")
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)public class BrowserStartupController {
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public interface StartupCallback {
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        void onSuccess(boolean alreadyStarted);
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        void onFailure();
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final String TAG = "BrowserStartupController";
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Helper constants for {@link StartupCallback#onSuccess}.
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final boolean ALREADY_STARTED = true;
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final boolean NOT_ALREADY_STARTED = false;
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Helper constants for {@link #executeEnqueuedCallbacks(int, boolean)}.
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static final int STARTUP_SUCCESS = -1;
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static final int STARTUP_FAILURE = 1;
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static BrowserStartupController sInstance;
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static boolean sBrowserMayStartAsynchronously = false;
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static void setAsynchronousStartup(boolean enable) {
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        sBrowserMayStartAsynchronously = enable;
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    @VisibleForTesting
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    static boolean browserMayStartAsynchonously() {
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sBrowserMayStartAsynchronously;
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static void browserStartupComplete(int result) {
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance != null) {
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance.executeEnqueuedCallbacks(result, NOT_ALREADY_STARTED);
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // A list of callbacks that should be called when the async startup of the browser process is
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // complete.
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private final List<StartupCallback> mAsyncStartupCallbacks;
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // The context is set on creation, but the reference is cleared after the browser process
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // initialization has been started, since it is not needed anymore. This is to ensure the
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // context is not leaked.
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Context mContext;
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Whether the async startup of the browser process has started.
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mHasStartedInitializingBrowserProcess;
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Whether the async startup of the browser process is complete.
91424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private boolean mStartupDone;
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Use single-process mode that runs the renderer on a separate thread in
94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // the main application.
95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public static final int MAX_RENDERERS_SINGLE_PROCESS = 0;
96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Cap on the maximum number of renderer processes that can be requested.
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // This is currently set to account for:
99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    //  13: The maximum number of sandboxed processes we have available
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: The regular New Tab Page
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: The incognito New Tab Page
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: A regular incognito tab
103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: Safety buffer (http://crbug.com/251279)
104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public static final int MAX_RENDERERS_LIMIT =
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            ChildProcessLauncher.MAX_REGISTERED_SANDBOXED_SERVICES - 4;
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // This field is set after startup has been completed based on whether the startup was a success
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // or not. It is used when later requests to startup come in that happen after the initial set
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // of enqueued callbacks have been executed.
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mStartupSuccess;
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    BrowserStartupController(Context context) {
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mContext = context;
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks = new ArrayList<StartupCallback>();
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public static BrowserStartupController get(Context context) {
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ThreadUtils.assertOnUiThread();
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance == null) {
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance = new BrowserStartupController(context.getApplicationContext());
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sInstance;
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static BrowserStartupController overrideInstanceForTest(BrowserStartupController controller) {
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance == null) {
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance = controller;
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sInstance;
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Start the browser process asynchronously. This will set up a queue of UI thread tasks to
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * initialize the browser process.
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * <p/>
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Note that this can only be called on the UI thread.
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param callback the callback to be called when browser startup is complete.
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public void startBrowserProcessesAsync(final StartupCallback callback) {
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
144424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // Browser process initialization has already been completed, so we can immediately post
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // the callback.
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            postStartupCompleted(callback);
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // Browser process has not been fully started yet, so we defer executing the callback.
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks.add(callback);
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (!mHasStartedInitializingBrowserProcess) {
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // This is the first time we have been asked to start the browser process. We set the
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // flag that indicates that we have kicked off starting the browser process.
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mHasStartedInitializingBrowserProcess = true;
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (!tryPrepareToStartBrowserProcess(MAX_RENDERERS_LIMIT)) return;
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            setAsynchronousStartup(true);
162424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (contentStart() > 0) {
163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                // Failed. The callbacks may not have run, so run them.
164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
169424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private boolean tryPrepareToStartBrowserProcess(int maxRenderers) {
170424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Make sure that everything is in place to initialize the Android browser process.
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        try {
172424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            prepareToStartBrowserProcess(maxRenderers);
173424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            return true;
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        } catch (ProcessInitException e) {
175424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            Log.e(TAG, "Unable to load native library.", e);
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            return false;
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
181424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Start the browser process synchronously. If the browser is already being started
183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * asynchronously then complete startup synchronously
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * <p/>
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Note that this can only be called on the UI thread.
187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
188424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * @param max_renderers The maximum number of renderer processes the browser may
189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *                      create. Zero for single process mode.
190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * @return true if successfully started, false otherwise.
191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public boolean startBrowserProcessesSync(int maxRenderers) {
193424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
194424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            // Nothing to do
195424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            return mStartupSuccess;
196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (!mHasStartedInitializingBrowserProcess) {
198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (!tryPrepareToStartBrowserProcess(maxRenderers)) return false;
199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
200424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
201424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        setAsynchronousStartup(false);
202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (contentStart() > 0) {
203424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            // Failed. The callbacks may not have run, so run them.
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
207424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Startup should now be complete
208424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        assert mStartupDone;
209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return mStartupSuccess;
210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
213424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Wrap ContentMain.start() for testing.
214424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
215424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    @VisibleForTesting
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    int contentStart() {
217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return ContentMain.start();
218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public void addStartupCompletedObserver(StartupCallback callback) {
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ThreadUtils.assertOnUiThread();
222424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            postStartupCompleted(callback);
224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        } else {
2253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mAsyncStartupCallbacks.add(callback);
226424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void executeEnqueuedCallbacks(int startupResult, boolean alreadyStarted) {
2303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Callback from browser startup from wrong thread.";
231424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mStartupDone = true;
232424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mStartupSuccess = (startupResult <= 0);
2333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        for (StartupCallback asyncStartupCallback : mAsyncStartupCallbacks) {
234424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (mStartupSuccess) {
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                asyncStartupCallback.onSuccess(alreadyStarted);
236424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            } else {
237424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                asyncStartupCallback.onFailure();
2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // We don't want to hold on to any objects after we do not need them anymore.
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks.clear();
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
244424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Queue the callbacks to run. Since running the callbacks clears the list it is safe to call
245424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // this more than once.
2463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void enqueueCallbackExecution(final int startupFailure, final boolean alreadyStarted) {
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new Handler().post(new Runnable() {
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
2493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                executeEnqueuedCallbacks(startupFailure, alreadyStarted);
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
2533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void postStartupCompleted(final StartupCallback callback) {
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new Handler().post(new Runnable() {
2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
259424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                if (mStartupSuccess) {
2603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    callback.onSuccess(ALREADY_STARTED);
261424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                } else {
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    callback.onFailure();
263424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                }
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
269424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    void prepareToStartBrowserProcess(int maxRendererProcesses) throws ProcessInitException {
270424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        Log.i(TAG, "Initializing chromium process, renderers=" + maxRendererProcesses);
271424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
272424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Normally Main.java will have kicked this off asynchronously for Chrome. But other
273424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // ContentView apps like tests also need them so we make sure we've extracted resources
274424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // here. We can still make it a little async (wait until the library is loaded).
275424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
276424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.startExtractingResources();
277424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Normally Main.java will have already loaded the library asynchronously, we only need
279424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // to load it here if we arrived via another flow, e.g. bookmark access & sync setup.
280424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        LibraryLoader.ensureInitialized();
281424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // TODO(yfriedman): Remove dependency on a command line flag for this.
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        DeviceUtils.addDeviceSpecificUserAgentSwitch(mContext);
284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        Context appContext = mContext.getApplicationContext();
286424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Now we really need to have the resources ready.
287424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.waitForCompletion();
288424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
289424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        nativeSetCommandLineFlags(maxRendererProcesses,
290424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                nativeIsPluginEnabled() ? getPlugins() : null);
291424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ContentMain.initApplicationContext(appContext);
2923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
295424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Initialization needed for tests. Mainly used by content browsertests.
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
297424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public void initChromiumBrowserProcessForTests() {
298424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
299424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.startExtractingResources();
300424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.waitForCompletion();
301424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
302424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Having a single renderer should be sufficient for tests. We can't have more than
303424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // MAX_RENDERERS_LIMIT.
304424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        nativeSetCommandLineFlags(1 /* maxRenderers */, null);
3053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
306424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
307424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private String getPlugins() {
308424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return PepperPluginManager.getPlugins(mContext);
309424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
310424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
311424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native void nativeSetCommandLineFlags(int maxRenderProcesses,
312424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            String pluginDescriptor);
313424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
314424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Is this an official build of Chrome? Only native code knows for sure. Official build
315424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // knowledge is needed very early in process startup.
316424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native boolean nativeIsOfficialBuild();
317424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
318424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native boolean nativeIsPluginEnabled();
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
320