Chromium扩展(Extension)加载过程分析

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

       Chromium在启动的时候,会根据当前用户的Profile创建一个Extension Service。Extension Service在创建过程中,会加载当前已经安装的所有Extension,并且将它们注册在一个Extension Registry中。以后通过这个Extension Registry,就可以得到当前可用的Extension的信息了。本文接下来就分析Extension的加载过程。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

       Chromium的启动,指的实际上是Chromium的Browser进程的启动。关于Chromium的多进程架构,可以参考前面Chromium多进程架构简要介绍和学习计划这个系列的文章。Chromium的Browser进程在启动之后,会创建一系列的Startup Task。每一个Startup Task都会负责初始化相应的模块。上述的Extension Service就是在一个Startup Task中创建的,如图1所示:


图1 Extension的加载过程

       Extension Service在创建的过程中,会通过一个Installed Loader加载当前已经安装的所有Extension,并且将那些设置为Enabled的Extension注册到Extension Registry中,从而得到一个当前可用的Extension列表。

       接下来,我们就从Chromium的Browser进程的启动开始,分析它加载Extension的过程。

       在前面Chromium硬件加速渲染的OpenGL上下文绘图表面创建过程分析一文中,我们以Content Shell APK为例,分析了Browser进程的启动过程。在这个启动过程中,会创建一个BrowserStartupController对象,并且调用这个BrowserStartupController对象的成员函数startBrowserProcessesAsync异步启动和初始化Chromium的Content模块,如下所示:

public class BrowserStartupController {    ......    public void startBrowserProcessesAsync(final StartupCallback callback)            throws ProcessInitException {        ......        // Browser process has not been fully started yet, so we defer executing the callback.        mAsyncStartupCallbacks.add(callback);        ......        if (!mHasStartedInitializingBrowserProcess) {            ......            prepareToStartBrowserProcess(MAX_RENDERERS_LIMIT);            ......            if (contentStart() > 0) {                // Failed. The callbacks may not have run, so run them.                enqueueCallbackExecution(STARTUP_FAILURE, NOT_ALREADY_STARTED);            }        }    }    ......}
      这个函数定义在文件external/chromium_org/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java中。

      在Browser进程的Content模块还没有启动过的情况下,BrowserStartupController类的成员变量mHasStartedInitializingBrowserProcess的值会等于false。在这种情况下,BrowserStartupController类的成员函数startBrowserProcessesAsync会做两件事情:

      1. 调用成员函数prepareToStartBrowserProcess在VM中加载libcontent_shell_content_view.so。

      2. 调用成员函数contentStart启动和初始化Content模块。

      从Dalvik虚拟机JNI方法的注册过程分析这篇文章可以知道,VM在加载so的过程中,将会调用它导出的一个名称为JNI_OnLoad的函数。对libcontent_shell_content_view.so来说,它导出的JNI_OnLoad函数的实现如下所示:

// This is called by the VM when the shared library is first loaded.JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {  ......  content::SetContentMainDelegate(new content::ShellMainDelegate());  return JNI_VERSION_1_4;}
      这个函数定义在文件external/chromium_org/content/shell/android/shell_library_loader.cc中。

      函数JNI_OnLoad将会创建一个ShellMainDelegate对象,并且调用函数SetContentMainDelegate将它保存在一个全局变量g_content_main_delegate中,如下所示:

namespace {......LazyInstance<scoped_ptr<contentmaindelegate> > g_content_main_delegate =    LAZY_INSTANCE_INITIALIZER;}  // namespacevoid SetContentMainDelegate(ContentMainDelegate* delegate) {  DCHECK(!g_content_main_delegate.Get().get());  g_content_main_delegate.Get().reset(delegate);}
      这个函数定义在文件external/chromium_org/content/app/android/content_main.cc中。

      这一步执行完成后,回到前面分析的BrowserStartupController类的成员函数startBrowserProcessesAsync中,它接下来将会调用另外一个成员函数contentStart启动和初始化Content模块,如下所示:

public class BrowserStartupController {    ......    int contentStart() {        return ContentMain.start();    }    ......}
       这个函数定义在文件external/chromium_org/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java中。

       BrowserStartupController类的成员函数contentStart调用ContentMain类的静态成员函数start在Browser进程中启动和初始化Content模块。在前面Chromium的Render进程启动过程分析一文中,我们已经分析过ContentMain类的静态成员函数start的实现了。它最终会调用到C++层的一个函数Start启动和初始化Content模块,如下所示:

namespace {LazyInstance<scoped_ptr<ContentMainRunner> > g_content_runner =    LAZY_INSTANCE_INITIALIZER;......}  // namespace......static jint Start(JNIEnv* env, jclass clazz) {  ......  if (!g_content_runner.Get().get()) {    ContentMainParams params(g_content_main_delegate.Get().get());    g_content_runner.Get().reset(ContentMainRunner::Create());    g_content_runner.Get()->Initialize(params);  }  return g_content_runner.Get()->Run();}

