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 org.chromium.base.CalledByNative;
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.JNINamespace;
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.ResourceExtractor;
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import org.chromium.base.ThreadUtils;
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.VisibleForTesting;
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)
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // This field is set after startup has been completed based on whether the startup was a success
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // or not. It is used when later requests to startup come in that happen after the initial set
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // of enqueued callbacks have been executed.
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mStartupSuccess;
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    BrowserStartupController(Context context) {
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mContext = context;
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks = new ArrayList<StartupCallback>();
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public static BrowserStartupController get(Context context) {
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ThreadUtils.assertOnUiThread();
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance == null) {
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance = new BrowserStartupController(context.getApplicationContext());
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sInstance;
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    static BrowserStartupController overrideInstanceForTest(BrowserStartupController controller) {
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (sInstance == null) {
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            sInstance = controller;
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return sInstance;
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Start the browser process asynchronously. This will set up a queue of UI thread tasks to
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * initialize the browser process.
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * <p/>
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Note that this can only be called on the UI thread.
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * @param callback the callback to be called when browser startup is complete.
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    public void startBrowserProcessesAsync(final StartupCallback callback)
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            throws ProcessInitException {
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // Browser process initialization has already been completed, so we can immediately post
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // the callback.
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            postStartupCompleted(callback);
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            return;
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // Browser process has not been fully started yet, so we defer executing the callback.
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks.add(callback);
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if (!mHasStartedInitializingBrowserProcess) {
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // This is the first time we have been asked to start the browser process. We set the
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            // flag that indicates that we have kicked off starting the browser process.
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mHasStartedInitializingBrowserProcess = true;
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            prepareToStartBrowserProcess(false);
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
152424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            setAsynchronousStartup(true);
153424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (contentStart() > 0) {
154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                // Failed. The callbacks may not have run, so run them.
155424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
156424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            }
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
161424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Start the browser process synchronously. If the browser is already being started
162424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * asynchronously then complete startup synchronously
163424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * <p/>
165424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Note that this can only be called on the UI thread.
166424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     *
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @param singleProcess true iff the browser should run single-process, ie. keep renderers in
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     *                      the browser process
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)     * @throws ProcessInitException
170424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    public void startBrowserProcessesSync(boolean singleProcess) throws ProcessInitException {
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // If already started skip to checking the result
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (!mStartupDone) {
174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (!mHasStartedInitializingBrowserProcess) {
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                prepareToStartBrowserProcess(singleProcess);
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
177424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            setAsynchronousStartup(false);
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (contentStart() > 0) {
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                // Failed. The callbacks may not have run, so run them.
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            }
183424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Startup should now be complete
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        assert mStartupDone;
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (!mStartupSuccess) {
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_STARTUP_FAILED);
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    /**
193424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Wrap ContentMain.start() for testing.
194424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     */
195424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    @VisibleForTesting
196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    int contentStart() {
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return ContentMain.start();
198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public void addStartupCompletedObserver(StartupCallback callback) {
2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ThreadUtils.assertOnUiThread();
202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        if (mStartupDone) {
2033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            postStartupCompleted(callback);
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        } else {
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            mAsyncStartupCallbacks.add(callback);
206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        }
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void executeEnqueuedCallbacks(int startupResult, boolean alreadyStarted) {
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert ThreadUtils.runningOnUiThread() : "Callback from browser startup from wrong thread.";
211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mStartupDone = true;
212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mStartupSuccess = (startupResult <= 0);
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        for (StartupCallback asyncStartupCallback : mAsyncStartupCallbacks) {
214424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            if (mStartupSuccess) {
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                asyncStartupCallback.onSuccess(alreadyStarted);
216424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            } else {
217424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                asyncStartupCallback.onFailure();
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        }
2203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        // We don't want to hold on to any objects after we do not need them anymore.
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mAsyncStartupCallbacks.clear();
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
224424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Queue the callbacks to run. Since running the callbacks clears the list it is safe to call
225424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // this more than once.
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void enqueueCallbackExecution(final int startupFailure, final boolean alreadyStarted) {
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new Handler().post(new Runnable() {
2283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
2303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                executeEnqueuedCallbacks(startupFailure, alreadyStarted);
2313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
2333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private void postStartupCompleted(final StartupCallback callback) {
2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        new Handler().post(new Runnable() {
2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            @Override
2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            public void run() {
239424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                if (mStartupSuccess) {
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    callback.onSuccess(ALREADY_STARTED);
241424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                } else {
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    callback.onFailure();
243424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                }
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
2453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        });
2463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    @VisibleForTesting
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    void prepareToStartBrowserProcess(boolean singleProcess) throws ProcessInitException {
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        Log.i(TAG, "Initializing chromium process, singleProcess=" + singleProcess);
251424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
252424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Normally Main.java will have kicked this off asynchronously for Chrome. But other
253424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // ContentView apps like tests also need them so we make sure we've extracted resources
254424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // here. We can still make it a little async (wait until the library is loaded).
255424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
256424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.startExtractingResources();
257424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
258424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Normally Main.java will have already loaded the library asynchronously, we only need
259424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // to load it here if we arrived via another flow, e.g. bookmark access & sync setup.
260c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        LibraryLoader.ensureInitialized(mContext, true);
261424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
262424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // TODO(yfriedman): Remove dependency on a command line flag for this.
263424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        DeviceUtils.addDeviceSpecificUserAgentSwitch(mContext);
264424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
265424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        Context appContext = mContext.getApplicationContext();
266424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Now we really need to have the resources ready.
267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.waitForCompletion();
268424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        nativeSetCommandLineFlags(singleProcess, nativeIsPluginEnabled() ? getPlugins() : null);
270424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ContentMain.initApplicationContext(appContext);
2713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
2723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
274424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)     * Initialization needed for tests. Mainly used by content browsertests.
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
276424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    public void initChromiumBrowserProcessForTests() {
277424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        ResourceExtractor resourceExtractor = ResourceExtractor.get(mContext);
278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.startExtractingResources();
279424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        resourceExtractor.waitForCompletion();
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        nativeSetCommandLineFlags(false, null);
2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private String getPlugins() {
284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        return PepperPluginManager.getPlugins(mContext);
285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
286424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    private static native void nativeSetCommandLineFlags(
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            boolean singleProcess, String pluginDescriptor);
289424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
290424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Is this an official build of Chrome? Only native code knows for sure. Official build
291424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // knowledge is needed very early in process startup.
292424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native boolean nativeIsOfficialBuild();
293424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
294424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private static native boolean nativeIsPluginEnabled();
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
296