Lynx 引擎共享 API 头文件(core/public)详解:跨 Shell、Runtime 与平台的公共契约层
2026/9/14 13:02:46 网站建设 项目流程

Lynx 引擎共享 API 头文件(core/public)详解:跨 Shell、Runtime 与平台的公共契约层

【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx

core/public是 Lynx 跨平台渲染引擎(Lynx/TASM)中位于核心引擎与外部世界之间的“契约层”:它是一组 header-only 的 C++ 接口头文件,定义了 shell、renderer、runtime、资源加载、列表处理、devtool 集成和 native module 绑定等各模块之间共享的稳定公共接口。本文基于仓库中的 core/public/AGENTS.md 及其全部头文件源码,梳理这组接口的模块划分、具体契约内容、维护规则,以及如何按“归属模块”定位回归问题,帮助你在阅读或扩展 Lynx 内核时准确把握这条公共 API 边界。

一、目录定位:稳定的核心对外接口面

AGENTS.md 对该目录的职责描述非常明确:

This directory contains stable core-facing interface headers shared across shell, renderer, runtime, resource loading, list handling, devtool integration, and native module bindings.

也就是说,凡是 shell(引擎宿主壳)、renderer(渲染端)、runtime(JS 运行时)、资源加载、列表组件、devtool 以及 native module 需要与核心引擎交互的地方,其接口都收敛在这里。从构建配置看,core/public/BUILD.gn 用lynx_core_source_set("public")注册了这个目标,sources列表全部是.h头文件(如lynx_engine_proxy.hlynx_resource_loader.hjsb/lynx_native_module.hdevtool/lynx_devtool_proxy.h等),没有编译实现单元——这印证了文档中“Keep this directory header-only and dependency-light”的编辑规则。

从源码结构看,AGENTS.md的 Module Map 与实际目录内容一一对应:

文档中的分组对应头文件(均位于 core/public 下)职责
shell/runtime/layout 代理lynx_engine_proxy.hlynx_layout_proxy.hlynx_runtime_proxy.h引擎/布局/运行时三线程的任务分发与跨线程调用
列表契约list_container_proxy.hlist_engine_proxy.hlist_data.h列表滚动控制与懒加载 diff 数据
资源加载lynx_resource_loader.h模板、图片、JS 等资源请求/响应的公共契约
生命周期与性能perf_controller_proxy.hruntime_lifecycle_observer.hvsync_observer_interface.h计时事件上报、运行时生命周期回调、VSync 观察
jsb/lynx_native_module.hlynx_extension_module.hnative_module_factory.hextension_module_factory.hlynx_module_callback.hnative module 与扩展模块的 JS 绑定接口
devtool/lynx_devtool_proxy.hlynx_inspector_owner.hdevtool 代理与 inspector 归属管理

此外目录中还有大量辅助契约头,如pub_value.h(跨层传递的pub::Value值类型)、page_options.hpipeline_option.hui_delegate.hgesture_handler.h等,它们共同构成lynx_core_source_set("public")的完整头文件清单。

二、三大 Proxy 接口:shell 与引擎/运行时/布局之间的桥梁

Proxy 类是 Lynx 引擎解耦宿主实现与核心逻辑的关键抽象:shell 侧持有 proxy,具体实现由各平台/宿主提供。

2.1 LynxEngineProxy:引擎线程的总入口

LynxEngineProxy 是职责最广泛的接口,命名空间为lynx::shell,核心方法可以按功能域分为四类:

  1. 任务分发DispatchTaskToLynxEngine(base::closure task)是所有跨线程进入引擎线程任务的统一入口;
  2. 事件转发SendTouchEvent(带tag、坐标与时间戳,还有基于pub::Value参数的重载)、SendCustomEventSendGestureEventSendBubbleEvent,以及事件管线控制StartEventGenerate/StartEventCapture/StartEventBubble/StartEventFire、伪类状态OnPseudoStatusChanged
  3. 列表驱动ScrollByListContainerScrollToPositionScrollStopped,以及复用池操作ObtainListChild/RecycleListChild/RenderListChild/UpdateListChild/GetListData
  4. 布局与渲染钩子TriggerLayoutMarkLayoutDirtyGetDensityEnableRasterAnimationOnFirstMeaningfulPaint

值得注意的两个设计细节:

  • CustomEventDispatchOptions::emergency:文档注释说明紧急任务会在下一个消息循环边界优先于普通 ready 任务被选中,但不会抢占正在执行的任务。这是事件派发优先级的公共契约;
  • SendCustomEventWithOptions提供了非纯虚的默认实现,直接回退到SendCustomEvent——这是一个典型的“additive change over breaking change”示例:新增带选项的接口时不破坏既有实现者;
  • GetAncestorElements的注释明确要求调用方在“使用 async tasm 时不要调用此函数”,说明接口的线程/架构假设直接写进了公共契约。

