Chromium扩展Extension的页面Page加载过程分析.docx
- 文档编号:12263434
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:25
- 大小:64.47KB
Chromium扩展Extension的页面Page加载过程分析.docx
《Chromium扩展Extension的页面Page加载过程分析.docx》由会员分享,可在线阅读,更多相关《Chromium扩展Extension的页面Page加载过程分析.docx(25页珍藏版)》请在冰豆网上搜索。
Chromium扩展Extension的页面Page加载过程分析
Chromium扩展(Extension)的页面(Page)加载过程分析
Chromium的ExtensionPage其实就是网页,因此它们的加载过程与普通网页相同。
常见的ExtensionPage有BackgroundPage和PopupPage。
其中,BackgroundPage在浏览器窗口初始化完成后自动加载,之后运行在后台中。
PopupPage在用户点击地址栏右边的按钮时加载,并且显示在弹窗中。
本文接下来就分析ExtensionPage的加载过程。
ExtensionPage是加载在ExtensionProcess中的,如图1所示:
ExtensionProcess实际上就是RenderProcess。
Chromium的Content层向外提供了一个WebContents类,通过调用这个类的静态成员函数Create就可以在一个ExtensionProcess加载一个指定的ExtensionPage。
BackgroundPage是一个特殊的网页,它的内容是空的,不过包含有一个background.js。
这个background.js是在Extension的清单文件中指定的。
PopupPage则与普通网页是一样的,它既可以包含有UI元素,也可以包含JavaScript脚本。
接下来,我们就结合源代码,先分析BackgroundPage的加载过程,再分析PopupPage的加载过程。
Chromium的chrome模块会创建一个ChromeNotificationObserver对象,用来监听每一个新打开的浏览器窗口的NOTIFICATION_BROWSER_WINDOW_READY事件。
这时候上述ChromeNotificationObserver对象的成员函数OnBrowserWindowReady会被调用,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidChromeNotificationObserver:
:
OnBrowserWindowReady(Browser*browser){
Profile*profile=browser->profile();
......
extensions:
:
ProcessManager*manager=
ExtensionSystem:
:
Get(profile)->process_manager();
......
manager->OnBrowserWindowReady();
......
}
这个函数定义在文件external/chromium_org/chrome/browser/extensions/chrome_notification_observer.cc中。
参数browser指向的是一个Browser对象。
这个Browser对象描述的就是一个新打开的浏览器窗口,ChromeNotificationObserver类的成员函数OnBrowserWindowReady首先调用它的成员函数profile获得浏览器在启动过程中创建的Profile,然后再根据这个Profile获得一个ProcessManager对象。
有了这个ProcessManager对象之后,就可以调用它的成员函数OnBrowserWindowReady,用来通知它有一个新的浏览器窗口打开了。
浏览器启动时创建Profile的过程,以及根据Profile创建ProcessManager对象的过程,可以参考前面Chromium扩展(Extension)加载过程分析一文。
ProcessManager类的成员函数OnBrowserWindowReady在执行的过程中,就会为当前加载的Extension创建BackgroundPage,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidProcessManager:
:
OnBrowserWindowReady(){
......
CreateBackgroundHostsForProfileStartup();
}
这个函数定义在文件external/chromium_org/extensions/browser/process_manager.cc中。
ProcessManager类的成员函数OnBrowserWindowReady调用另外一个成员函数CreateBackgroundHostsForProfileStartup为当前加载的Extension创建BackgroundPage,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidProcessManager:
:
CreateBackgroundHostsForProfileStartup(){
......
constExtensionSet&enabled_extensions=
ExtensionRegistry:
:
Get(GetBrowserContext())->enabled_extensions();
for(ExtensionSet:
:
const_iteratorextension=enabled_extensions.begin();
extension!
=enabled_extensions.end();
++extension){
CreateBackgroundHostForExtensionLoad(this,extension->get());
......
}
......
}
这个函数定义在文件external/chromium_org/extensions/browser/process_manager.cc中。
在前面Chromium扩展(Extension)加载过程分析一文提到,Chromium的Browser进程在启动的时候,会将那些状态设置为Enabled的Extension保存在一个ExtensionRegistry的EnabledList中。
ProcessManager类的成员函数CreateBackgroundHostsForProfileStartup主要就是遍历这个EnabledList中的每一个Extension,并且调用函数CreateBackgroundHostForExtensionLoad检查它们是否指定了BackgroundPage。
如果指定了,那么就会进行加载。
函数CreateBackgroundHostForExtensionLoad的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
staticvoidCreateBackgroundHostForExtensionLoad(
ProcessManager*manager,constExtension*extension){
DVLOG
(1)<<"CreateBackgroundHostForExtensionLoad";
if(BackgroundInfo:
:
HasPersistentBackgroundPage(extension))
manager->CreateBackgroundHost(extension,
BackgroundInfo:
:
GetBackgroundURL(extension));
}
这个函数定义在文件external/chromium_org/extensions/browser/process_manager.cc中。
函数CreateBackgroundHostForExtensionLoad首先检查参数extension描述的Extension是否指定了类型为persitent的BackgroundPage。
如果指定了,那么就会调用参数manager指向的一个ProcessManager对象的成员函数CreateBackgroundHost对它进行加载。
对于非persitent的BackgroundPage,它们只会在特定事件发生时,才会被加载。
本文主要以类型为persitent的BackgroundPage为例,说明它们的加载过程。
非persitent的BackgroundPage的加载过程,也是类似的。
函数CreateBackgroundHostForExtensionLoad在调用ProcessManager类的成员函数CreateBackgroundHost加载一个BackgroundPage之前,首先要获得这个BackgroundPage的URL。
这个URL是通过调用BackgroundInfo类的静态成员函数GetBackgroundURL获得的,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
GURLBackgroundInfo:
:
GetBackgroundURL(constExtension*extension){
constBackgroundInfo&info=GetBackgroundInfo(extension);
if(info.background_scripts_.empty())
returninfo.background_url_;
returnextension->GetResourceURL(kGeneratedBackgroundPageFilename);
}
这个函数定义在文件external/chromium_org/extensions/common/manifest_handlers/background_info.cc中。
Chromium将其平台上的程序分为扩展(Extension)和应用(App)两种。
两者具有相同的文件结构,在Chromium中都是通过一个Extension类描述,但是后者比前者具有更严格的权限限制。
应用又分为HostedApp(托管应用)和PackagedApp(打包应用)两种。
HostedApp只提供一个图标和Manifest文件,并且在Manifest文件中声明了它的PopupPage和BackgroundPage等URL。
PackagedApp则将PopupPage和BackgroundPage文件打包在一起安装在本地。
关于Extension、HostedApp和PackagedApp的更详细描述,可以参考Chrome应用基础一文。
我们假设参数extension描述的是一个Extension,并且是一个安装在本地的Extension。
这时候它在Manifest文件实际上只是为BackgropundPage指定了BackgroundScript,如我们在前面文章所示的Pageactionexample:
[plain]viewplaincopy在CODE上查看代码片派生到我的代码片
{
......
"background":
{
"scripts":
["background.js"]
},
......
}
BackgroundInfo类的静态成员函数GetBackgroundURL首先会获得参数extension描述的Extension的BackgroundPage信息。
这些信息保存在一个BackgroundInfo对象中。
当这个BackgroundInfo对象的成员变量background_scripts_的字符串不为空时,这个字符串描述的就是一个BackgroundPage的BackgroundScript,同时也表明参数extension描述的不是一个HostedApp。
在这种情况下,我们就不能直接获得BackgroundPage的URL,而是要通过调用参数extension指向的Extension对象的成员函数GetResourceURL获得。
Extension类的成员函数GetResourceURL的实现如下所示:
[plain]viewplaincopy在CODE上查看代码片派生到我的代码片
classExtension:
publicbase:
:
RefCountedThreadSafe
public:
......
GURLGetResourceURL(conststd:
:
string&relative_path)const{
returnGetResourceURL(url(),relative_path);
}
......
};
这个函数定义在文件external/chromium_org/extensions/common/extension.h中。
从前面的调用过程可以知道,参数relative_path的值为kGeneratedBackgroundPageFilename。
Extension类的成员函数GetResourceURL首先调用另外一个成员函数url获得当前正在处理的Extension的URL。
这个URL的形式为:
chrome-extension:
//[extension_id]/。
其中,[extension_id]为当前正在处理的Extension的ID。
最后,Extension类的成员函数GetResourceURL将参数relative_path的值kGeneratedBackgroundPageFilename添加在前面获得的URL的后面,从而得到当前正在处理的Extension的BackgroundPage的URL。
这是通过调用Extension类的静态成员函数GetResourceURL实现的,如下所示:
[plain]viewplaincopy在CODE上查看代码片派生到我的代码片
//static
GURLExtension:
:
GetResourceURL(constGURL&extension_url,
conststd:
:
string&relative_path){
......
std:
:
stringpath=relative_path;
//Iftherelativepathstartswith"/",itis"absolute"relativetothe
//extensionbasedirectory,butextension_urlisalreadyspecifiedtorefer
//tothatbasedirectory,sostriptheleading"/"ifpresent.
if(relative_path.size()>0&&relative_path[0]=='/')
path=relative_path.substr
(1);
GURLret_val=GURL(extension_url.spec()+path);
......
returnret_val;
}
这个函数定义在文件external/chromium_org/extensions/common/extension.cc中。
通过上面的分析,我们就可以知道,一个Extension如果指定了BackgroundPage,那么这个BackgroundPage的URL就为chrome-extension:
//[extension_id]/kGeneratedBackgroundPageFilename。
其中,kGeneratedBackgroundPageFilename是一个常量,它的定义如下所示:
[plain]viewplaincopy在CODE上查看代码片派生到我的代码片
constcharkGeneratedBackgroundPageFilename[]=
"_generated_background_page.html";
这个常量定义在文件external/chromium_org/extensions/common/constants.cc中。
这意味着,一个Extension的BackgroundPage的URL为:
chrome-extension:
//[extension_id]/_generated_background_page.html。
Chromium的extension模块会注册一个ChromiumExtensionProtocolHandler,用来处理chrome-extension协议。
也就是说,当我们在浏览器的地址栏输入上述URL时ChromiumExtensionProtocolHandler会返回[extension_id]/_generated_background_page.html的内容给WebKit处理。
这个文件的内容是动态生成的。
以前面的Pageactionexample为例,ChromiumExtensionProtocolHandler为它生成的_generated_background_page.html的内容如下所示:
[html]viewplaincopy在CODE上查看代码片派生到我的代码片
DOCTYPEhtml>
获得了要加载的BackgroundPage的URL之后,回到前面分析的函数CreateBackgroundHostForExtensionLoad中,接下来它就会调用ProcessManager类的成员函数CreateBackgroundHost加载BackgroundPage,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
boolProcessManager:
:
CreateBackgroundHost(constExtension*extension,
constGURL&url){
......
ExtensionHost*host=
newExtensionHost(extension,GetSiteInstanceForURL(url),url,
VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
host->CreateRenderViewSoon();
......
returntrue;
}
这个函数定义在文件external/chromium_org/extensions/browser/process_manager.cc中。
ProcessManager类的成员函数CreateBackgroundHost首先是创建一个ExtensionHost对象。
这个ExtensionHost对象类似于Chromium加载一个普通URL时在Browser进程中创建的RenderProcessHost对象。
关于RenderProcessHost的详细描述,可以参考Chromium多进程架构简要介绍和学习计划这个系列的文章。
ExtensionHost对象在创建的过程中,会创建一个WebContents对象,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
ExtensionHost:
:
ExtensionHost(constExtension*extension,
SiteInstance*site_instance,
constGURL&url,
ViewTypehost_type)
:
......,
initial_url_(url),
......{
......
host_contents_.reset(WebContents:
:
Create(
WebContents:
:
CreateParams(browser_context_,site_instance))),
......
}
这个函数定义在文件external/chromium_org/extensions/browser/extension_host.cc中。
创建出来的WebContents对象保存在ExtensionHost类的成员变量host_contents_中。
同时,要加载的BackgroundPageURL将会保存在ExtensionHost类的成员变量initial_url_中。
回到前面分析的ProcessManager类的成员函数CreateBackgroundHost,它创建了一个ExtensionHost对象之后,接下来就会调用这个ExtensionHost对象的成员函数CreateRenderViewSoon加载指定的BackgroundPage,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidExtensionHost:
:
CreateRenderViewSoon(){
if((render_process_host()&&render_process_host()->HasConnection())){
//Iftheprocessisalreadystarted,goaheadandinitializetheRenderView
//synchronously.Theprocesscreationistherealmeatypartthatwewant
//todefer.
CreateRenderViewNow();
}else{
ProcessCreationQueue:
:
GetInstance()->CreateSoon(this);
}
}
这个函数定义在文件external/chromium_org/extensions/browser/extension_host.cc中。
ExtensionHost类的成员函数CreateRenderViewSoon首先判断用来加载指定的BackgroundPage的ExtensionProcess是否已经创建出来了。
如果已经创建,那么就直接调用另外一个成员函数CreateRenderViewNow同步请求在这个ExtensionProcess中加载指定的BackgroundPage。
否则的话,则需要通过调用当前进程中的一个ProcessCreationQueue单例对象的成员函数CreateSoon异步请求加载指定的的BackgroundPage。
后一种情况之所以要异步请求,是因为这种情况需要先创建一个Ex
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Chromium 扩展 Extension 页面 Page 加载 过程 分析