BrowserStartupController.java revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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;
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.base.library_loader.LibraryLoader;
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.base.library_loader.LoaderErrors;
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.chromium.base.library_loader.ProcessInitException;
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import org.chromium.content.app.ContentMain;
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.ArrayList;
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.util.List;
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)/**
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * This class controls how C++ browser main loop is started and ensures it happens only once.
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * It supports kicking off the startup sequence in an asynchronous way. Startup can be called as
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * many times as needed (for instance, multiple activities for the same application), but the
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * browser process will still only be initialized once. All requests to start the browser will
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * always get their callback executed; if the browser process has already been started, the callback
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * is called immediately, else it is called when initialization is complete.
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * All communication with this class must happen on the main thread.
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) *
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) * This is a singleton, and stores a reference to the application context.
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) */
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)@JNINamespace("content")
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)public class BrowserStartupController {
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    /**
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     * This provides the interface to the callbacks for successful or failed startup
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)     */
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public interface StartupCallback {
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        void onSuccess(boolean alreadyStarted);
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        void onFailure();
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final String TAG = "BrowserStartupController";
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Helper constants for {@link StartupCallback#onSuccess}.
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final boolean ALREADY_STARTED = true;
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static final boolean NOT_ALREADY_STARTED = false;
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Helper constants for {@link #executeEnqueuedCallbacks(int, boolean)}.
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static final int STARTUP_SUCCESS = -1;
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static final int STARTUP_FAILURE = 1;
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static BrowserStartupController sInstance;
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private static boolean sBrowserMayStartAsynchronously = false;
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static void setAsynchronousStartup(boolean enable) {
65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        sBrowserMayStartAsynchronously = enable;
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    @VisibleForTesting
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
70424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    static boolean browserMayStartAsynchonously() {
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sBrowserMayStartAsynchronously;
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @CalledByNative
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static void browserStartupComplete(int result) {
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance != null) {
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance.executeEnqueuedCallbacks(result, NOT_ALREADY_STARTED);
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // A list of callbacks that should be called when the async startup of the browser process is
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // complete.
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private final List<StartupCallback> mAsyncStartupCallbacks;
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // The context is set on creation, but the reference is cleared after the browser process
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // initialization has been started, since it is not needed anymore. This is to ensure the
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // context is not leaked.
89424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Context mContext;
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Whether the async startup of the browser process has started.
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mHasStartedInitializingBrowserProcess;
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // Whether the async startup of the browser process is complete.
95424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private boolean mStartupDone;
96424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
97424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Use single-process mode that runs the renderer on a separate thread in
98424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // the main application.
99424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public static final int MAX_RENDERERS_SINGLE_PROCESS = 0;
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Cap on the maximum number of renderer processes that can be requested.
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // This is currently set to account for:
103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    //  13: The maximum number of sandboxed processes we have available
104424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: The regular New Tab Page
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: The incognito New Tab Page
106424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: A regular incognito tab
107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // - 1: Safety buffer (http://crbug.com/251279)
108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public static final int MAX_RENDERERS_LIMIT =
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            ChildProcessLauncher.MAX_REGISTERED_SANDBOXED_SERVICES - 4;
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // This field is set after startup has been completed based on whether the startup was a success
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // or not. It is used when later requests to startup come in that happen after the initial set
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // of enqueued callbacks have been executed.
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mStartupSuccess;
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    BrowserStartupController(Context context) {
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mContext = context;
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks = new ArrayList<StartupCallback>();
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public static BrowserStartupController get(Context context) {
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ThreadUtils.assertOnUiThread();
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance == null) {
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance = new BrowserStartupController(context.getApplicationContext());
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sInstance;
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static BrowserStartupController overrideInstanceForTest(BrowserStartupController controller) {
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance == null) {
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance = controller;
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sInstance;
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Start the browser process asynchronously. This will set up a queue of UI thread tasks to
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * initialize the browser process.
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * <p/>
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Note that this can only be called on the UI thread.
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param callback the callback to be called when browser startup is complete.
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    public void startBrowserProcessesAsync(final StartupCallback callback)
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            throws ProcessInitException {
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
149424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // Browser process initialization has already been completed, so we can immediately post
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // the callback.
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            postStartupCompleted(callback);
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // Browser process has not been fully started yet, so we defer executing the callback.
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks.add(callback);
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (!mHasStartedInitializingBrowserProcess) {
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // This is the first time we have been asked to start the browser process. We set the
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // flag that indicates that we have kicked off starting the browser process.
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mHasStartedInitializingBrowserProcess = true;
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            prepareToStartBrowserProcess(MAX_RENDERERS_LIMIT);
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            setAsynchronousStartup(true);
167424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (contentStart() > 0) {
168424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                // Failed. The callbacks may not have run, so run them.
169424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
170424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
174424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
175424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Start the browser process synchronously. If the browser is already being started
176424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * asynchronously then complete startup synchronously
177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
178424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * <p/>
179424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Note that this can only be called on the UI thread.
180424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @param maxRenderers The maximum number of renderer processes the browser may
182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *                      create. Zero for single process mode.
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @throws ProcessInitException
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    public void startBrowserProcessesSync(int maxRenderers) throws ProcessInitException {
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // If already started skip to checking the result
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (!mStartupDone) {
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (!mHasStartedInitializingBrowserProcess) {
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                prepareToStartBrowserProcess(maxRenderers);
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            setAsynchronousStartup(false);
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (contentStart() > 0) {
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                // Failed. The callbacks may not have run, so run them.
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Startup should now be complete
200424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        assert mStartupDone;
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (!mStartupSuccess) {
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_STARTUP_FAILED);
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
207424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Wrap ContentMain.start() for testing.
208424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    @VisibleForTesting
210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    int contentStart() {
211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return ContentMain.start();
212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
213424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public void addStartupCompletedObserver(StartupCallback callback) {
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ThreadUtils.assertOnUiThread();
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            postStartupCompleted(callback);
218424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        } else {
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mAsyncStartupCallbacks.add(callback);
220424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void executeEnqueuedCallbacks(int startupResult, boolean alreadyStarted) {
2243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Callback from browser startup from wrong thread.";
225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mStartupDone = true;
226424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mStartupSuccess = (startupResult <= 0);
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        for (StartupCallback asyncStartupCallback : mAsyncStartupCallbacks) {
228424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (mStartupSuccess) {
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                asyncStartupCallback.onSuccess(alreadyStarted);
230424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            } else {
231424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                asyncStartupCallback.onFailure();
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
2343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // We don't want to hold on to any objects after we do not need them anymore.
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks.clear();
2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
238424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Queue the callbacks to run. Since running the callbacks clears the list it is safe to call
239424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // this more than once.
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void enqueueCallbackExecution(final int startupFailure, final boolean alreadyStarted) {
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new Handler().post(new Runnable() {
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                executeEnqueuedCallbacks(startupFailure, alreadyStarted);
2453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void postStartupCompleted(final StartupCallback callback) {
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new Handler().post(new Runnable() {
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
2523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
253424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                if (mStartupSuccess) {
2543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    callback.onSuccess(ALREADY_STARTED);
255424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                } else {
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    callback.onFailure();
257424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                }
2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
2603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
263424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    void prepareToStartBrowserProcess(int maxRendererProcesses) throws ProcessInitException {
264424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        Log.i(TAG, "Initializing chromium process, renderers=" + maxRendererProcesses);
265424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
266424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Normally Main.java will have kicked this off asynchronously for Chrome. But other
267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // ContentView apps like tests also need them so we make sure we've extracted resources
268424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // here. We can still make it a little async (wait until the library is loaded).
269424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
270424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.startExtractingResources();
271424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
272424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Normally Main.java will have already loaded the library asynchronously, we only need
273424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // to load it here if we arrived via another flow, e.g. bookmark access & sync setup.
274c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        LibraryLoader.ensureInitialized(mContext, true);
275424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
276424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // TODO(yfriedman): Remove dependency on a command line flag for this.
277424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        DeviceUtils.addDeviceSpecificUserAgentSwitch(mContext);
278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
279424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        Context appContext = mContext.getApplicationContext();
280424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Now we really need to have the resources ready.
281424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.waitForCompletion();
282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        nativeSetCommandLineFlags(maxRendererProcesses,
284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                nativeIsPluginEnabled() ? getPlugins() : null);
285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ContentMain.initApplicationContext(appContext);
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
289424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Initialization needed for tests. Mainly used by content browsertests.
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
291424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public void initChromiumBrowserProcessForTests() {
292424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
293424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.startExtractingResources();
294424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.waitForCompletion();
295424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
296424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Having a single renderer should be sufficient for tests. We can't have more than
297424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // MAX_RENDERERS_LIMIT.
298424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        nativeSetCommandLineFlags(1 /* maxRenderers */, null);
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
300424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
301424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private String getPlugins() {
302424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return PepperPluginManager.getPlugins(mContext);
303424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
304424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
305424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native void nativeSetCommandLineFlags(int maxRenderProcesses,
306424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            String pluginDescriptor);
307424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
308424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Is this an official build of Chrome? Only native code knows for sure. Official build
309424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // knowledge is needed very early in process startup.
310424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native boolean nativeIsOfficialBuild();
311424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
312424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native boolean nativeIsPluginEnabled();
3133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
314