webview创建过程分析(五)

今天我们来看下WebView的Browser端的启动过程,在前面webview创建过程分析(二)的分析中,我们知道WebViewChromium在init过程中会涉及到Browser端的启动,具体代码为

public void init(final Map javaScriptInterfaces,
            final boolean privateBrowsing) {
        if (privateBrowsing) {
            mFactory.startYourEngines(true);
            final String msg = "Private browsing is not supported in WebView.";
            if (mAppTargetSdkVersion >= Build.VERSION_CODES.KITKAT) {
                throw new IllegalArgumentException(msg);
            } else {
                Log.w(TAG, msg);
                TextView warningLabel = new TextView(mWebView.getContext());
                warningLabel.setText(mWebView.getContext().getString(
                        com.android.internal.R.string.webviewchromium_private_browsing_warning));
                mWebView.addView(warningLabel);
            }
        }
        // We will defer real initialization until we know which thread to do it on, unless:
        // - we are on the main thread already (common case),
        // - the app is targeting >= JB MR2, in which case checkThread enforces that all usage
        //   comes from a single thread. (Note in JB MR2 this exception was in WebView.java).
        if (mAppTargetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            //1.browser端启动逻辑
            mFactory.startYourEngines(false);
            checkThread();
        } else if (!mFactory.hasStarted()) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                mFactory.startYourEngines(true);
            }
        }
        ......
    }

今天我们就来分析这里Browser的启动逻辑,从上面的代码可以知道这里会调用WebViewChromiumFactoryProvider的startYourEngines方法,

void startYourEngines(boolean onMainThread) {
        try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped(
                     "WebViewChromiumFactoryProvider.startYourEngines")) {
            mAwInit.startYourEngines(onMainThread);
        }
    }

这里我们假设webview的创建是在主线程进行的,即这里的onMainThread为true,接着调用

WebViewChromiumAwInit.java的方法

void startYourEngines(boolean onMainThread) {
        synchronized (mLock) {
            ensureChromiumStartedLocked(onMainThread);
        }
    }
void ensureChromiumStartedLocked(boolean onMainThread) {
        assert Thread.holdsLock(mLock);

        if (mStarted) { // Early-out for the common case.
            return;
        }

        Looper looper = !onMainThread ? Looper.myLooper() : Looper.getMainLooper();
        Log.v(TAG, "Binding Chromium to "
                        + (Looper.getMainLooper().equals(looper) ? "main" : "background")
                        + " looper " + looper);

        //1.设置uiThread
        ThreadUtils.setUiThread(looper);

        if (ThreadUtils.runningOnUiThread()) {
            startChromiumLocked();
            return;
        }

        // We must post to the UI thread to cover the case that the user has invoked Chromium
        // startup by using the (thread-safe) CookieManager rather than creating a WebView.
        PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
            @Override
            public void run() {
                synchronized (mLock) {
                    startChromiumLocked();
                }
            }
        });
        while (!mStarted) {
            try {
                // Important: wait() releases |mLock| the UI thread can take it :-)
                mLock.wait();
            } catch (InterruptedException e) {
                // Keep trying... eventually the UI thread will process the task we sent it.
            }
        }
    }

由于webview在主线程中创建,所以这里的looper就是主线程的Looper,下面看下ThreadUtils.setUiThread的实现逻辑。

public static void setUiThread(Looper looper) {
        synchronized (sLock) {
            if (looper == null) {
                // Used to reset the looper after tests.
                sUiThreadHandler = null;
                return;
            }
            if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
                throw new RuntimeException("UI thread looper is already set to "
                        + sUiThreadHandler.getLooper() + " (Main thread looper is "
                        + Looper.getMainLooper() + "), cannot set to new looper " + looper);
            } else {
                sUiThreadHandler = new Handler(looper);
            }
        }
    }

这里创建了一个Handler,名为sUiThreadHandler,它的Looper就是主线程的Looper。

接下来就是调用startChormiumLocked方法

