/**
   * Start the browser process asynchronously. This will set up a queue of UI thread tasks to
   * initialize the browser process.
   *
   * <p>Note that this can only be called on the UI thread.
   *
   * @param callback the callback to be called when browser startup is complete.
   */
  public void startBrowserProcessesAsync(final StartupCallback callback)
      throws ProcessInitException {
    assert ThreadUtils.runningOnUiThread() : "Tried to start the browser on the wrong thread.";
    if (mStartupDone) {
      // Browser process initialization has already been completed, so we can immediately post
      // the callback.
      postStartupCompleted(callback);
      return;
    }

    // Browser process has not been fully started yet, so we defer executing the callback.
    mAsyncStartupCallbacks.add(callback);

    if (!mHasStartedInitializingBrowserProcess) {
      // This is the first time we have been asked to start the browser process. We set the
      // flag that indicates that we have kicked off starting the browser process.
      mHasStartedInitializingBrowserProcess = true;

      prepareToStartBrowserProcess(MAX_RENDERERS_LIMIT);

      setAsynchronousStartup(true);
      if (contentStart() > 0) {
        // Failed. The callbacks may not have run, so run them.
        enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
      }
    }
  }
  /**
   * Start the browser process synchronously. If the browser is already being started asynchronously
   * then complete startup synchronously
   *
   * <p>Note that this can only be called on the UI thread.
   *
   * @param maxRenderers The maximum number of renderer processes the browser may create. Zero for
   *     single process mode.
   * @throws ProcessInitException
   */
  public void startBrowserProcessesSync(int maxRenderers) throws ProcessInitException {
    // If already started skip to checking the result
    if (!mStartupDone) {
      if (!mHasStartedInitializingBrowserProcess) {
        prepareToStartBrowserProcess(maxRenderers);
      }

      setAsynchronousStartup(false);
      if (contentStart() > 0) {
        // Failed. The callbacks may not have run, so run them.
        enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);
      }
    }

    // Startup should now be complete
    assert mStartupDone;
    if (!mStartupSuccess) {
      throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_STARTUP_FAILED);
    }
  }