       这个函数定义在文件external/chromium_org/content/app/android/content_main.cc中。

       函数Start首先判断一个全局变量g_content_runner是否已经指向了一个ContentMainRunner对象。如果还没有指向,那么就会调用ContentMainRunner类的静态成员函数Create创建一个ContentMainRunner对象,如下所示:

ContentMainRunner* ContentMainRunner::Create() {  return new ContentMainRunnerImpl();}
       这个函数定义在文件external/chromium_org/content/app/content_main_runner.cc中。

       从这里可以看到,ContentMainRunner类的静态成员函数Create创建的实际上是一个ContentMainRunnerImpl对象。这个ContentMainRunnerImpl对象返回给前面分析的函数Start之后,就会保存在全局变量g_content_runner中。

       函数Start获得了新创建的ContentMainRunnerImpl对象之后,会调用它的成员函数Initialize,并且将全局变量g_content_main_delegate指向的ShellMainDelegate对象封装在一个类型为ContentMainParams的参数中传递给它,让它执行初始化工作。

      ContentMainRunnerImpl类的成员函数Initialize的实现如下所示:

class ContentMainRunnerImpl : public ContentMainRunner { public:  ......  virtual int Initialize(const ContentMainParams& params) OVERRIDE {    ......    delegate_ = params.delegate;    ......  }   ...... private:  ......  ContentMainDelegate* delegate_;    ......};
      这个函数定义在文件external/chromium_org/content/app/content_main_runner.cc中。

      ContentMainRunnerImpl类的成员函数Initialize将封装在参数params中的一个ShellMainDelegate对象保存在成员变量delegate_中,也就是ContentMainRunnerImpl类的成员变量delegate_指向了一个ShellMainDelegate对象。

      回到前面分析的函数Start中,它最后调用前面创建的ContentMainRunnerImpl对象的成员函数Run启动和初始化Content模块,如下所示:

class ContentMainRunnerImpl : public ContentMainRunner { public:  ......  virtual int Run() OVERRIDE {    ......    const CommandLine& command_line = *CommandLine::ForCurrentProcess();    std::string process_type =          command_line.GetSwitchValueASCII(switches::kProcessType);    MainFunctionParams main_params(command_line);    ......#if !defined(OS_IOS)    return RunNamedProcessTypeMain(process_type, main_params, delegate_);#else    return 1;#endif  }  ......};

       这个函数定义在文件external/chromium_org/content/app/content_main_runner.cc中。

       ContentMainRunnerImpl类的成员函数Run首先检查当前进程是否指定了switches::kProcessType启动选项。如果指定了,那么就会获取它的值。获取到的值保存在本地变量process_type中,表示当前进程的类型。Browser进程没有指定switches::kProcessType启动选项,因此本地变量process_type的值将为空,表示当前进程是Browser进程。

        ContentMainRunnerImpl类的成员函数Run接下来调用函数RunNamedProcessTypeMain启动和初始化Content模块,如下所示:

int RunNamedProcessTypeMain(    const std::string& process_type,    const MainFunctionParams& main_function_params,    ContentMainDelegate* delegate) static const MainFunction kMainFunctions[] = {#if !defined(CHROME_MULTIPLE_DLL_CHILD)    { "",                            BrowserMain },#endif#if !defined(CHROME_MULTIPLE_DLL_BROWSER)#if defined(ENABLE_PLUGINS)#if !defined(OS_LINUX)    { switches::kPluginProcess,      PluginMain },#endif    { switches::kWorkerProcess,      WorkerMain },    { switches::kPpapiPluginProcess, PpapiPluginMain },    { switches::kPpapiBrokerProcess, PpapiBrokerMain },#endif  // ENABLE_PLUGINS    { switches::kUtilityProcess,     UtilityMain },    { switches::kRendererProcess,    RendererMain },    { switches::kGpuProcess,         GpuMain },#endif  // !CHROME_MULTIPLE_DLL_BROWSER  };  ......  for (size_t i = 0; i < arraysize(kMainFunctions); ++i) {    if (process_type == kMainFunctions[i].name) {      if (delegate) {        int exit_code = delegate->RunProcess(process_type,            main_function_params);#if defined(OS_ANDROID)        // In Android's browser process, the negative exit code doesn't mean the        // default behavior should be used as the UI message loop is managed by        // the Java and the browser process's default behavior is always        // overridden.        if (process_type.empty())          
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值