protected void startChromiumLocked() {
        try (ScopedSysTraceEvent event =
                        ScopedSysTraceEvent.scoped("WebViewChromiumAwInit.startChromiumLocked")) {
            assert Thread.holdsLock(mLock) && ThreadUtils.runningOnUiThread();

            // The post-condition of this method is everything is ready, so notify now to cover all
            // return paths. (Other threads will not wake-up until we release |mLock|, whatever).
            mLock.notifyAll();

            if (mStarted) {
                return;
            }

            ......

            AwBrowserProcess.start();
            ......

            mStarted = true;

        }
    }

这里会先判断之前有没有启动过,有的话就返回,没有就调用AwBrwoserProcess.start,然后标记为已启动,看下start的代码实现

public static void start() {
        try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("AwBrowserProcess.start")) {
            final Context appContext = ContextUtils.getApplicationContext();
            tryObtainingDataDirLock(appContext);
            // We must post to the UI thread to cover the case that the user
            // has invoked Chromium startup by using the (thread-safe)
            // CookieManager rather than creating a WebView.
            ThreadUtils.runOnUiThreadBlocking(() -> {

                //1.这里判断有没有设置多进程的属性,在android这里是单进程架构
                boolean multiProcess =
                      CommandLine.getInstance().hasSwitch(AwSwitches.WEBVIEW_SANDBOXED_RENDERER);
                if (multiProcess) {
                    ChildProcessLauncherHelper.warmUp(appContext, true);
                }
                // The policies are used by browser startup, so we need to register the policy
                // providers before starting the browser process. This only registers java objects
                // and doesn't need the native library.
                CombinedPolicyProvider.get().registerProvider(new AwPolicyProvider(appContext));

                // Check android settings but only when safebrowsing is enabled.
                try (ScopedSysTraceEvent e2 =
                                ScopedSysTraceEvent.scoped("AwBrowserProcess.maybeEnable")) {
                    AwSafeBrowsingConfigHelper.maybeEnableSafeBrowsingFromManifest(appContext);
                }

                try (ScopedSysTraceEvent e2 = ScopedSysTraceEvent.scoped(
                             "AwBrowserProcess.startBrowserProcessesSync")) {
                    BrowserStartupController.get(LibraryProcessType.PROCESS_WEBVIEW)
                            .startBrowserProcessesSync(!multiProcess);
                } catch (ProcessInitException e) {
                    throw new RuntimeException("Cannot initialize WebView", e);
                }
            });
        }
    }

这里主要逻辑是先通过BrowserStartupController的get方法获取一个BrowserStartupControllerImpl对象,再调用它的startBrowserProcessesSync方法。

