Friday, November 8, 2013

Clank (a.k.a chrome for android) vs Android Webview based on Chromium vs Aura

original doc : https://github.com/ds-hwang/wiki/wiki/Clank-(a.k.a-chrome-for-android)-vs-Android-Webview-based-on-Chromium-vs-Aura


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

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.
// 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

// 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!!
    • 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
  ...
}

Renference

No comments:

Post a Comment