I was very confused when I read Android chromium code, because there are two path; single process hack and similar to Aura.
In conclusion
- Clank is very similar to Aura
- Clank runs GPU thread, not GPU Process. Refer to InProcessGPU switch.
- ContentViewRenderView in Clank has similar role to RootWindow in Aura. Those own Compositor!!
- Android Webview has wholly different.
- It is single process
- Impl thread for compositor is the same to UI thread.
- So there is no latency to send touch events to Impl thread.
- It uses ContextProviderInProcess instead of ContextProviderCommandBuffer. It means that GPU calls are executed in UI thread (= Impl thread).
- It uses SynchronousBlahBlah terms. e.g. SynchronousRendererCompositor, SynchronousCompositor, etc..
- This doc has prerequisites
- Aura compositor. Compositor of both render and browser process
Clank (a.k.a chrome for android)
Which cpp instances does Clank need?
- remember ContentViewRenderView is needed.
// in browser_jni_registrar.cc base::android::RegistrationMethod kContentRegisteredMethods[] = { {"AndroidLocationApiAdapter", content::AndroidLocationApiAdapter::RegisterGeolocationService}, {"BrowserAccessibilityManager", content::RegisterBrowserAccessibilityManager}, {"BrowserStartupController", content::RegisterBrowserStartupController}, {"ChildProcessLauncher", content::RegisterChildProcessLauncher}, {"ContentSettings", content::ContentSettings::RegisterContentSettings}, {"ContentViewRenderView", content::ContentViewRenderView::RegisterContentViewRenderView}, {"ContentVideoView", content::ContentVideoView::RegisterContentVideoView}, {"ContentViewCore", content::RegisterContentViewCore}, {"DataFetcherImplAndroid", content::DataFetcherImplAndroid::Register}, {"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid}, {"DownloadControllerAndroidImpl", content::DownloadControllerAndroidImpl::RegisterDownloadController}, {"InterstitialPageDelegateAndroid", content::InterstitialPageDelegateAndroid:: RegisterInterstitialPageDelegateAndroid}, {"MediaDrmCredentialManager", content::MediaDrmCredentialManager::RegisterMediaDrmCredentialManager}, {"MediaResourceGetterImpl", content::MediaResourceGetterImpl::RegisterMediaResourceGetter}, {"LoadUrlParams", content::RegisterLoadUrlParams}, {"PowerSaveBlock", content::RegisterPowerSaveBlocker}, {"RegisterImeAdapter", content::RegisterImeAdapter}, {"SpeechRecognizerImplAndroid", content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer}, {"TouchPoint", content::RegisterTouchPoint}, {"TracingControllerAndroid", content::RegisterTracingControllerAndroid}, {"VibrationMessageFilter", content::VibrationMessageFilter::Register}, {"WebContentsObserverAndroid", content::RegisterWebContentsObserverAndroid}, {"WebViewStatics", content::RegisterWebViewStatics}, };
What is ContentViewRenderView?
- ShellManager.java and Shell.java use ContentViewRenderView.
- Shell looks like Browser in chrome aura.
- ContentViewRenderView seems to have similar role to RootWindow that DesktopRootWindowHostX11 owns.
- because both has the same role; managing Compositor. See Compositor of both render and browser process
// Callstack how to make DesktopRootWindowHostX11
views::DesktopRootWindowHostX11::Init() at desktop_root_window_host_x11.cc:343 0x555559e94c8f
views::DesktopNativeWidgetAura::InitNativeWidget() at desktop_native_widget_aura.cc:240 0x555559e8f775
DesktopBrowserFrameAura::InitNativeWidget() at desktop_browser_frame_aura.cc:54 0x55555904bb69
views::Widget::Init() at widget.cc:374 0x555559ea73e1
BrowserFrame::InitBrowserFrame() at browser_frame.cc:78 0x555559049423
BrowserWindow::CreateBrowserWindow() at browser_view.cc:2,618 0x555558e9df6d
() at browser.cc:235 0x555558db983c
Browser::Browser() at browser.cc:402 0x555558dba8a8
Anything interesting
- There is not huge difference. Aura and Clank are very same.
There is some adjustment for resources.
- GPU resources adjustment.
static scoped_ptr<WebGraphicsContext3DCommandBufferImpl> CreateGpuProcessViewContext( const blink::WebGraphicsContext3D::Attributes attributes, int surface_id) { ... static const size_t kBytesPerPixel = 4; gfx::DeviceDisplayInfo display_info; size_t full_screen_texture_size_in_bytes = display_info.GetDisplayHeight() * display_info.GetDisplayWidth() * kBytesPerPixel; WebGraphicsContext3DCommandBufferImpl::SharedMemoryLimits limits; limits.command_buffer_size = 64 * 1024; limits.start_transfer_buffer_size = 64 * 1024; limits.min_transfer_buffer_size = 64 * 1024; limits.max_transfer_buffer_size = std::min( 3 * full_screen_texture_size_in_bytes, kDefaultMaxTransferBufferSize); limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024; bool use_echo_for_swap_ack = true; return make_scoped_ptr( new WebGraphicsContext3DCommandBufferImpl(surface_id, url, gpu_channel_host.get(), use_echo_for_swap_ack, attributes, false, limits)); }
Clank don't use threaded-compositor in Browser side.
void CompositorImpl::SetVisible(bool visible) {
if (!visible) {
ui_resource_map_.clear();
host_.reset();
client_->UIResourcesAreInvalid();
} else if (!host_) {
cc::LayerTreeSettings settings;
settings.refresh_rate = 60.0;
settings.impl_side_painting = false;
settings.allow_antialiasing = false;
settings.calculate_top_controls_position = false;
settings.top_controls_height = 0.f;
settings.use_memory_management = false;
settings.highp_threshold_min = 2048;
host_ = cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
...
}
}
Others
- Clank runs GPU thread, not GPU Process. Refer to InProcessGPU switch.
- Clank enables impl-side-painting in renderer side.
- Browser side HW Surface is gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NATIVE_DIRECT). same to Aura.
Android Webview
- It's single process hacking.
Class diagram
- Which classes does Android Webview need?
- wholly different from Clank
- use android_webview namespace while Clank use android namespace.
// in android_webview_jni_registrar.cc
static base::android::RegistrationMethod kWebViewRegisteredMethods[] = {
// Register JNI for android_webview classes.
{ "AndroidProtocolHandler", RegisterAndroidProtocolHandler },
{ "AwAutofillManagerDelegate", RegisterAwAutofillManagerDelegate },
{ "AwContents", RegisterAwContents },
{ "AwContentsClientBridge", RegisterAwContentsClientBridge },
{ "AwContentsIoThreadClientImpl", RegisterAwContentsIoThreadClientImpl },
{ "AwDevToolsServer", RegisterAwDevToolsServer },
{ "AwFormDatabase", RegisterAwFormDatabase },
{ "AwPicture", RegisterAwPicture },
{ "AwSettings", RegisterAwSettings },
{ "AwHttpAuthHandler", RegisterAwHttpAuthHandler },
{ "AwQuotaManagerBridge", RegisterAwQuotaManagerBridge },
{ "AwResource", AwResource::RegisterAwResource },
{ "AwWebContentsDelegate", RegisterAwWebContentsDelegate },
{ "CookieManager", RegisterCookieManager },
{ "InterceptedRequestDataImpl", RegisterInterceptedRequestData },
{ "InputStream", RegisterInputStream },
{ "JavaBrowserViewRendererHelper", RegisterJavaBrowserViewRendererHelper },
};
How about Compositor or something.
- In conclusion, WebView has no browser side compositor.
- WebView has only one WebContents instance.
- InProcessViewRenderer can draw by HW and SW. SW is needed for thumbnail (block API backward compatibility).
- Important class relationship
- AwContents owns WebContents
- AwContents -> InProcessViewRenderer -> SynchronousCompositor -> SynchronousCompositorOutputSurface
- SynchronousCompositorOutputSurface is back door that WebView gets contents image.
- SynchronousCompositorOutputSurface is created in render thread but mainly used in UI thread.
- because UI thread is impl thread!!
- In render thread. see Compositor of both render and browser process
- RenderWidget -> RenderWidgetCompositor -> LayerTreeHost -> ThreadProxy
- In Impl thread,
- ThreadProxy -> LayerTreeHostImpl -> SynchronousCompositorOutputSurface
Some code
you can feel darn.
AwContents::AwContents(scoped_ptr<WebContents> web_contents)
: web_contents_(web_contents.Pass()),
browser_view_renderer_(
new InProcessViewRenderer(this, java_renderer_helper(),
web_contents_.get())) {
...
}
void InProcessViewRenderer::DidInitializeCompositor(
content::SynchronousCompositor* compositor) {
TRACE_EVENT0("android_webview",
"InProcessViewRenderer::DidInitializeCompositor");
DCHECK(compositor && compositor_ == NULL);
compositor_ = compositor;
hardware_initialized_ = false;
hardware_failed_ = false;
}
scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
#if defined(OS_ANDROID)
if (SynchronousCompositorFactory* factory =
SynchronousCompositorFactory::GetInstance()) {
return factory->CreateOutputSurface(routing_id());
}
#endif
...
}
scoped_refptr<cc::ContextProvider>
RenderThreadImpl::OffscreenCompositorContextProvider() {
DCHECK(IsMainThread());
#if defined(OS_ANDROID)
if (SynchronousCompositorFactory* factory =
SynchronousCompositorFactory::GetInstance()) {
if (compositor_message_loop_proxy_)
return factory->GetOffscreenContextProviderForCompositorThread();
return factory->GetOffscreenContextProviderForMainThread();
}
#endif
...
}