@Override
    public void startBrowserProcessesSync(boolean singleProcess) throws ProcessInitException {
        ServicificationStartupUma.getInstance().record(
                ServicificationStartupUma.getStartupMode(mFullBrowserStartupDone,
                        mServiceManagerStarted, false /* startServiceManagerOnly */));

        // If already started skip to checking the result
        if (!mFullBrowserStartupDone) {
            if (!mHasStartedInitializingBrowserProcess || !mPostResourceExtractionTasksCompleted) {
                prepareToStartBrowserProcess(singleProcess, null);
            }

            boolean startedSuccessfully = true;
            if (!mHasCalledContentStart) {
                mCurrentBrowserStartType = BrowserStartType.FULL_BROWSER;
                if (contentStart() > 0) {
                    // Failed. The callbacks may not have run, so run them.
                    enqueueCallbackExecution(STARTUP_FAILURE);
                    startedSuccessfully = false;
                }
            } else if (mCurrentBrowserStartType == BrowserStartType.SERVICE_MANAGER_ONLY) {
                mCurrentBrowserStartType = BrowserStartType.FULL_BROWSER;
                if (contentStart() > 0) {
                    enqueueCallbackExecution(STARTUP_FAILURE);
                    startedSuccessfully = false;
                }
            }
            if (startedSuccessfully) {
                flushStartupTasks();
            }
        }

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

这里主要分为两步:调用prepareToStartBrowserProcess和contentStart,接下来我们分别看下这两个方法

void prepareToStartBrowserProcess(final boolean singleProcess,
            final Runnable completionCallback) throws ProcessInitException {
        Log.i(TAG, "Initializing chromium process, singleProcess=%b", singleProcess);

        // This strictmode exception is to cover the case where the browser process is being started
        // asynchronously but not in the main browser flow.  The main browser flow will trigger
        // library loading earlier and this will be a no-op, but in the other cases this will need
        // to block on loading libraries.
        // This applies to tests and ManageSpaceActivity, which can be launched from Settings.
        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
        try {
            // Normally Main.java will have already loaded the library asynchronously, we only need
            // to load it here if we arrived via another flow, e.g. bookmark access & sync setup.
            LibraryLoader.getInstance().ensureInitialized(mLibraryProcessType);
        } finally {
            StrictMode.setThreadPolicy(oldPolicy);
        }

        Runnable postResourceExtraction = new Runnable() {
            @Override
            public void run() {
                if (!mPostResourceExtractionTasksCompleted) {
                    // TODO(yfriedman): Remove dependency on a command line flag for this.
                    DeviceUtilsImpl.addDeviceSpecificUserAgentSwitch();
                    nativeSetCommandLineFlags(singleProcess);
                    mPostResourceExtractionTasksCompleted = true;
                }

                if (completionCallback != null) completionCallback.run();
            }
        };

    }

在prepareToStartBrowserProcess方法中,singleProcess为true,completionCallback为空,在该方法中主要是调用nativeSetCommandLineFlags方法。该方法是个native方法,其对应的jni方法在

BrowserStartupControllerImpl_jni.h中,

JNI_GENERATOR_EXPORT void
    Java_org_chromium_content_browser_BrowserStartupControllerImpl_nativeSetCommandLineFlags(
    JNIEnv* env,
    jclass jcaller,
    jboolean singleProcess) {
  return JNI_BrowserStartupControllerImpl_SetCommandLineFlags(env, singleProcess);
}

具体的实现在browser_startup_controller.cc中

static void JNI_BrowserStartupControllerImpl_SetCommandLineFlags(
    JNIEnv* env,
    jboolean single_process) {
  SetContentCommandLineFlags(static_cast(single_process));
}

这里的主要作用是向native设置为单进程模式。

接下来我们再回到startBrowserProcessesSync中,我们再看下contentStart方法的具体实现:

int contentStart() {
        boolean startServiceManagerOnly =
                mCurrentBrowserStartType == BrowserStartType.SERVICE_MANAGER_ONLY;
        int result = contentMainStart(startServiceManagerOnly);
        mHasCalledContentStart = true;
        // No need to launch the full browser again if we are launching full browser now.
        if (!startServiceManagerOnly) mLaunchFullBrowserAfterServiceManagerStart = false;
        return result;
    }
@VisibleForTesting
    int contentMainStart(boolean startServiceManagerOnly) {
        return ContentMain.start(startServiceManagerOnly);
    }

这里主要调用ContentMain的start方法,这里startServiceManagerOnly为默认值false,ContentMain的代码在ContentMain.java

public static int start(boolean startServiceManagerOnly) {
        return nativeStart(startServiceManagerOnly);
    }

private static native int nativeStart(boolean startServiceManagerOnly);

这里也是调用native方法,jni的代码在ContentMain_jni.h

static jint JNI_ContentMain_Start(JNIEnv* env, jboolean startServiceManagerOnly);

JNI_GENERATOR_EXPORT jint Java_org_chromium_content_app_ContentMain_nativeStart(
    JNIEnv* env,
    jclass jcaller,
    jboolean startServiceManagerOnly) {
  return JNI_ContentMain_Start(env, startServiceManagerOnly);
}

具体实现在content_main.cc

static jint JNI_ContentMain_Start(JNIEnv* env,
                                  jboolean start_service_manager_only) {
  TRACE_EVENT0("startup", "content::Start");

  DCHECK(!g_service_manager_main_delegate.Get() || !start_service_manager_only);

  if (!g_service_manager_main_delegate.Get()) {
    g_service_manager_main_delegate.Get() =
        std::make_unique(
            ContentMainParams(g_content_main_delegate.Get().get()));
  }

  static_cast(
      g_service_manager_main_delegate.Get().get())
      ->SetStartServiceManagerOnly(start_service_manager_only);

  service_manager::MainParams main_params(
      g_service_manager_main_delegate.Get().get());
  return service_manager::Main(main_params);
}

这里首先会创建ContentServiceManagerMainDelegate,ContentServiceManagerMainDelegate的逻辑。

ContentServiceManagerMainDelegate::ContentServiceManagerMainDelegate(
    const ContentMainParams& params)
    : content_main_params_(params),
      content_main_runner_(ContentMainRunnerImpl::Create()) {}

ContentServiceManagerMainDelegate对象需要一个ContentMainParms类型的参数,ContentMainParams结构为

ContentMainParams(ContentMainDelegate* delegate)
      : delegate(delegate) {}

它需要一个ContentMainDelegate对象,存放到自己的delegate中。而这个delegate是通过content_main.cc中的下面的代码设置的

void SetContentMainDelegate(ContentMainDelegate* delegate) {
  DCHECK(!g_content_main_delegate.Get().get());
  g_content_main_delegate.Get().reset(delegate);
}

具体的调用在webview_jni_onload.cc中,调用代码为

bool OnJNIOnLoadInit() {
  if (!content::android::OnJNIOnLoadInit())
    return false;

  base::android::SetVersionNumber(PRODUCT_VERSION);
  content::SetContentMainDelegate(new android_webview::AwMainDelegate());

  // Initialize url lib here while we are still single-threaded, in case we use
  // CookieManager before initializing Chromium (which would normally have done
  // this). It's safe to call this multiple times.
  url::Initialize();
  return true;
}

所以这里最终的ContentMainDelegate是一个AwMainDelegate,代码在aw_main_delegate.cc。

在ContentServiceManagerMainDelegate的创建过程中还会调用ContentMainRunnerImpl::Create方法创建ContentMainRunnerImpl对象。后面调用service_manager::Main方法,该方法比较长,这里截取一些主要的代码片段

.....
exit_code = delegate->Initialize(init_params);
......
exit_code = delegate->RunEmbedderProcess();
.....

在该方法中会调用ContentServiceManagerMainDelegate的Initialize方法和RunEmbedderProcess方法

int ContentServiceManagerMainDelegate::Initialize(
    const InitializeParams& params) {
#if defined(OS_ANDROID)
  // May be called twice on Android due to the way browser startup requests are
  // dispatched by the system.
  if (initialized_)
    return -1;
#endif

#if defined(OS_MACOSX)
  content_main_params_.autorelease_pool = params.autorelease_pool;
#endif

  return content_main_runner_->Initialize(content_main_params_);
}

进而调到ContentMainRunnerImpl的Initialize方法,这里主要是执行

ContentClientInitializer::Set(process_type, delegate_);

这里会创建一个AwContentBrowserClient对象。存放在delegate的content_browser_client_中。

再看下RunEmbedderProcess方法

int ContentServiceManagerMainDelegate::RunEmbedderProcess() {
  return content_main_runner_->Run(start_service_manager_only_);
}

这里会调用到ContentMainRunnerImpl的run方法中

int ContentMainRunnerImpl::Run(bool start_service_manager_only) {
  DCHECK(is_initialized_);
  DCHECK(!is_shutdown_);
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  std::string process_type =
      command_line.GetSwitchValueASCII(switches::kProcessType);

#if !defined(CHROME_MULTIPLE_DLL_BROWSER)
  // Run this logic on all child processes. Zygotes will run this at a later
  // point in time when the command line has been updated.
  if (!process_type.empty() &&
      process_type != service_manager::switches::kZygoteProcess) {
    InitializeFieldTrialAndFeatureList();
    delegate_->PostFieldTrialInitialization();
  }
#endif

  MainFunctionParams main_params(command_line);
  main_params.ui_task = ui_task_;
  main_params.created_main_parts_closure = created_main_parts_closure_;
#if defined(OS_WIN)
  main_params.sandbox_info = &sandbox_info_;
#elif defined(OS_MACOSX)
  main_params.autorelease_pool = autorelease_pool_;
#endif

  RegisterMainThreadFactories();

#if !defined(CHROME_MULTIPLE_DLL_CHILD)
  if (process_type.empty())
    return RunServiceManager(main_params, start_service_manager_only);
#endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)

  return RunOtherNamedProcessTypeMain(process_type, main_params, delegate_);
}

由于android webview是单进程架构,所以这里的process_type是空字符串。接着会创建MainFunctionParams对象main_params,接着调用RegisterMainThreadFactories来构造render线程的创建方法,以便后续请求url的时候使用,我们看下RegisterMainThreadFactories的实现

static void RegisterMainThreadFactories() {
  ......
  RenderProcessHostImpl::RegisterRendererMainThreadFactory(
      CreateInProcessRendererThread);
  ......
}

void RenderProcessHostImpl::RegisterRendererMainThreadFactory(
    RendererMainThreadFactoryFunction create) {
  g_renderer_main_thread_factory = create;
}
base::Thread* CreateInProcessRendererThread(
    const InProcessChildThreadParams& params) {
  return new InProcessRendererThread(params);
}

InProcessRendererThread::InProcessRendererThread(
    const InProcessChildThreadParams& params)
    : Thread("Chrome_InProcRendererThread"), params_(params) {
}

从上面的代码可以知道在RegisterMainThreadFactories方法中会有一个用来创建render线程的function,而这个function也是会保存在RenderProcessHostImpl的g_render_main_thread_factory中。

接着再回到run方法中,在run方法的最后最终会调到AwMainDelegate的RunProcess方法中。

int AwMainDelegate::RunProcess(
    const std::string& process_type,
    const content::MainFunctionParams& main_function_params) {
  if (process_type.empty()) {
    browser_runner_ = content::BrowserMainRunner::Create();
    int exit_code = browser_runner_->Initialize(main_function_params);
    DCHECK_LT(exit_code, 0);

    // Return 0 so that we do NOT trigger the default behavior. On Android, the
    // UI message loop is managed by the Java application.
    return 0;
  }

  return -1;
}

这里会先调用BrowserMainRunner::Create创建一个BrowserMainRunnerImpl对象,接着调用该对象的Initialize方法。

int BrowserMainRunnerImpl::Initialize(const MainFunctionParams& parameters) {
  SCOPED_UMA_HISTOGRAM_LONG_TIMER(
      "Startup.BrowserMainRunnerImplInitializeLongTime");
  TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize");

  // On Android we normally initialize the browser in a series of UI thread
  // tasks. While this is happening a second request can come from the OS or
  // another application to start the browser. If this happens then we must
  // not run these parts of initialization twice.
  if (!initialization_started_) {
    initialization_started_ = true;

    const base::TimeTicks start_time_step1 = base::TimeTicks::Now();

    base::SamplingHeapProfiler::Init();
    if (parameters.command_line.HasSwitch(switches::kSamplingHeapProfiler)) {
      base::SamplingHeapProfiler* profiler = base::SamplingHeapProfiler::Get();
      unsigned sampling_interval = 0;
      bool parsed =
          base::StringToUint(parameters.command_line.GetSwitchValueASCII(
                                 switches::kSamplingHeapProfiler),
                             &sampling_interval);
      if (parsed && sampling_interval > 0)
        profiler->SetSamplingInterval(sampling_interval * 1024);
      profiler->Start();
    }

    SkGraphics::Init();

    if (parameters.command_line.HasSwitch(switches::kWaitForDebugger))
      base::debug::WaitForDebugger(60, true);

    if (parameters.command_line.HasSwitch(switches::kBrowserStartupDialog))
      WaitForDebugger("Browser");

    notification_service_.reset(new NotificationServiceImpl);

#if defined(OS_WIN)
    // Ole must be initialized before starting message pump, so that TSF
    // (Text Services Framework) module can interact with the message pump
    // on Windows 8 Metro mode.
    ole_initializer_.reset(new ui::ScopedOleInitializer);
    gfx::win::InitializeDirectWrite();
#endif  // OS_WIN

    main_loop_.reset(
        new BrowserMainLoop(parameters, std::move(scoped_execution_fence_)));

    main_loop_->Init();

    if (parameters.created_main_parts_closure) {
      parameters.created_main_parts_closure->Run(main_loop_->parts());
      delete parameters.created_main_parts_closure;
    }

    const int early_init_error_code = main_loop_->EarlyInitialization();
    if (early_init_error_code > 0)
      return early_init_error_code;

    // Must happen before we try to use a message loop or display any UI.
    if (!main_loop_->InitializeToolkit())
      return 1;

    main_loop_->PreMainMessageLoopStart();
    main_loop_->MainMessageLoopStart();
    main_loop_->PostMainMessageLoopStart();

    // WARNING: If we get a WM_ENDSESSION, objects created on the stack here
    // are NOT deleted. If you need something to run during WM_ENDSESSION add it
    // to browser_shutdown::Shutdown or BrowserProcess::EndSession.

    ui::InitializeInputMethod();
    UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep1Time",
                        base::TimeTicks::Now() - start_time_step1);
  }
  const base::TimeTicks start_time_step2 = base::TimeTicks::Now();
  main_loop_->CreateStartupTasks();
  int result_code = main_loop_->GetResultCode();
  if (result_code > 0)
    return result_code;

  UMA_HISTOGRAM_TIMES("Startup.BrowserMainRunnerImplInitializeStep2Time",
                      base::TimeTicks::Now() - start_time_step2);

  // Return -1 to indicate no early termination.
  return -1;
}

