1. VSync 信号的起始
Chromium 在 Android 平台是通过 ExternaBeginFrameSourceAndroid 监听 Android 平台的 VSync 信号,在收到 VSync 信号后,通过 BeginFrameObserver 通知信号订阅者
ExternaBeginFrameSourceAndroid 构造流程
browser_view_renderer.Constructor
|-->UpdateBeginFrameSource
|-->begin_frame_source_->SetParentSource(RootBeginFrameSourceWebView::GetInstance())
|-->RootBeginFrameSourceWebView.GetInstance [ begin_frame_source_webview ]
|-->begin_frame_source_ [ ExternalBeginFrameSourceAndroid.Constructor ]
|-->external_begin_frame_source_android.Constructor
|-->Create Java Object ( ExternalBeginFrameSourceAndroid )
VSync 信号通知流程
external_begin_frame_source_android.OnVSync
|-->OnVSyncImpl
|-->OnBeginFrame
|
| ExternalBeginFrameSourceAndroid extends BeginFrameSource
|
|-->begin_frame_source.OnBeginFrame
|-->FilterAndIssueBeginFrame
|-->BeginFrameObserver.OnBeginFrame
|
| BeginFrameSourceWebView::BeginFrameObserver extends BeginFrameObserver
|
|-->BeginFrameSourceWebView::BeginFrameObserver.OnBeginFrame [ begin_frame_source_webview ]
|-->BeginFrameSourceWebView.SendBeginFrame
|-->OnBeginFrame
|--> 通知 SynchronousCompositoHost.OnBeginFrame
|-->AfterBeginFrame
|--> 阻塞 UI 线程,等待 Render BeginFrame Response
如代码中所示,VSync信号有两个重步骤:
- 通知 SynchronousCompositorHost VSync 信号,最终告知到 Render 进程的 SynchronousCompositorProxy 刷新一帧内容
- 在 1 调用完成后,阻塞 UI 线程,直至 Render 绘制帧准备完成后接触阻塞
2. SynchronousCompositorHost 通知 Render 生成一帧内容
接 1 中 OnBeginFrame 省略的部分,从 BeginFrameSourceWebView.OnBeginFrame 开始
BeginFrameSourceWebView.SendBeginFrame
|-->OnBeginFrame
|
| BeginFrameSourceWebView extends ExternalBeginFrameSource
|
|-->ExternalBeginFrameSource.OnBeginFrame
|-->FilterAndIssueBeginFrame
|-->BeginFrameObserver.OnBeginFrame
|
| SynchronousCompositorHost extends BeginFrameObserver
|
|-->SynchronousCompositorHost.OnBeginFrame
|-->SendBeginFrame
|-->① SynchronousCompositorSyncCallBridge.WaitAfterVSyncOnUIThread
|-->SynchronousCompositorHost.AddBeginFrameCompletionCallback ---> SynchronousCompositorSyncCallBridge::BeginFrameCompleteOnUIThread
|-->SynchronousCompositorClient.AddBeginFrameCompletionCallback
|
| BrowserViewRenderer extends SynchronousCompositorClient
|
|-->BrowserViewRenderer.AddBeginFrameCompletionCallback
|-->BeginFrameSourceWebView.AddBeginFrameCompletionCallback [ begin_frame_source_webview ]
|-->after_begin_frame_callbacks_.emplace_back(std::move(callback)) [ 记录 callback ]
|-->② blink::mojom::SynchronousCompositor.BeginFrame
|--> mojo 通知 Render 生成一帧内容
如代码流程所示,SynchronousCompositorHost.OnBeginFrame 主要有以下2个步骤
① 向 BeginFrameSourceWebView 注册回调,并保存在 after_begin_frame_callbacks_ 队列中
② 通过 blink::mojom::SynchronousCompositor.BeginFrame 通知 Render 进程刷新一帧内容
3. UI 线程阻塞等待 Render 帧内容准备完成
回到 BeginFrameSourceWebView.SendBeginFrame,方法内部主要有 2 个调用
BeginFrameSourceWebView.SendBeginFrame
|-->OnBeginFrame --> 通知 Render 生成一帧内容
|-->AfterBeginFrame
|-->RootBeginFrameSourceWebView.AfterBeginFrame [ begin_frame_source_webview ]
|-->after_begin_frame_callbacks_.clear()
通过 [2] 我们知道 OnBeginFrame 会调用到 SynchronousCompositorHost.OnBeginFrame,经过一系列逻辑调用最终会在 after_begin_frame_callbacks_ 中注册回调方法 SynchronousCompositorSyncCallBridge::BeginFrameCompleteOnUIThread,而 after_begin_frame_callbacks_ 成员变量如下
std::vector<base::ScopedClosureRunner> after_begin_frame_callbacks_;
~ScopedClosureRunner() {
RunAndReset();
}
after_begin_frame_callbacks_.clear 会销毁列表中的成员,并触发成员的析构方法,在析构中会调用我们所设置的函数指针,因此 after_begin_frame_callbacks_.clear() 会触发我们之前添加的回调方法
SynchronousCompositorSyncCallBridge.BeginFrameCompleteOnUIThread
|-->begin_frame_condition_.Wait()
begin_frame_condition_ 信号量阻塞等待,直到唤醒,达到阻塞 UI 线程的效果
4. Render 进程一帧内容准备好后,通知 Browser,解除 UI 线程阻塞
回到 SynchronousCompositorHost.SendBeginFrame 方法,他会通知到 Render 刷新一帧内容
SynchronousCompositorHost.SendBeginFrame
|-->compositor->BeginFrame ---------------------------------------|
|
~~~~~~~~~~~~~~~~~~~~~~~~~Renderer~~~~~~~~~~~~~~~~~~~~~~~~~ | synchronous_compositor.mojom
|
SynchronousCompositorProxy.BeginFrame <-----------------------------|
Render 收到 Browser BeginFrame 的调用
SynchronousCompositorProxy.BeginFrame
|-->① layer_tree_frame_sink_->BeginFrame
|-->LayerTreeFrameSink.BeginFrame
|
| extends LayerTreeFrameSink
|
|-->SynchronousLayerTreeFrameSink.BeginFrame
|-->② SendBeginFrameResponse
SynchronousCompositorProxy.BeginFrame 2 个比较关键的步骤
① 刷新页面
② 页面刷新完成后,通知到Browser
刷新页面的具体逻辑稍后再分析,这里先看 SendBeginFrameResponse 将 VSync 整体的刷新流程对起来
SynchronousCompositorProxy 页面刷新完成后,通过 BeginFrameResponse 通知 Browser 进程内容帧已刷新完成
SynchronousCompositorProxy.SendBeginFrameResponse
|-->control_host_->BeginFrameResponse ------------------------------------------------------|
|
~~~~~~~~~~~~~~~~~~~~~Browser~~~~~~~~~~~~~~~~~~~~~~ |
|
SynchronousCompositorControlHost.BeginFrameResponse [ synchronous_compositor_host.cc ] <------|
SynchronousCompositorControlHost.BeginFrameResponse 收到 Render 刷新完成的信号,经过一系列的调用,最终会唤醒信号量 begin_frame_condition_
SynchronousCompositorControlHost.BeginFrameResponse [ synchronous_compositor_host.cc ]
|-->SynchronousCompositorSyncCallBridge.BeginFrameResponseOnIOThread
|-->begin_frame_condition_.Signal();
5. 唤醒 UI 线程阻塞的信号量,并触发 View 绘制流程
begin_frame_condition_.Singal 唤醒 begin_frame_condition.Wait 的等待逻辑
SynchronousCompositorSyncCallBridge.BeginFrameCompleteOnUIThread
|-->begin_frame_condition_.Wait [ 唤醒 ]
|-->SynchronousCompositorHost.UpdateState
|-->client_.PostInvalidate [ SynchronousCompositorClient ]
|
| extends SynchronousCompositorClient
|
|-->BrowserViewRenderer.PostInvalidate
|-->client_.PostInvalidate [ BrowserViewRendererClient ]
|
| extends BrowserViewRendererClient
|
|-->aw_contents.PostInvalidate
|-->AwContents.PostInvalidate
经过一系列的调用,最终通知到 AwContents.PostInvalidate,该方法会调用 WebView.nvalidate 方法,触发 WebView.onDraw 回调进行内容的绘制
6. WebView.onDraw 绘制 Render 已刷新好的内容
WebView.onDraw
|-->AwContents.onDraw
|-->aw_contents.onDraw
|-->browser_view_renderer.OnDrawHardware
|-->SynchronousCompositorHost.DemandDrawHwAsync
|-->DemandDrawHw
|-->GetSynchronousCompositor()->DemandDrawHw -------------|
|
~~~~~~~~~~~~~~~~~~~~Renderer~~~~~~~~~~~~~~~~~~~~ | synchronous_compositor.mojom
|
SynchronousCompositorProxy.DemandDrawHw <-----------------------------|
SynchronousCompositorHost 通过 DemandDrawHw mojo调用从 Render 进程取回刷新好的内容帧
SynchronousCompositorProxy.DemandDrawHw
|-->hardware_draw_reply_ = std::move(callback) [ 同步调用,通过此回调完成mojo方法的值返回 ]
|-->SynchronousLayerTreeFrameSink.DemandDrawHw
|-->InvokeComposite
|-->client_.OnDraw [ LayerTreeFrameSinkClient ]
|
| extends LayerTreeFrameSinkClient
|
|-->LayerTreeHostImpl.OnDraw
|-->client_.OnDrawForLayerTreeFrameSink [ LayerTreeHostImplClient ]
|
| extends LayerTreeHostImplClient
|
|-->ProxyImpl.OnDrawForLayerTreeFrameSink
|-->scheduler.OnDrawForLayerTreeFrameSink
|-->OnBeginImplFrameDeadline
|-->ProcessScheduledActions
|-->DrawIfPossible
|-->client_.ScheduledActionDrawIfPossible [ SchedulerClient ]
|
| extends SchedulerClient
|
|-->ProxyImpl.ScheduledActionDrawIfPossible
|-->DrawInternal
|-->LayerTreeHostImpl.DrawLayers
|-->layer_tree_frame_sink_.SubmitCompositorFrame [ LayerTreeFrameSink ]
|
| extends LayerTreeFrameSink
|
|-->SynchronousLayerTreeFrameSink.SubmitCompositorFrame
|-->sync_client_.SubmitCompositorFrame [ SynchronousLayerTreeFrameSinkClient ]
|
| extends SynchronousLayerTreeFrameSinkClient
|
|-->SynchronousCompositorProxy.SubmitCompositorFrame
|-->std::move(hardware_draw_reply_).Run ---> mojo方法值返回 ----------------|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Browser~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
SynchronousCompositorHost.DemandDrawHw |
|-->GetSynchronousCompositor()->DemandDrawHw <-------------------sync mojo call--------------------|
|-->UpdateState [ 参考第5步的方法调用分解 ]
Render 将帧内容通过同步mojo方法调用返回给Browser进程,Browser进程完成同步mojo调用后,通过 UpdateState方法再次触发AwContents刷新View,触发WebView的绘制流程
7. [2]补充 SynchronousCompositorProxy.BeginFrame 刷新内容
在第2步中,SynchronousCompositorHost 有 2 个主要方法,以上步骤我们详细跟踪了 VSync → UI 阻塞 → UI 阻塞 → 刷新View 的调用流程,这里补充下 SynchronousCompositorHost 中通过 BeginFrame 通知 Render 刷新内容的过程
SynchronousCompositorProxy.BeginFrame
|-->SynchronousLayerTreeFrameSink.BeginFrame
|-->ExternalBeginFrameSource.OnBeginFrame [ begin_frame_source.cc ]
|-->FilterAndIssueBeginFrame
|-->BeginFrameObserver.OnBeginFrame
|
| extends BeginFrameObserver
|
|-->BeginFrameObserverBase.OnBeginFrame [ begin_frame_source.cc ]
|-->OnBeginFrameDerivedImpl
|
| extends BeginFrameObserverBase
|
|-->Scheduler.OnBeginFrameDerivedImpl
|-->BeginImplFrameSynchronous
|-->BeginImplFrame
|-->ProcessScheduledActions
|-->client_->ScheduledActionInvalidateLayerTreeFrameSink [ SchedulerClient ]
|
| extends SchedulerClient
|
|-->ProxyImpl.ScheduledActionInvalidateLayerTreeFrameSink
|-->LayerTreeHostImpl.InvalidateLayerTreeFrameSink
|-->layer_tree_frame_sink()->Invalidate [ LayerTreeFrameSink ]
|
| extends LayerTreeFrameSink
|
|-->SynchronousLayerTreeFrameSink.Invalidate
|-->sync_client_.Invalidate [ SynchronousLayerTreeFrameSinkClient ]
|
| extends SynchronousLayerTreeFrameSinkClient
|
|-->SynchronousCompositorProxy.Invalidate
|-->SendAsyncRendererStateIfNeeded
|-->host_.UpdateStae -----------------------------------------|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Browser~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
SynchronousCompositorHost.UpdateState <---------------------------------------------------|
Render 刷新内容后通过UpdateState通知到Browser,触发WebView绘制流程以便绘制新的内容