Showing posts with label clank. Show all posts
Showing posts with label clank. Show all posts

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