我们看下这个初始化过程涉及到的主要逻辑

1.创建BrowserMainLoop对象,放在成员变量main_loop_中

2.调用main_loop_的init方法

void BrowserMainLoop::Init() {
  TRACE_EVENT0("startup", "BrowserMainLoop::Init");

  // |startup_data| is optional. If set, the thread owned by the data
  // will be registered as BrowserThread::IO in CreateThreads() instead of
  // creating a brand new thread.
  if (parameters_.startup_data) {
    StartupDataImpl* startup_data =
        static_cast(parameters_.startup_data);
    // This is always invoked before |io_thread_| is initialized (i.e. never
    // resets it).
    io_thread_ = std::move(startup_data->thread);
    service_manager_context_ = startup_data->service_manager_context;
  }

  parts_.reset(
      GetContentClient()->browser()->CreateBrowserMainParts(parameters_));
}

这里主要会创建一个AwBrowserMainParts对象,放在BrowserMainLoop的parts_中

3.调用main_loop_的EarlyInitialization方法,该方法中会调用parts_的PreEarlyInitialization方法

int AwBrowserMainParts::PreEarlyInitialization() {
  // Network change notifier factory must be singleton, only set factory
  // instance while it is not been created.
  // In most cases, this check is not necessary because SetFactory should be
  // called only once, but both webview and native cronet calls this function,
  // in case of building both webview and cronet to one app, it is required to
  // avoid crashing the app.
  if (!net::NetworkChangeNotifier::GetFactory()) {
    net::NetworkChangeNotifier::SetFactory(
        new AwNetworkChangeNotifierFactory());
  }

  // Creates a MessageLoop for Android WebView if doesn't yet exist.
  DCHECK(!main_message_loop_.get());
  if (!base::MessageLoopCurrent::IsSet())
    main_message_loop_.reset(new base::MessageLoopForUI);
  return service_manager::RESULT_CODE_NORMAL_EXIT;
}

