好的,这是一份基于你提供的框架,进行了深度扩充和润色的技术演进文档。我保留了你的原意和核心结构,同时补充了技术细节、历史背景和逻辑衔接,使其更像一篇正式的技术博客或内部培训材料。
浏览器能力演进史:从 NPAPI 到 Mojo,从插件到平台
做浏览器内核开发时,经常会看到这些名字:NPAPI、PPAPI、Extension、content::、Mojo、MSHTML、IE Mode。
刚接触时很容易混淆:NPAPI 和 PPAPI 到底是什么关系?为什么浏览器后来不再推荐插件?现代浏览器为什么转向 Extension?为什么还有厂商保留 NPAPI?为什么还有浏览器保留 IE 内核?Chromium 里的 content:: 又是什么?
本文把这些概念串成一条完整的演进链,揭示浏览器如何从一个"网页加载器"演进成一个"完整的应用运行平台"。
一、浏览器最早为什么需要插件
最初,浏览器的能力非常有限。它本质上是一个声明式文档查看器,只能处理:
- HTML:描述文档结构
- CSS:定义视觉样式
- JS:提供基本的页面交互
然而,用户的需求远比"查看文档"复杂得多。随着互联网的商业化,涌现出大量超出浏览器原生能力的需求:
- 富媒体播放:视频、音频、流媒体
- 文档处理:PDF 阅读、Office 文档预览
- 高级交互:3D 在线游戏、复杂的文件上传与下载管理
- 安全与硬件交互:网银 U 盾、USB Key、摄像头、麦克风、数字签名
浏览器自身的标准制定和功能实现速度,远远跟不上这些需求的爆发。为了让网页能够承载这些"重型"应用,浏览器必须开放一个"能力后门",允许第三方原生代码在浏览器中运行。这就是插件诞生的背景。
其核心架构非常简单直接:
网页 (HTML/JS)
↓ 调用
插件 (NPAPI/PPAPI)
↓ 直接调用
操作系统 (Windows/macOS/Linux)
这个时代最早也是最成功的标准,就是 NPAPI。
二、NPAPI:浏览器与 DLL 直接通信的"野蛮时代"
NPAPI,全称 Netscape Plugin Application Programming Interface ,始于 Netscape 浏览器。它的设计哲学简单而粗暴:将浏览器进程变成一个原生代码的宿主。
架构模型
chrome.exe (浏览器进程)
├─ Browser (界面)
├─ Renderer (网页渲染)
└─ plugin.dll (插件,作为动态库直接加载进进程空间)
插件本质上就是一个操作系统级别的动态链接库(Windows 上是 .dll,Linux 上是 .so,macOS 上是 .plugin)。
生命周期与调用链
- 页面嵌入 :网页通过
<object>或<embed>标签声明插件内容。 - 加载 :浏览器解析到标签,通过
LoadLibrary()或dlopen()将插件 DLL 加载到自己的内存空间。 - 初始化 :调用
NP_Initialize()交换浏览器和插件的函数指针表,然后调用NPP_New()创建插件实例。 - 运行与交互 :事件循环触发
NPP_HandleEvent(),脚本调用触发NPObject的调用。 - 销毁 :页面关闭时调用
NPP_Destroy(),最终卸载 DLL。
完整的调用链是:
HTML <object>/<embed>
↓
PluginDocument (浏览器内部的插件文档节点)
↓
WebPlugin (浏览器对插件的封装层)
↓
NPAPI (C接口层)
↓
DLL (插件原生代码)
NPAPI 的"超能力"
因为插件和浏览器共享同一个进程空间,插件代码拥有与浏览器本身完全同等的权限。它可以做任何事:
CreateFile()/ReadFile():随意读写用户磁盘OpenProcess()/ReadProcessMemory():操作其他进程EnumWindows():枚举系统所有窗口send()/recv():发起任意网络连接- 加载其他 DLL,Hook 系统 API
这种能力模型虽然极其强大,但也埋下了灾难的种子。
NPAPI 的致命问题
这种"无边界"的架构导致了严重且系统性的问题。假设一个插件里写了 Sleep(30000),整个调用链会如何?
插件执行 Sleep(30000)
↓ 阻塞
消息循环卡死
↓
浏览器UI线程阻塞
↓
整个浏览器窗口失去响应,无法操作、无法滚动、无法关闭
这只是一个缩影,典型问题如下表所示:
| 问题 | 结果 | 原因 |
|---|---|---|
| 插件崩溃 | 整个浏览器崩溃 | 插件和浏览器在同一进程,一个内存越界(野指针)直接破坏整个进程。 |
| 死锁/死循环 | UI 卡死、无响应 | 插件占用了浏览器的主线程(UI线程),导致事件循环无法处理用户输入。 |
| 内存泄漏 | 浏览器内存持续飙高,最终崩溃 | 插件内部忘记释放内存,且该内存属于浏览器进程的堆。 |
| 严重安全风险 | 用户系统被完全控制 | 插件可以执行任意系统调用、安装恶意软件、窃取文件,浏览器沙箱对其完全无效。 |
| 跨平台困难 | 一个插件只能用于特定OS | DLL 是二进制文件,内含 x86/x64 机器码和特定OS的系统调用,必须为每个平台单独编译。 |
随着浏览器在性能和稳定性上的要求越来越高,这种"插件亡、浏览器亡"的共生关系变得不可接受。浏览器厂商在维护崩溃报告时,发现绝大多数崩溃都指向第三方插件。变革势在必行。
三、PPAPI:插件进程隔离与沙箱化时代
Google 在接手 Chromium 项目后,深刻认识到多进程架构是浏览器的未来。他们提出了一项革命性原则:插件不能再和浏览器共进程 。这个原则催生了 PPAPI (Pepper Plugin API)。
核心理念 :将插件从浏览器主进程中剥离,放入一个独立、低权限的沙箱进程 。浏览器和插件之间通过高效的 IPC (进程间通信) 机制进行交互。
架构模型
Browser Process (浏览器主进程)
↓ 发现 Pepper 插件
↓ 启动
Plugin Process (独立的插件进程)
↓ 加载并运行
pepflashplayer.dll (Pepper 插件)
调用链
网页 JS/HTML
↓
Renderer Process (渲染进程,处理普通网页内容)
↓
Pepper Host (在渲染进程或浏览器进程中,封装PPAPI的C++接口)
↓ IPC (通过 Mojo 或 Chromium IPC 通道)
Plugin Process (插件进程)
↓
PPAPI 实现 (处理 IPC 调用,执行沙箱允许的操作)
PPAPI 的能力边界
PPAPI 不再提供"无限制的系统调用"。相反,它提供了一系列封装的、受控的接口,所有能力必须通过IPC向浏览器申请和代理执行。
插件的能力从:
CreateFile(),send()
变成了:
PPB_URLLoader:发起网络请求(由浏览器网络栈代理)PPB_FileIO:受限的文件读写(只能访问沙箱临时目录或用户指定的文件)PPB_Graphics2D/PPB_Graphics3D:使用 GPU 加速的图形渲染(通过 CommandBuffer 提交给 GPU 进程)PPB_Audio:播放音频(由浏览器音频栈代理)PPB_Instance:管理插件实例的生命周期
PPAPI 带来的进步与代价
优点:
- 稳定性隔离:插件崩溃,仅其自身的 Plugin Process 终止,浏览器主程序和其标签页毫发无伤。用户可以刷新页面重载插件。
- 安全沙箱:插件进程运行在高度受限的环境中,无法直接访问文件系统、注册表或其他进程。所有敏感操作必须经过浏览器审核和代理。
- GPU 硬件加速 :通过
Graphics3DAPI,Pepper Flash 可以高效使用 OpenGL/DirectX 进行视频解码和渲染,性能远超 NPAPI。 - 真正的多进程:浏览器架构变得更加健壮和模块化。
缺点:
- IPC 性能开销:每次绘图调用、文件读写都需要跨进程通信,对延迟敏感的应用(如游戏)有一定影响。
- 生命周期与状态同步极其复杂:浏览器崩溃了,插件进程怎么办?插件进程无响应,浏览器如何判断和重启?多个标签页共享一个插件进程时如何处理?这些边界情况使得实现异常困难。
- API 设计耦合度高:PPAPI 的 C++ API 与 Chromium 内部机制(如 Compositor、CommandBuffer)绑定较深,版本兼容性差。
其最著名、也几乎是唯一的典型应用,就是 Pepper Flash。Google 与 Adobe 合作,将 Flash Player 移植到 PPAPI 之上,使其能在 Chrome 的安全沙箱中运行。
四、为什么 PPAPI 最终也消失了
PPAPI 的消失,并非因为它是一个失败的技术,恰恰相反,它在过渡期完美地完成了历史使命。它退役的根本原因,是浏览器自身变得足够强大,吞噬了插件的核心应用场景。
这场"功能吞噬"的演进路径非常清晰:
- 视频播放 :
Flash Video→ HTML5<video>标签。浏览器原生支持 H.264/VP9 编解码。 - 矢量图形与动画 :
Flash SWF→ CSS3 Animations / SVG。 - 2D/3D 游戏 :
Stage3D→ WebGL / WebGL 2.0。浏览器直接封装 OpenGL ES,提供原生级 GPU 渲染。 - 高性能计算 :
C++ 插件计算→ WebAssembly (WASM)。允许在浏览器中安全地运行接近原生速度的二进制代码。 - PDF 阅读 :
Adobe Reader 插件→ 内建 PDF 引擎 (Chrome/Edge 用 PDFium)。 - 实时通信 :
RTMP via Flash→ WebRTC。浏览器原生支持点对点音视频和数据通信。
整个能力替代路线图:
NPAPI 插件
↓ 隔离 + 沙箱
PPAPI 插件
↓ 浏览器原生功能替代
扩展 (Extensions)
↓ 深化与开放
功能强大的 Web API (W3C标准)
↓ 将浏览器内核服务化
Mojo 服务化架构
当 Web 平台本身可以做几乎所有事情,并且做得更安全、更流畅时,一个需要用户额外安装、存在安全风险、难以跨平台维护的第三方插件框架,退出历史舞台就是必然。
五、现代浏览器为什么转向 Extension
现代浏览器的扩展(Extension)模型,其设计哲学与插件截然不同。插件是在浏览器上"开洞",而扩展是在浏览器之上"添砖加瓦" 。它不是一个二进制程序的加载器,而是一个能力受限的标准化 Web 应用。
现代模型
网页 (Web Content)
↓ 隔离
扩展 (Extension) - 由 HTML/JS/CSS 组成
↓ 通过受限 API 调用
Browser (浏览器核心) - 作为能力的唯一中介和代理
↓ 通过内部机制访问
操作系统能力 (读写文件、管理下载、网络请求等)
扩展的能力边界:声明与权限
扩展通过 manifest.json 声明自己需要的权限,用户在安装时进行授权。
chrome.tabs:访问标签页信息chrome.storage:同步/本地存储数据chrome.cookies:访问和管理 Cookiechrome.downloads:管理文件下载chrome.webRequest:拦截和修改网络请求nativeMessaging:唯一的"后门",允许扩展与一个用户预先安装的原生程序进行标准输入输出通信。
内部调用链路
一个看似简单的扩展 API 调用,背后是复杂的进程间通信。例如:
chrome.tabs.query({active: true, currentWindow: true})
其内部链路是:
Extension Context (扩展的JS代码运行环境)
↓ 调用 chrome.tabs.query API
Extensions API (C++ 实现,运行在 Browser Process)
↓ 访问内部数据结构
Browser (TabStripModel, Window管理等)
↓ 通过 Mojo 与渲染进程通信
Renderer (WebContents,查找对应标签页状态)
↓ 返回结果
最终将 Tab 对象返回给扩展的 JS 代码
在这个模型中,浏览器成为了所有系统能力的统一、受控的入口。它不再是简单地加载插件 DLL,而是精心的在扩展和系统之间加了一层代理和审计。
六、既然淘汰了,为什么还有厂商保留 NPAPI
尽管主流浏览器(Chrome, Firefox, Edge, Safari)早已全面禁用 NPAPI,但在某些特定领域,尤其在中国,仍有大量基于 Chromium 的国产浏览器保留了 NPAPI 支持。这通常不是技术优劣的问题,而是无法逃避的历史兼容成本。
这些系统往往是多年前基于 ActiveX (IE) 或 NPAPI (Firefox/Chrome) 开发的关键业务系统。
典型的遗留系统依赖链
业务网页
↓ 调用
plugin.Sign("合同数据") 或 plugin.ReadUSB()
↓ 插件通过
中间件 DLL (PKI 库、驱动接口)
↓ 与
硬件证书 (U盾) / 系统驱动
↓ 绑定
后台业务逻辑
受影响的核心行业:
- 银行:企业网银、银企直连
- 政务:电子税务局、工商注册、政府采购平台
- OA 办公:公文处理、电子签章(如iSignature)、红头文件
- 工控与医疗:基于浏览器的 SCADA 监控界面、PACS 医学影像系统
- 教育:老旧的在线考试系统、虚拟实验平台
如果贸然删除 NPAPI 支持,结果是灾难性的:
- 功能直接失效:登录按钮点击无反应、签章无法调用、U盾无法识别、文件无法上传。
- 业务停摆:企业每月报税、发送公文、处理订单的基础操作都无法完成。
厂商的常见兼容方案
为了在升级 Chromium 内核的同时保证业务连续性,厂商通常采用以下几种方案:
方案一:内部维护 NPAPI 层(硬扛)
直接在 Chromium 代码中恢复被删除的 NPAPI 基础设施。
- 需要恢复的组件 :
PluginService、PluginProcessHost、WebPlugin、NPObject绑定等。 - 代价:带来极高的 Chromium 升级成本,每次合并上游代码都会发生剧烈冲突,并需要自行承担安全风险。
方案二:伪插件(Native Messaging 桥接)
对外表现像一个插件,但内部是扩展 + 原生程序的组合。
业务网页 (仍可调用 window.plugin.method())
↓ 通过页面注入JS进行拦截和转发
Content Script (Extension)
↓ chrome.runtime.connectNative()
Native Host (一个独立的 host.exe)
↓ 加载并调用
旧插件的核心 DLL (usbkey.dll)
- 优点:符合现代安全模型,不需要维护整个 NPAPI 栈。
- 缺点 :需要分发和安装一个额外的
host.exe,并且页面需要适配JS桥接层。
方案三:双内核切换(最普遍的中国方案)
这也是我们下一节要重点讨论的内容。
对于 *.bank.com, *.gov.cn
↓ 自动切换
使用 IE 内核(MSHTML)加载,原生支持 ActiveX/NPAPI
↓
对于其他标准网站
↓
使用 Chromium 内核加载
这完美地引出了下一个问题。
七、很多浏览器说支持 IE 内核,本质上到底做了什么
很多人可能简单地理解为:LoadLibrary("mshtml.dll") 就完成了。实际上,这背后的工程复杂度堪比在飞机飞行时更换引擎。
7.1 IE 浏览器 ≠ IE 内核
IE 浏览器(iexplore.exe)只是一个外壳,它真正的核心是一系列以 mshtml.dll 为首的 COM 组件集合。
真正的 IE 内核组件:
| 核心 DLL | 职责 |
|---|---|
mshtml.dll |
排版与渲染引擎,负责 HTML/CSS 解析、DOM 树构建、布局和绘制。 |
jscript.dll |
JavaScript 引擎 (非 Chakra 模式),负责解析和执行 ES3 标准的 JS。 |
vbscript.dll |
VBScript 引擎,负责解析和执行 VBS,这是很多老式 ASP 系统的核心。 |
urlmon.dll |
URL 监视器与安全域管理,负责 URL 解析、安全区域判断、异步可插拔协议。 |
wininet.dll |
网络与缓存,负责 HTTP/HTTPS 请求和响应,以及 Cookie 和缓存管理。 |
ole32.dll |
COM 基础结构,所有组件都以 COM 形式交互,是 IE 内核的"神经系统"。 |
浏览器通常通过以下 COM 调用获取 IE 的核心能力:
cpp
// 创建 WebBrowser 控件的实例
CoCreateInstance(CLSID_WebBrowser, NULL, CLSCTX_INPROC_SERVER, IID_IWebBrowser2, (void**)&pBrowser);
// 控制其导航到指定URL
pBrowser->Navigate(L"http://old-system.com");
7.2 浏览器真正做的是构建一个"IE 容器"
现代浏览器并不是"变成"IE,而是 在自己的一个标签页或区域中,作为容器宿主(Host)去承载一个 IE 内核的实例。
宏观架构
现代浏览器 (Browser Process)
├─ Chromium 标签页栈
└─ IE 容器宿主
├─ IEHostView (一个自定义的窗口类)
│ ↓ 创建子窗口,管理布局和消息
└─ WebBrowser Control (ActiveX 控件实例)
↓ 加载和运行
├─ mshtml.dll, jscript.dll ...
└─ 业务 ActiveX 控件 (网银U盾)
容器内部的典型实现:
cpp
class IEHostView {
public:
// 创建一个可以嵌入 ActiveX 控件的容器窗口
HWND Create(HWND parent) {
// AtlAxCreateControl 会加载并初始化 "Shell.Explorer" (即WebBrowser控件)
AtlAxCreateControl(L"Shell.Explorer", parent, NULL, &m_spBrowser);
// 获取 IWebBrowser2 接口进行操作
m_spBrowser->Navigate(url);
}
private:
CComPtr<IWebBrowser2> m_spBrowser;
};
7.3 真正困难的是"统一体验"
加载 IE 内核只是第一步,最困难的是让用户感觉不到他在使用两个完全不同的引擎。这需要在多个层面进行深度同步。
(1) 统一的 Tab 生命周期管理
需要一个抽象基类来封装所有类型的网页宿主:
cpp
class IWebPage {
public:
virtual void LoadURL(const GURL& url) = 0;
virtual void Close() = 0;
virtual std::string GetTitle() = 0;
// ...
};
// 一个实现是标准 Chromium 页面
class ChromeView : public IWebPage { /* 包含 content::WebContents */ };
// 另一个实现是 IE 容器页面
class IEView : public IWebPage { /* 包含 IEHostView */ };
(2) 同步导航状态
监听 IE 的一系列 COM 事件,并转换成浏览器统一的状态。
NavigateComplete2-> 更新地址栏 URLDocumentComplete-> 通知 Tab 页面加载完毕,停止刷新动画TitleChange-> 更新 Tab 标题CommandStateChange-> 更新前进后退按钮的可用状态
(3) 同步 Cookie 与登录态
这是最棘手的问题之一。许多旧系统使用 wininet.dll 的 Cookie 容器,而 Chromium 使用自己的 CookieMonster。两者默认是隔离的。
- 登录丢失问题:用户在 IE 内核中登录银行,切换到 Chrome 内核又变成未登录。
- 解决方案 :需要实现一个
CookieSyncService,通过InternetGetCookieEx等 API 定期将 WinINET Cookie 与 Chromium 的 Cookie 数据库进行双向同步,或者强制所有请求走同一套网络栈。
(4) 接管下载
IE 弹出原生的下载对话框会破坏统一体验。
- 实现 :监听
DownloadBegin、FileDownload等事件,取消 IE 的原生下载,获取文件的 URL、Cookie等信息,传递给浏览器自己的DownloadManager处理。
(5) JS 与浏览器通信桥接
老旧系统大量使用 window.external 作为 JS 与浏览器外壳通信的渠道。
window.external.Login("user", "pass")- 实现 :浏览器需要实现一个
IDispatch接口的 COM 对象,并将其挂载到 IE 容器的window.external上。这样,IE 内的 JS COM 调用就能被转换成 C++ 函数调用,进入浏览器的逻辑。
(6) 智能切核(自动切换规则)
不可能让用户手动选择哪个网站用哪个内核。需要一套复杂的规则引擎。
- 规则示例 :
*.bank.com、*.gov.cn、*.taobao.com(仅限某些特定路径)。 - 逻辑 :当一个导航请求发起时,先匹配规则引擎。
- 命中 IE 规则:
CreateViewForIE()-> 创建IEView。 - 未命中:
CreateViewForChrome()-> 创建ChromeView。
- 命中 IE 规则:
7.4 为什么越来越少浏览器保留 IE 了
这个"IE 容器"方案的维护成本是天文数字:
- Chromium 代码库本身已经极其庞大和复杂。
- MSHTML + 同步层 + 兼容层,这是一套对稳定性、性能和安全性要求都极高的胶水代码。
- 微软的态度:微软已放弃 IE,转向基于 Chromium 的 Edge。Windows 11 中已移除 IE。继续依赖一个不再更新的系统组件,风险极高。
现代替代方案(微软主推):
Chromium 内核浏览器
↓ 如果遇到老旧系统
开启 IE 模式标签页 (实际上就是之前的"容器"方案,但由微软官方维护)
↓ 或者
使用 WebView2,引导客户将系统前端逐步重构为现代 Web 技术
八、那 Chromium 的 content:: API 又是什么?
当你在 Chromium 源码中看到满屏的 content:: 时,它不是指"网页内容"。它是 Chromium 项目最核心、最基础的**"浏览器抽象层"**。
可以这样理解 Chromium 的分层架构:
+-----------------+ <-- 产品层(面向用户)
| chrome/ | Chrome, Edge, Opera 等浏览器的个性化功能 (书签, 同步, 历史, UI主题)
+-----------------+
^
|
+-----------------+ <-- 内容层(核心抽象)
| content/ | 一个多进程的、沙箱化的 Web 平台托管层。它是所有浏览器功能的基础。
+-----------------+ 暴露 content:: 公共 API。
^
|
+-----------------+ <-- 引擎层
| blink/ & v8/ | 渲染引擎 (Blink) 和 JavaScript 引擎 (V8)。
+-----------------+
^
|
+-----------------+ <-- 系统层
| //base, //net | 基础库、网络栈、图形、GPU 命令缓冲等。
+-----------------+
content:: 层的核心职责:
- 多进程架构的实现:管理 Browser, GPU, Utility, Plugin, Renderer 等各种进程的启动、通信和生命周期。
- 沙箱隔离:为每个渲染进程以及其他子进程配置沙箱策略。
- 站点隔离:实现现代浏览器的站点隔离(Site Isolation)安全特性。
- 核心 Web 平台功能:提供一个最小化的集合来加载、渲染和交互网页,并暴露必要的 API 供上层使用。
content:: 命名空间下的核心类
| 核心类 | 职责与代表意义 |
|---|---|
content::WebContents |
一个网页页面实例的抽象 。它是 content/ 层最核心的类。代表了从导航开始,到渲染、显示、事件处理的全过程。 |
content::RenderProcessHost |
渲染进程的宿主。负责管理一个独立的渲染器进程的生命周期和通信。 |
content::RenderFrameHost |
一个 RenderFrame 的宿主 。一个 WebContents 可能包含多个 frame(主 frame + 子 iframe),每个都由一个 RenderFrameHost 代理。 |
content::BrowserContext |
浏览器上下文。通常对应一个用户 Profile,管理该用户下的 Cookie、缓存、存储权限等数据。 |
content::NavigationHandle |
一次导航请求的处理对象。从发起 URL 请求到提交渲染的全过程。 |
当你在 chrome/ 层想要打开一个新标签页时,最终会调用 content::WebContents::Create() 等方法,在 content/ 层创建并管理这个页面实例。
九、现代 Chromium 的真实能力链路
今天浏览器内部的能力调用,早已不是一条单向直线,而是一个服务化的、多层解耦的复杂系统。
能力链路全景图:
网页 JavaScript
↓ 调用
标准 Web API (如 navigator.geolocation, navigator.mediaDevices)
↓ 实现于
Blink 渲染引擎 (在沙箱化的 Renderer Process 中运行)
↓ 如果该 API 需要系统权限,则通过 Mojo 接口发起 IPC 调用
Browser Process 中的对应 Mojo 服务实现 (如 GeolocationServiceImpl)
↓ 该服务验证权限、管理生命周期,并调用真正的系统接口
操作系统 API (如 Windows Location API, CoreAudio, Win32 file I/O)
对比过去的 NPAPI 链路:
网页 JS
↓ 直接调用
Plugin DLL (在浏览器进程中)
↓ 直接调用
Windows API
核心变化在于:
- 调用从直接函数调用变为跨进程 IPC:保证了安全与稳定。
- 能力提供者从第三方 DLL 变为浏览器自己的服务:浏览器从平台的使用者,变成了平台能力的定义者和提供者。
- 一切皆服务化(Mojo):地理定位、文件系统、网络、音频、GPU 等都变成了独立的 Mojo 服务。这使得架构极度模块化,可以独立开发、测试甚至替换。
十、总结:浏览器能力的四个时代
浏览器能力模型的演进,本质上是一段不断强化安全与规范,逐步收回"系统权限后门" 的历史。
第一代:NPAPI 时代(野蛮共生)
网页
↓ 无限制调用
NPAPI 插件 (DLL)
↓ 直接调用
操作系统
- 关键词:高性能、无权限控制、稳定性极差、严重安全风险。
- 代表:Flash, Silverlight, 各种网银控件。
第二代:PPAPI 时代(隔离沙箱)
网页
↓ 声明式调用
PPAPI 插件进程 (沙箱运行)
↓ 通过代理访问
操作系统
- 关键词:进程隔离、沙箱安全、过渡技术。
- 代表:Pepper Flash。
第三代:Extension 时代(能力封装)
网页 (受限环境)
↓ 通过 Event/API 通信
扩展 (Extension)
↓ 通过受限的 JS API 调用
浏览器核心 (权限代理)
- 关键词:跨平台、权限声明、浏览器即中介。
- 代表:Chrome Web Store 中的各类扩展。
第四代:Web API + Mojo 服务化时代(平台即服务)
网页 (JS)
↓ 调用标准 API
Web 平台 (Blink + Mojo 服务)
↓ 高度模块化、可审计
操作系统能力
- 关键词:标准化、服务化、高模块化、安全纵深防御。
- 代表:现代浏览器本身。
如果你今天还在 Chromium 代码里看到 PluginService、PluginProcessHost、NPObject、WebPlugin 等代码,它们通常意味着:
- 历史兼容:为了不破坏某些极端边缘的旧页面。
- 企业定制:某些发行版(如企业浏览器或国产浏览器)为特定业务保留的能力。
- 代码遗迹:在彻底移除前,暂时保留的僵尸代码。
现代浏览器的真正主路径已经全面迁移到了:
content/:负责核心的多进程 Web 平台托管。extensions/:提供安全、跨平台的扩展系统。services/:网络、设备、媒体等核心系统服务的集合。components/:可复用的浏览器功能组件,如自动填充、密码管理。
浏览器,已经不再是那个简单的"网页加载器"。它已经蜕变成一个功能强大、安全严密的通用应用运行平台,是事实上的新一代操作系统用户态。