今天我们来看下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线程等