这里主要是创建一个MessageLoopForUI给main_message_loop_,MessageLoopForUI继承MessageLoop。

4.调用main_loop_的MainMessageLoopStart方法

void BrowserMainLoop::MainMessageLoopStart() {
  // DO NOT add more code here. Use PreMainMessageLoopStart() above or
  // PostMainMessageLoopStart() below.

  TRACE_EVENT0("startup", "BrowserMainLoop::MainMessageLoopStart");
  DCHECK(base::MessageLoopCurrentForUI::IsSet());
  InitializeMainThread();
}
void BrowserMainLoop::InitializeMainThread() {
  TRACE_EVENT0("startup", "BrowserMainLoop::InitializeMainThread");
  base::PlatformThread::SetName("CrBrowserMain");

  // Register the main thread. The main thread's task runner should already have
  // been initialized in MainMessageLoopStart() (or before if
  // MessageLoopCurrent::Get() was externally provided).
  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
  main_thread_.reset(new BrowserThreadImpl(
      BrowserThread::UI, base::ThreadTaskRunnerHandle::Get()));
  // TODO(https://crbug.com/863341): Replace with a better API
  GetContentClient()->browser()->PostAfterStartupTask(
      FROM_HERE, base::SequencedTaskRunnerHandle::Get(), base::BindOnce([]() {
        content::BrowserTaskExecutor::NotifyBrowserStartupCompleted();
      }));
}

