之前的博客介绍了chromium代码的下载和编译,调试环境的搭建。接下来我们根据编译的WebViewInstrumentation.apk来梳理浏览器的入口,看看chromium demo apk的启动流程。

从日志上看WebViewInstrumentation.apk 的activity是:org.chromium.android_webview.shell/.AwShellActivity。我们看看webview apk的启动流程。

当Android程序启动时系统会创建一个Application对象,用来存储系统的一些信息。Android系统自动会为每个程序运行时创建一个Application类的对象且只创建一个,所以Application可以说是单例(singleton)模式的一个类。通常们是不需要指定一个Application的,系统会自动帮我们创建,WebViewInstrumentation apk在AndroidManifest.xml 文件中的application标签添加了AwShellApplication。所以我们先看看AwShellApplication.java都做了什么,代码如下:

public class AwShellApplication extends Application {// Called by the framework for ALL processes. Runs before ContentProviders are created.// Quirk: context.getApplicationContext() returns null during this method.@Overrideprotected void attachBaseContext(Context context) {super.attachBaseContext(context);ContextUtils.initApplicationContext(this);PathUtils.setPrivateDataDirectorySuffix("webview", "WebView");CommandLine.initFromFile("/data/local/tmp/android-webview-command-line");ResourceBundle.setAvailablePakLocales(new String[] {}, AwLocaleConfig.getWebViewSupportedPakLocales());}
}

这部分的实现都是在base目录下,这里都是一些初始化的操作,这里也记住下commoand读取的路径。好了接着看AwShellActivity.java onCreate执行了哪些操作:

1 首先调用registerResources(this),其实现就是调用getResources获取resource,然后存储在AwResource全局变量sResources中,  设置Uuid存储在AwResource就没干啥了;

2  AwBrowserProcess.loadLibrary(null) ,加载库;

3 判断/data/local/tmp/android-webview-command-line是否含trace命令,如果有则设置trace enable;

4 createAwTestContainerView,可以看到其实现先调用AwBrowserProcess.start()起browser进程,new AwTestContainerView设置硬件渲染,new AwSettings部分参数设置,new AwDevToolsServer,将devtool调试开关设置为开;

5 然后是获取NavigationController,设置焦点、URL初始化,前进、后退安静初始化,加载URL

    public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);AwShellResourceProvider.registerResources(this);AwBrowserProcess.loadLibrary(null);if (CommandLine.getInstance().hasSwitch(AwShellSwitches.ENABLE_ATRACE)) {Log.e(TAG, "Enabling Android trace.");TraceEvent.setATraceEnabled(true);}setContentView(R.layout.testshell_activity);mAwTestContainerView = createAwTestContainerView();mWebContents = mAwTestContainerView.getWebContents();mNavigationController = mWebContents.getNavigationController();LinearLayout contentContainer = (LinearLayout) findViewById(R.id.content_container);mAwTestContainerView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1f));contentContainer.addView(mAwTestContainerView);mAwTestContainerView.requestFocus();initializeUrlField();initializeNavigationButtons();String startupUrl = getUrlFromIntent(getIntent());if (TextUtils.isEmpty(startupUrl)) {startupUrl = INITIAL_URL;}mAwTestContainerView.getAwContents().loadUrl(startupUrl);AwContents.setShouldDownloadFavicons();mUrlTextView.setText(startupUrl);}

代码路径:./android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellActivity.java

接下来看看上面1~5的实现:

1、registerResources的实现,并没什么复杂的操作;

    public static void registerResources(Context context) {if (sInitialized) {return;}AwResource.setResources(context.getResources());AwResource.setConfigKeySystemUuidMapping(R.array.config_key_system_uuid_mapping);sInitialized = true;}

代码路径:./android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellResourceProvider.java