2.2 LynxRuntimeProxy:宿主侧对 JS 运行时的调用

LynxRuntimeProxy 定义了 shell 向 runtime 线程发起 JS 调用的五个纯虚方法:

  • CallJSFunction(module_id, method_id, params):按 module/method 定位并调用 JS 函数;
  • CallJSApiCallbackWithValue(callback_id, params):回调 JS 侧注册的 API 回调;
  • CallJSIntersectionObserver(observer_id, callback_id, params):Intersection Observer 的专用通道;
  • EvaluateScript(url, script, callback_id):动态脚本求值;
  • RejectDynamicComponentLoad(url, callback_id, err_code, err_msg):动态组件加载失败时的 reject 通道。

参数统一采用std::unique_ptr<pub::Value>转移所有权,体现了“值跨线程、所有权唯一”的契约风格。

2.3 LynxLayoutProxy:布局线程的最小接口

LynxLayoutProxy 只有两个方法:DispatchTaskToLynxLayout(base::closure task)TriggerLayout()。它展示了这组头文件“dependency-light”的原则——布局线程的对外面被刻意压缩到最小。

三、列表契约:滚动控制与懒加载数据

3.1 两级代理结构

列表相关的滚动控制被拆成了两级接口:

  • ListEngineProxy:纯虚接口,声明ScrollByListContainer/ScrollToPosition/ScrollStopped三个滚动方法;
  • ListContainerProxy:持有ListEngineProxy*的具体类(标注LYNX_EXPORT),实现同名方法并转发给注入的 engine proxy,构造函数explicit ListContainerProxy(ListEngineProxy* list_engine_proxy)体现了依赖注入关系。

值得注意的是,LynxEngineProxy 中也保留了ScrollByListContainer等列表方法,源码中留有注释 “TODO(chenyouhui): Split the list interface into its own public API.”——从源码结构看,列表接口正处在“从引擎总代理中拆分独立出来”的演进过程中,ListContainerProxy/ListEngineProxy就是拆分后的目标形态。

3.2 ListData:列表懒加载的 diff 契约

ListData(命名空间lynx::tasm)承载<list>懒加载所需的全部 diff 信息,注释指出该信息“由 FE 框架生成”,并在 Fiber 架构下已被标记 deprecated。其字段与语义完整如下:

  • view_type_names_:视图类型名列表(SetViewTypeNames);
  • new_arch_/diffable_:架构与 diff 能力开关(SetNewArch/SetDiffable);
  • full_span_:跨列(全宽)项索引,setter 会内部std::sort保持有序;
  • sticky_top_/sticky_bottom_:吸顶/吸底项索引,同样有序化;
  • 六组 diff 操作:SetInsertions/SetRemovals/SetUpdateFrom/SetUpdateTo/SetMoveFrom/SetMoveTo,均为模板接口,接受任意 vector-like 容器;
  • 对应的Get*方法返回const std::vector<int32_t>&(view type 返回const std::vector<std::string>&)。

该类的 getter/setter 全部内联在头文件内,符合“目录不移动实现逻辑”的规则——它只是数据载体契约,真正的 diff 应用在 renderer/list 模块完成。

四、资源加载契约:LynxResourceLoader

lynx_resource_loader.h 是资源加载的公共契约核心,命名空间lynx::pub,包含请求/响应/流式委托四部分:

4.1 资源类型与请求

LynxResourceType枚举定义了 15 种资源类型(源码注释标明 “generated by IDL”):