这里主要是为browser端设置main_thread_,即创建一个BrowserThreadImpl,该线程的名字为BrowserThread::UI,同时该线程还有个handler,后续可以通过该handler向该线程发送消息。

5.调用main_loop_的CreateStartupTasks方法

void BrowserMainLoop::CreateStartupTasks() {
  TRACE_EVENT0("startup", "BrowserMainLoop::CreateStartupTasks");

  ........
 
  StartupTask pre_create_threads =
      base::Bind(&BrowserMainLoop::PreCreateThreads, base::Unretained(this));
  startup_task_runner_->AddTask(std::move(pre_create_threads));

  StartupTask create_threads =
      base::Bind(&BrowserMainLoop::CreateThreads, base::Unretained(this));
  startup_task_runner_->AddTask(std::move(create_threads));

  .........
}

该方法中会创建很多线程,我们看下PreCreateThreads和CreateThreads

int BrowserMainLoop::PreCreateThreads() {
  ......

#if !defined(GOOGLE_CHROME_BUILD) || defined(OS_ANDROID)
  // Single-process is an unsupported and not fully tested mode, so
  // don't enable it for official Chrome builds (except on Android).
  if (parsed_command_line_.HasSwitch(switches::kSingleProcess))
    RenderProcessHost::SetRunRendererInProcess(true);
#endif
  .......
}