2、AwBrowserProcess.loadLibrary(null) ,加载库

    public static void loadLibrary(String processDataDirSuffix) {LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_WEBVIEW);if (processDataDirSuffix == null) {PathUtils.setPrivateDataDirectorySuffix(WEBVIEW_DIR_BASENAME, "WebView");} else {String processDataDirName = WEBVIEW_DIR_BASENAME + "_" + processDataDirSuffix;PathUtils.setPrivateDataDirectorySuffix(processDataDirName, processDataDirName);}StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();try {LibraryLoader.getInstance().loadNow();// Switch the command line implementation from Java to native.// It's okay for the WebView to do this before initialization because we have// setup the JNI bindings by this point.LibraryLoader.getInstance().switchCommandLineForWebView();} finally {StrictMode.setThreadPolicy(oldPolicy);}}

代码路径:./android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java

如果想跟整个so的加载流程,可以在loadWithSystemLinkerAlreadyLocked函数中添加堆栈,查看整个调用流程

    private void loadWithSystemLinkerAlreadyLocked(ApplicationInfo appInfo, boolean inZygote) {setEnvForNative();preloadAlreadyLocked(appInfo, inZygote);// If the libraries are located in the zip file, assert that the device API level is M or// higher. On devices <=M, the libraries should always be loaded by LegacyLinker.assert !isInZipFile() || Build.VERSION.SDK_INT >= VERSION_CODES.M;// Load libraries using the system linker.for (String library : NativeLibraries.LIBRARIES) {if (!isInZipFile()) {System.loadLibrary(library);} else {// Load directly from the APK.boolean is64Bit = ApiHelperForM.isProcess64Bit();String zipFilePath = appInfo.sourceDir;boolean crazyPrefix = forceSystemLinker(); // See comment in this function.String fullPath = zipFilePath + "!/"+ makeLibraryPathInZipFile(library, crazyPrefix, is64Bit);Log.i(TAG, "libraryName: %s", fullPath);System.load(fullPath);}}}

代码路径:./base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java

3 判断/data/local/tmp/android-webview-command-line是否含trace命令,如果有则设置trace enable

    public static void setATraceEnabled(boolean enabled) {if (sATraceEnabled == enabled) return;sATraceEnabled = enabled;if (enabled) {// Calls TraceEvent.setEnabled(true) via// TraceLog::EnabledStateObserver::OnTraceLogEnabledTraceEventJni.get().startATrace();} else {// Calls TraceEvent.setEnabled(false) via// TraceLog::EnabledStateObserver::OnTraceLogDisabledTraceEventJni.get().stopATrace();}}

代码路径:./base/android/java/src/org/chromium/base/TraceEvent.java

4 createAwTestContainerView的函数实现如下

    private AwTestContainerView createAwTestContainerView() {AwBrowserProcess.start();AwTestContainerView testContainerView = new AwTestContainerView(this, true);......SharedPreferences sharedPreferences =getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);if (mBrowserContext == null) {mBrowserContext = new AwBrowserContext(sharedPreferences, AwBrowserContext.getDefault().getNativePointer(), true);}final AwSettings awSettings =new AwSettings(this /* context */, false /* isAccessFromFileURLsGrantedByDefault */,false /* supportsLegacyQuirks */, false /* allowEmptyDocumentPersistence */,true /* allowGeolocationOnInsecureOrigins */,false /* doNotUpdateSelectionOnMutatingSelectionRange */);// Required for WebGL conformance tests.awSettings.setMediaPlaybackRequiresUserGesture(false);// Allow zoom and fit contents to screenawSettings.setBuiltInZoomControls(true);awSettings.setDisplayZoomControls(false);awSettings.setUseWideViewPort(true);awSettings.setLoadWithOverviewMode(true);awSettings.setLayoutAlgorithm(AwSettings.LAYOUT_ALGORITHM_TEXT_AUTOSIZING);testContainerView.initialize(new AwContents(mBrowserContext, testContainerView,testContainerView.getContext(), testContainerView.getInternalAccessDelegate(),testContainerView.getNativeDrawFunctorFactory(), awContentsClient, awSettings));testContainerView.getAwContents().getSettings().setJavaScriptEnabled(true);if (mDevToolsServer == null) {mDevToolsServer = new AwDevToolsServer();mDevToolsServer.setRemoteDebuggingEnabled(true);}return testContainerView;}

4.1 我们先来看如何browser线程,看start的实现如下,调用了startBrowserProcessesSync函数

    public static void start() {try (ScopedSysTraceEvent e1 = ScopedSysTraceEvent.scoped("AwBrowserProcess.start")) {final Context appContext = ContextUtils.getApplicationContext();AwDataDirLock.lock(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(() -> {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.getInstance().startBrowserProcessesSync(LibraryProcessType.PROCESS_WEBVIEW, !multiProcess);}});}}

代码路径:./android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java

startBrowserProcessesSync 实现代码如下,通过调用contentStart函数,调用ContentMain.start()函数:

    public void startBrowserProcessesSync(@LibraryProcessType int libraryProcessType, boolean singleProcess) {......if (contentStart() > 0) {// Failed. The callbacks may not have run, so run them.enqueueCallbackExecution(STARTUP_FAILURE);startedSuccessfully = false;}......}

代码路径:./content/public/android/java/src/org/chromium/content/browser/BrowserStartupControllerImpl.java

ContentMain.start函数实现如下,往下调用的函数是jni函数nativeStart:

    public static int start(boolean startServiceManagerOnly) {return ContentMainJni.get().start(startServiceManagerOnly);}

代码路径:./content/public/android/java/src/org/chromium/content/app/ContentMain.java

接下来我们看看nativeStart在c++做啥,函数实现如下,调用service_manager Main;

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<ContentServiceManagerMainDelegate>(ContentMainParams(g_content_main_delegate.Get().get()));}static_cast<ContentServiceManagerMainDelegate*>(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);
}

代码路径:./content/app/android/content_main.cc

接着往下看看service_manager Main做了什么,做了mojo的初始然,然后是通过delegate->RunEmbedderProcess()调用content_service_manager_main_delegate.cc的RunEmbedderProcess。

int Main(const MainParams& params) {MainDelegate* delegate = params.delegate;......int exit_code = -1;base::debug::GlobalActivityTracker* tracker = nullptr;ProcessType process_type = delegate->OverrideProcessType();static bool is_initialized = false;if (!is_initialized) {is_initialized = true;
......mojo::core::Configuration mojo_config;if (process_type == ProcessType::kDefault &&command_line.GetSwitchValueASCII(switches::kProcessType) ==switches::kProcessTypeServiceManager) {mojo_config.is_broker_process = true;}mojo_config.max_message_num_bytes = kMaximumMojoMessageSize;delegate->OverrideMojoConfiguration(&mojo_config);mojo::core::Init(mojo_config);ui::RegisterPathProvider();tracker = base::debug::GlobalActivityTracker::Get();exit_code = delegate->Initialize(init_params);if (exit_code >= 0) {if (tracker) {tracker->SetProcessPhase(base::debug::GlobalActivityTracker::PROCESS_LAUNCH_FAILED);tracker->process_data().SetInt("exit-code", exit_code);}return exit_code;}......if (base::CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTraceToConsole)) {base::trace_event::TraceConfig trace_config =tracing::GetConfigForTraceToConsole();base::trace_event::TraceLog::GetInstance()->SetEnabled(trace_config, base::trace_event::TraceLog::RECORDING_MODE);}}const auto& command_line = *base::CommandLine::ForCurrentProcess();if (process_type == ProcessType::kDefault) {std::string type_switch =command_line.GetSwitchValueASCII(switches::kProcessType);if (type_switch == switches::kProcessTypeServiceManager) {process_type = ProcessType::kServiceManager;} else if (type_switch == switches::kProcessTypeService) {process_type = ProcessType::kService;} else {process_type = ProcessType::kEmbedder;}}switch (process_type) {case ProcessType::kDefault:NOTREACHED();break;case ProcessType::kServiceManager:exit_code = RunServiceManager(delegate);break;case ProcessType::kService:CommonSubprocessInit();exit_code = RunService(delegate);break;case ProcessType::kEmbedder:if (delegate->IsEmbedderSubprocess())CommonSubprocessInit();exit_code = delegate->RunEmbedderProcess();break;}if (tracker) {if (exit_code == 0) {tracker->SetProcessPhaseIfEnabled(base::debug::GlobalActivityTracker::PROCESS_EXITED_CLEANLY);} else {tracker->SetProcessPhaseIfEnabled(base::debug::GlobalActivityTracker::PROCESS_EXITED_WITH_CODE);tracker->process_data().SetInt("exit-code", exit_code);}}
......if (process_type == ProcessType::kEmbedder)delegate->ShutDownEmbedderProcess();return exit_code;
}

代码路径:./services/service_manager/embedder/main.cc

然后可以看content_main_runner_impl.cc的Run函数,调用RegisterMainThreadFactories,创建InProcessUtility、InProcessRenderer、InProcessGpu线程并注册。然后是调用RunServiceManager,然后是创建起来的相关任务,我在browser_main_loop.cc的CreateStartupTasks函数中添加了堆栈,方便看流程。

int ContentMainRunnerImpl::Run(bool start_service_manager_only) {
......const base::CommandLine& command_line =*base::CommandLine::ForCurrentProcess();std::string process_type =command_line.GetSwitchValueASCII(switches::kProcessType);// 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();}......RegisterMainThreadFactories();if (process_type.empty()){    return RunServiceManager(main_params, start_service_manager_only);}return RunOtherNamedProcessTypeMain(process_type, main_params, delegate_);
}

代码路径:./content/app/content_main_runner_impl.cc

堆栈打印的流程如下,接着往下可以看看都创建了什么任务:

./../../content/browser/browser_main_loop.cc:899         BrowserMainLoop::CreateStartupTasks
./../../content/browser/browser_main_runner_impl.cc:129     main_loop_->CreateStartupTasks();
./../../android_webview/lib/aw_main_delegate.cc:307         int exit_code = browser_runner_->Initialize(main_function_params);
./../../content/app/content_main_runner_impl.cc:502         int exit_code = delegate->RunProcess("", main_function_params);
./../../content/app/content_main_runner_impl.cc:950         return RunBrowserProcessMain(main_params, delegate_);
./../../content/app/content_main_runner_impl.cc:851         return RunServiceManager(main_params, start_service_manager_only);
./../../services/service_manager/embedder/main.cc:459       exit_code = delegate->RunEmbedderProcess();
./../../content/app/android/content_main.cc:62              return service_manager::Main(main_params);

4.2 然后是DevToolsServer对象的新建,devtool不太了解的小伙伴可以看看这个链接,devtool sever的开启便于后面的调试 https://developers.google.com/web/tools/chrome-devtools。这里只介绍如何启动devtool server,不介绍devtool server 如何实现。

        if (mDevToolsServer == null) {mDevToolsServer = new AwDevToolsServer();mDevToolsServer.setRemoteDebuggingEnabled(true);}
    public void setRemoteDebuggingEnabled(boolean enabled) {AwDevToolsServerJni.get().setRemoteDebuggingEnabled(AwDevToolsServer.this, mNativeDevToolsServer, enabled);}
static void JNI_AwDevToolsServer_SetRemoteDebuggingEnabled(JNIEnv* env,const JavaParamRef<jobject>& obj,jlong server,jboolean enabled) {AwDevToolsServer* devtools_server =reinterpret_cast<AwDevToolsServer*>(server);if (enabled) {devtools_server->Start();} else {devtools_server->Stop();}
}

代码路径:./android_webview/browser/aw_devtools_server.cc

5 我们来看看URL的加载mAwTestContainerView.getAwContents().loadUrl(startupUrl);兜兜转转会调用到NavigationControllerImpl.java的loadUrl函数,调用一个JNI又是到C++了,调用的是navigation_controller_impl.cc的LoadURL,后面资源加载部分,再对整个请求流程进行分析。

    public void loadUrl(LoadUrlParams params) {if (mNativeNavigationControllerAndroid != 0) {NavigationControllerImplJni.get().loadUrl(mNativeNavigationControllerAndroid,NavigationControllerImpl.this, params.getUrl(), params.getLoadUrlType(),params.getTransitionType(),params.getReferrer() != null ? params.getReferrer().getUrl() : null,params.getReferrer() != null ? params.getReferrer().getPolicy() : 0,params.getUserAgentOverrideOption(), params.getExtraHeadersString(),params.getPostData(), params.getBaseUrl(), params.getVirtualUrlForDataUrl(),params.getDataUrlAsString(), params.getCanLoadLocalResources(),params.getIsRendererInitiated(), params.getShouldReplaceCurrentEntry());}}

代码路径:./content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java

往下就是开始资源加载了,在下篇博客中进行更新

chromium 84.0.4122.0 WebView apk 启动流程相关推荐

  1. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

  2. Android 4.0 ICS SystemUI浅析——SystemUI启动流程

    阅读Android 4.0源码也有一段时间了,这次是针对SystemUI的一个学习过程.本文只是对SystemUI分析的一个开始--启动流程的分析,网上有很多关于2.3的SystemUI的分析,可4. ...

  3. 从0移植uboot (二) _uboot启动流程分析

    经过了上一篇的配置,我们已经执行make就可以编译出一个uboot.bin,但这还不够,首先,此时的uboot并不符合三星芯片对bootloader的格式要求,同时,此时的uboot.bin也没有结合 ...

  4. 从0移植uboot (二) _启动流程分析

    来源:Linux社区  作者:xiaojiang1025  : http://www.linuxidc.com/Linux/2017-02/141019.htm 经过了上一篇的配置,我们已经执行mak ...

  5. Android 10.0 系统服务之ActivityMnagerService-AMS启动流程-[Android取经之路]

    摘要:上一节我们讲完了SystemServer的启动过程,这一节接着上一节的步骤,来讲解ActivityManagerService的启动过程. ActivityManagerService简称AMS ...

  6. Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]

    摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...

  7. Android App启动流程详解

    前言:在之前的文章中已经写了apk的打包流程.安装流程,今天就是梳理一下apk系列的最后的流程--app启动流程.经过今天的梳理以后咱们就可以对apk包是怎么编译生成的.apk是怎么被安装到安卓手机的 ...

  8. Android10.0 四大组件与进程启动间关系

    原文地址:https://skytoby.github.io/2019/Android%E5%9B%9B%E5%A4%A7%E7%BB%84%E4%BB%B6%E4%B8%8E%E8%BF%9B%E7 ...

  9. android serialport new 软件退出_基于Android9.0,了解Android启动流程

    先记住四个进程和三种方式. **四个进程** 1.Launcher进程 2.system_server进程 3.App进程 4.Zygote进程 **三种方式** 1.Binder方式 2.Socke ...

最新文章

  1. npm安装serve实现静态资源的访问
  2. 中断(interrupted()、isInterrupted())、Executor的中断
  3. WP8.1学习系列(第二十二章)——在页面之间导航
  4. when and where is createContent called
  5. Python第三方库的安装,升级以及版本查看
  6. scratch飞机大战图片素材包,值得您的分享!
  7. 5、优化方法:随机梯度下降法
  8. Oblog 4.5-4.6 accessmssql getshell 0day
  9. 计算机体系结构多处理器性能评价指标——加速比
  10. 单稳态电路和双稳态电路电路详解 CD4013触发器开关电路驱动继电器
  11. Java Lempel-Ziv
  12. 找金币问题/只秤一次找出真假金币在哪个箱子
  13. 虚拟桌面的服务器,虚拟桌面与集合
  14. python 字符串方法总结
  15. Bear and Big Brother
  16. 类器官——从 2D 到 3D 的进阶
  17. GB9706.1-2020安规三项之漏电流测试方法
  18. SecureCRT常用命令分享 SecureCRT命令大全
  19. 图像去模糊(一)——理解模糊核
  20. 疯狂kotlin讲义连载之Kotlin的基础类型--字符串

热门文章

  1. 解决微信登录Emoji表情昵称乱码问题
  2. matlab 两个txt文件的合并。。
  3. AAM Alignment最后一篇:Robust AAM Alignment with Occlusion
  4. 对话哈佛大学教授Lukin:量子计算将在我们有生之年普及! | AI英雄
  5. 十大免费教程资源帮助新手快速学习JavaScript
  6. NO.7--定区关联快递员前台系统注册用户(发送验证码)
  7. JAVA GUI(图形用户界面)
  8. Intel SGX入门教程(二)在windows环境搭建intel sgx环境并运行helloworld程序
  9. sql语句查询某天、某周、某月、某年的数据
  10. win10如何隐藏任务栏