enum class LynxResourceType : int32_t { kGeneric = 0, kImage = 1, kFont = 2, kLottie = 3, kVideo = 4, kSvg = 5, kTemplate = 6, kLazyBundle = 7, // LazyBundle from js kLynxCoreJs = 8, kExternalJs = 9, kAssets = 11, kI18nText = 12, kGraphics = 13, kTheme = 14, kFrame = 15, kExternalByteCode = 16, // external byteCode loaded from outside; };

注意枚举值从 9 跳到 11——中间的值已被占用或移除,这类“保留空洞”正是“additive change、避免破坏 ABI”原则的直接体现。

LynxResourceRequest结构简单:urltype,以及request_in_current_thread(默认true,注释标明当前用于 lazy bundle,长期会被移除)。

4.2 响应与计时

LynxResourceResponse携带std::vector<uint8_t> datavoid* bundle(用于平台可返回的 template bundle 指针,源码留有 “make LynxTemplateBundle a public class” 的 TODO)、resource_handleerr_code/err_msgResourceLoadTimingSuccess()err_code == 0判定成功。

ResourceLoadTiming提供了一套微秒级加载计时字段,可用于平台侧精细化性能归因:

字段含义
request_start收到客户端请求
request_internal_prepare_finish内部准备完成(如 URL 检查、fallback 逻辑)
request_prepare_to_call_fetcher开始准备调用 fetcher
request_send_to_fetcher实际把请求发给 fetcher
response_received_from_fetcher实际收到 fetcher 响应
response_trigger_callback触发客户端回调

图片类请求还有LynxImageResponseOptionsfallback_paths(回退路径)、file_cache_nameuse_highest_prioritymapped_file_cache_key/mapped_memory_cache_key(缓存键映射)。

4.3 加载入口与流式委托

LynxResourceLoader继承std::enable_shared_from_this,导出LYNX_EXPORT,对外提供:

  • LoadResource(request, callback)LoadResourcePath(request, path_callback)非虚的公共入口,内部转发给纯虚的LoadResourceInternal/LoadResourcePathInternal,并叠加 replay 缓存逻辑(SetReplayResourceCache注入tasm::replay::ReplayResourceCache);
  • LoadStream(request, stream_delegate):流式加载,配合LynxStreamDelegateOnStart(size)/OnData(data)/OnEnd()/OnError(msg)四个回调;
  • LoadBytecode(request, callback):默认实现直接回包err_code = -1"LoadBytecode is not supported.",需要时由平台覆写;
  • IsLocalResource(url)(默认false)、ShouldRedirectUrl(默认原样返回 URL)、ShouldRedirectUrlAsync(默认报错-1,提示“not supported”)——这些带默认实现的虚函数同样是“新增能力不破坏旧实现”的模式。

五、生命周期与性能:RuntimeLifecycleObserver 与 VSync、Perf 代理

5.1 RuntimeLifecycleObserver

RuntimeLifecycleObserver(命名空间lynx::runtime,标注“Triggered on runtime thread”)定义 runtime 生命周期回调:

  • OnRuntimeCreate(std::shared_ptr<IVSyncObserver> observer):注意它把 VSync observer 作为参数回传给监听者,说明 VSync 通道是在 runtime 创建时注入的;
  • OnRuntimeInit(int64_t runtime_id)
  • OnAppEnterForeground()/OnAppEnterBackground():前后台切换;
  • OnRuntimeAttach(void* env, const char* runtime_type)/OnRuntimeDetach():运行时附着/脱离。

5.2 IVSyncObserver

IVSyncObserver 是“exported from lynx.so”的 C++ VSync 观察接口,三个方法分别对应帧时序的三个插入点:

  • RequestAnimationFrame(id, callback):帧动画回调;
  • RequestBeforeAnimationFrame(id, callback):帧前回调;
  • RegisterAfterAnimationFrameListener(callback):帧后监听。

回调签名统一为base::MoveOnlyClosure<void, int64_t, int64_t>(移动语义闭包)。同目录的vsync_monitor_platform_impl.h则是对应的平台实现侧接口,二者构成“接口 + 平台实现”的分层。

5.3 PerfControllerProxy

PerfControllerProxy 是性能数据上行的公共契约,核心方法:

  • SetHostPlatformType(const std::string& type):设置宿主平台类型(文档注释举例'windowsClay'),影响PipelineEntryHostPlatformTiming的平台类型标签;
  • MarkTiming(tasm::TimingKey, const tasm::PipelineID&):以 key + 管线 ID 打点;
  • SetTiming(timing_key, timestamp_us, pipeline_id):直接写入微秒时间戳;
  • SetHostPlatformTiming(...):平台侧计时事件写入;
  • GetPlatform():返回当前运行平台(文档注释举例'windows' 'macOS' 'iOS' 'Android' 'Linux');
  • RunTaskInReportThread(base::closure task):向 report 线程投递任务;
  • OnEvent(tasm::report::MoveOnlyEvent&& event):事件上报入口,移动语义传递MoveOnlyEvent

这里的TimingKeyPipelineID类型来自 core/public/timing_key.h 和 core/public/pipeline_option.h,性能计时的键体系本身就是公共契约的一部分。

六、jsb/:native module 与扩展模块的绑定接口

core/public/jsb/下的五个头文件定义 JS 绑定层(JSB)的模块接口。以最核心的 lynx_native_module.h 为例:

  • LynxNativeModule标注LYNX_EXPORT_FOR_DEVTOOL,注释说明 “Upper-level modules can inherit from LynxNativeModule to register their own JSB”,即它是所有 native module 的公共基类;
  • 内部Delegate类提供InvokeCallback(callback, invoke_pre_func)RunOnJSThread(func)RunOnPlatformThread(func)三个纯虚方法,把“回调 JS”“切 JS 线程”“切平台线程”三件跨层高频动作抽象出来,供 module 开发者统一使用;
  • NativeModuleMethod { name, args_count }NativeModuleMethodsstd::unordered_map)用于方法名到参数个数的注册表;
  • 文件头部还有一段 Objective-C++ 兼容处理:用#pragma push_macro保护LynxNativeModule这个与 Objective-C 库同名的宏冲突,并在文件尾恢复——这是多平台头文件维护中真实存在的兼容细节。

同目录的lynx_extension_module.h+extension_module_factory.hlynx_native_module.h+native_module_factory.h构成 native/extension 两族模块的平行结构,lynx_module_callback.h则承载回调句柄。此外 lynx_runtime_proxy.h 被lynx_native_module.h直接包含,说明 native module 到 runtime 的调用通道也走这组公共契约。

七、维护规则:如何安全地修改这组头文件

AGENTS.md 的 Edit Rules 给出了三条维护准则,它们都有源码层面的对应佐证:

  1. 视同共享 API 面:签名、所有权或类型变更通常需要 shell、runtime、资源加载与平台实现协同更新。证据是LynxEngineProxyjsb/lynx_native_module.h包含、ListContainerProxy依赖ListEngineProxyRuntimeLifecycleObserver依赖IVSyncObserver——头文件之间已形成一张依赖网,改动任何一处都可能波及多模块;
  2. 保持 header-only 与轻依赖BUILD.gn的 source set 只有头文件,头文件仅依赖base/include/closure.hcore/base/lynx_export.h等少量基础头;
  3. 优先增量式变更:如前文所述的SendCustomEventWithOptions默认实现、LoadBytecode/ShouldRedirectUrlAsync的“默认不支持”实现、LynxResourceType的保留空洞,都是“新能力以默认实现/新增枚举值落地,不破坏既有派生类”的模式。

八、回归症状与验证路径:契约变了去哪找问题

当一次“看起来很小”的头文件编辑导致多模块构建失败、或“编译通过但运行时坏掉”,AGENTS.md 归纳了三个典型症状,本质都是公共契约失配:

  • 多模块构建失败 → 共享契约(签名/类型)变了;
  • proxy 调用编译通过但运行时崩溃 → 所有权(如std::unique_ptr<pub::Value>)、回调生命周期(如LynxStreamDelegatebase::closure捕获的裸对象)或线程假设(如OnEvent的线程约定、GetAncestorElements的 async tasm 限制)变了,但实现侧未同步;
  • native module / resource loader / list 集成回归 → 契约失配通常源头在此目录。

由于本目录不定义自己的单测 exec,文档要求“通过归属实现模块验证”,对应到仓库中的构建目标:

验证目标覆盖的契约定义位置
shell_unittests_execproxy 与生命周期契约core/shell/testing/BUILD.gn
list_container_testset_exec列表面向的契约core/list/BUILD.gn
lazy_bundle_test_exec或 runtime 资源测试资源加载契约core/resource/BUILD.gn、core/runtime/BUILD.gn
runtime_tests_exec或 module-binding 测试jsb/契约core/runtime/BUILD.gn

另外 core/renderer/ui_component/list/BUILD.gn 也引用了list_container_testset_exec,说明列表契约的验证同时覆盖 renderer 侧的 list 组件。

九、小结

core/public虽然只是一个“全是头文件”的目录,但它承载了 Lynx 引擎最关键的一条边界:shell 与引擎/运行时/布局三线程之间、宿主平台与 JS 运行时之间、资源系统与模板加载之间、列表容器与 diff 引擎之间,以及 JS 与 native module 之间的全部公共契约。理解这个目录的价值在于:

  • 读到*proxy*.h时,应理解为“shell 侧持有、宿主实现”的注入点;
  • 读到LynxResourceLoader的默认实现时,应理解为平台可覆写的扩展缝;
  • 修改这里任何签名前,先确认“additive over breaking”是否可能,并预先规划 shell、runtime、resource、list 四路实现与对应验证 target 的协同更新。

掌握这一契约层后,你可以在仓库中沿 core/shell、core/runtime、core/renderer、core/list 等实现目录继续深入,追踪每一条公共接口在真实引擎中的落点。

【免费下载链接】lynxEmpower the Web community and invite more to build across platforms.项目地址: https://gitcode.com/GitHub_Trending/lynx10/lynx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询