在PreCreateThreads中会设置render端为单进程,这是通过RenderProcessHost::SetRunRenderInProcess来的

void RenderProcessHost::SetRunRendererInProcess(bool value) {
  g_run_renderer_in_process = value;

  ......
}

这里会将g_run_render_in_process的值置为true,保存在RenderProcessHostImpl中。

接下来我们看下其中IO线程的创建。该创建过程在CreateThreads中

int BrowserMainLoop::CreateThreads() {
  TRACE_EVENT0("startup,rail", "BrowserMainLoop::CreateThreads");

  // Release the ThreadPool's threads.
  scoped_execution_fence_.reset();

  // The |io_thread| can have optionally been injected into Init(), but if not,
  // create it here. Thre thread is only tagged as BrowserThread::IO here in
  // order to prevent any code from statically posting to it before
  // CreateThreads() (as such maintaining the invariant that PreCreateThreads()
  // et al. "happen-before" BrowserThread::IO is "brought up").
  if (!io_thread_) {
    io_thread_ = BrowserProcessSubThread::CreateIOThread();
  }
  io_thread_->RegisterAsBrowserThread();

  created_threads_ = true;
  return result_code_;
}
BrowserProcessSubThread::CreateIOThread() {
  TRACE_EVENT0("startup", "BrowserProcessSubThread::CreateIOThread");
  base::Thread::Options options;
  options.message_loop_type = base::MessageLoop::TYPE_IO;
#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(USE_OZONE)
  // Up the priority of the |io_thread_| as some of its IPCs relate to
  // display tasks.
  options.priority = base::ThreadPriority::DISPLAY;
#endif
  std::unique_ptr io_thread(
      new BrowserProcessSubThread(BrowserThread::IO));
  if (!io_thread->StartWithOptions(options))
    LOG(FATAL) << "Failed to start BrowserThread:IO";
  return io_thread;
}

这样我们整个browser端的构建过程就基本结束了。

各人认为这里最主要要清楚的就是在WebViewChromium的创建过程中,会在native层创建一个browser线程,这个线程就是java层的ui线程,后续chromium要在browser线程中处理一些task的时候都会抛到这个线程中来,同时还会创建IO线程等

你可能感兴趣的:(android,webview)