chromium/android_webview/browser/aw_content_browser_client_receiver_bindings.cc

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_content_browser_client.h"
#include "android_webview/browser/aw_print_manager.h"
#include "android_webview/browser/renderer_host/aw_render_view_host_ext.h"
#include "android_webview/browser/safe_browsing/aw_url_checker_delegate_impl.h"
#include "android_webview/common/aw_features.h"
#include "android_webview/common/mojom/render_message_filter.mojom.h"
#include "base/feature_list.h"
#include "components/autofill/content/browser/content_autofill_driver_factory.h"
#include "components/cdm/browser/media_drm_storage_impl.h"
#include "components/content_capture/browser/onscreen_content_provider.h"
#include "components/network_hints/browser/simple_network_hints_handler_impl.h"
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/content/browser/mojo_safe_browsing_impl.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
#include "components/spellcheck/spellcheck_buildflags.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "media/mojo/buildflags.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/mojom/webview/webview_media_integrity.mojom.h"

#if BUILDFLAG(ENABLE_SPELLCHECK)
#include "components/spellcheck/browser/spell_check_host_impl.h"
#endif

namespace android_webview {

namespace {

#if BUILDFLAG(ENABLE_MOJO_CDM)
void CreateOriginId(cdm::MediaDrmStorageImpl::OriginIdObtainedCB callback) {
  std::move(callback).Run(true, base::UnguessableToken::Create());
}

void AllowEmptyOriginIdCB(base::OnceCallback<void(bool)> callback) {
  // Since CreateOriginId() always returns a non-empty origin ID, we don't need
  // to allow empty origin ID.
  std::move(callback).Run(false);
}

void CreateMediaDrmStorage(
    content::RenderFrameHost* render_frame_host,
    mojo::PendingReceiver<::media::mojom::MediaDrmStorage> receiver) {
  CHECK(render_frame_host);

  if (render_frame_host->GetLastCommittedOrigin().opaque()) {
    DVLOG(1) << __func__ << ": Unique origin.";
    return;
  }

  auto* aw_browser_context =
      static_cast<AwBrowserContext*>(render_frame_host->GetBrowserContext());
  DCHECK(aw_browser_context) << "AwBrowserContext not available.";

  PrefService* pref_service = aw_browser_context->GetPrefService();
  DCHECK(pref_service);

  // The object will be deleted on connection error, or when the frame navigates
  // away.
  new cdm::MediaDrmStorageImpl(
      *render_frame_host, pref_service, base::BindRepeating(&CreateOriginId),
      base::BindRepeating(&AllowEmptyOriginIdCB), std::move(receiver));
}
#endif  // BUILDFLAG(ENABLE_MOJO_CDM)

// Helper method that checks the RenderProcessHost is still alive before hopping
// over to the IO thread.
void MaybeCreateSafeBrowsing(
    int rph_id,
    base::RepeatingCallback<scoped_refptr<safe_browsing::UrlCheckerDelegate>()>
        get_checker_delegate,
    mojo::PendingReceiver<safe_browsing::mojom::SafeBrowsing> receiver) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

  content::RenderProcessHost* render_process_host =
      content::RenderProcessHost::FromID(rph_id);
  if (!render_process_host)
    return;

  safe_browsing::MojoSafeBrowsingImpl::MaybeCreate(
      rph_id, std::move(get_checker_delegate), std::move(receiver));
}

void BindNetworkHintsHandler(
    content::RenderFrameHost* frame_host,
    mojo::PendingReceiver<network_hints::mojom::NetworkHintsHandler> receiver) {
  network_hints::SimpleNetworkHintsHandlerImpl::Create(frame_host,
                                                       std::move(receiver));
}

// This class handles android_webview.mojom.RenderMessageFilter Mojo interface's
// methods on IO thread.
class AwContentsMessageFilter : public mojom::RenderMessageFilter {
 public:
  explicit AwContentsMessageFilter(int process_id);

  AwContentsMessageFilter(const AwContentsMessageFilter&) = delete;
  AwContentsMessageFilter& operator=(const AwContentsMessageFilter&) = delete;

  // mojom::RenderMessageFilter overrides:
  void SubFrameCreated(
      const blink::LocalFrameToken& parent_frame_token,
      const blink::LocalFrameToken& child_frame_token) override;

  ~AwContentsMessageFilter() override;

 private:
  const int process_id_;
};

AwContentsMessageFilter::AwContentsMessageFilter(int process_id)
    : process_id_(process_id) {}

AwContentsMessageFilter::~AwContentsMessageFilter() = default;

void AwContentsMessageFilter::SubFrameCreated(
    const blink::LocalFrameToken& parent_frame_token,
    const blink::LocalFrameToken& child_frame_token) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
  AwContentsIoThreadClient::SubFrameCreated(process_id_, parent_frame_token,
                                            child_frame_token);
}

void CreateRenderMessageFilter(
    int rph_id,
    mojo::PendingReceiver<mojom::RenderMessageFilter> receiver) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
  mojo::MakeSelfOwnedReceiver(std::make_unique<AwContentsMessageFilter>(rph_id),
                              std::move(receiver));
}

template <typename Interface>
void ForwardToJavaFrame(content::RenderFrameHost* render_frame_host,
                        mojo::PendingReceiver<Interface> receiver) {
  render_frame_host->GetJavaInterfaces()->GetInterface(std::move(receiver));
}

void BindMediaIntegrityServiceReceiver(
    content::RenderFrameHost* render_frame_host,
    mojo::PendingReceiver<blink::mojom::WebViewMediaIntegrityService>
        receiver) {
  const url::Origin& origin = render_frame_host->GetLastCommittedOrigin();
  // Note that this particular check respects the origin of the base URL
  // supplied by loadDataWithBaseURL.
  if ((origin.scheme() != url::kHttpScheme &&
       origin.scheme() != url::kHttpsScheme) ||
      !network::IsOriginPotentiallyTrustworthy(origin)) {
    mojo::ReportBadMessage(
        "Attempted to access WebView Media Integrity service for a "
        "non-trustworthy or non-HTTP/HTTPS origin.");
    return;
  };
  ForwardToJavaFrame<blink::mojom::WebViewMediaIntegrityService>(
      render_frame_host, std::move(receiver));
}

}  // anonymous namespace

void AwContentBrowserClient::BindMediaServiceReceiver(
    content::RenderFrameHost* render_frame_host,
    mojo::GenericPendingReceiver receiver) {
#if BUILDFLAG(ENABLE_MOJO_CDM)
  if (auto r = receiver.As<media::mojom::MediaDrmStorage>()) {
    CreateMediaDrmStorage(render_frame_host, std::move(r));
    return;
  }
#endif
}

void AwContentBrowserClient::
    RegisterAssociatedInterfaceBindersForRenderFrameHost(
        content::RenderFrameHost& render_frame_host,
        blink::AssociatedInterfaceRegistry& associated_registry) {
  associated_registry.AddInterface<autofill::mojom::AutofillDriver>(
      base::BindRepeating(
          &autofill::ContentAutofillDriverFactory::BindAutofillDriver,
          &render_frame_host));
  // TODO(lingqi): Swap the parameters so that lambda functions are not needed.
  associated_registry.AddInterface<
      content_capture::mojom::ContentCaptureReceiver>(base::BindRepeating(
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingAssociatedReceiver<
             content_capture::mojom::ContentCaptureReceiver> receiver) {
        content_capture::OnscreenContentProvider::BindContentCaptureReceiver(
            std::move(receiver), render_frame_host);
      },
      &render_frame_host));
  associated_registry.AddInterface<mojom::FrameHost>(base::BindRepeating(
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingAssociatedReceiver<mojom::FrameHost> receiver) {
        AwRenderViewHostExt::BindFrameHost(std::move(receiver),
                                           render_frame_host);
      },
      &render_frame_host));
  associated_registry.AddInterface<page_load_metrics::mojom::PageLoadMetrics>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<
                 page_load_metrics::mojom::PageLoadMetrics> receiver) {
            page_load_metrics::MetricsWebContentsObserver::BindPageLoadMetrics(
                std::move(receiver), render_frame_host);
          },
          &render_frame_host));
  associated_registry.AddInterface<printing::mojom::PrintManagerHost>(
      base::BindRepeating(
          [](content::RenderFrameHost* render_frame_host,
             mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost>
                 receiver) {
            AwPrintManager::BindPrintManagerHost(std::move(receiver),
                                                 render_frame_host);
          },
          &render_frame_host));
  associated_registry.AddInterface<
      security_interstitials::mojom::InterstitialCommands>(base::BindRepeating(
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingAssociatedReceiver<
             security_interstitials::mojom::InterstitialCommands> receiver) {
        security_interstitials::SecurityInterstitialTabHelper::
            BindInterstitialCommands(std::move(receiver), render_frame_host);
      },
      &render_frame_host));
}

void AwContentBrowserClient::ExposeInterfacesToRenderer(
    service_manager::BinderRegistry* registry,
    blink::AssociatedInterfaceRegistry* associated_registry,
    content::RenderProcessHost* render_process_host) {
  registry->AddInterface<safe_browsing::mojom::SafeBrowsing>(
      base::BindRepeating(
          &MaybeCreateSafeBrowsing, render_process_host->GetID(),
          base::BindRepeating(
              &AwContentBrowserClient::GetSafeBrowsingUrlCheckerDelegate,
              base::Unretained(this))),
      content::GetUIThreadTaskRunner({}));

  // Add the RenderMessageFilter creation callback, the callbkack will happen on
  // the IO thread.
  registry->AddInterface<mojom::RenderMessageFilter>(base::BindRepeating(
      &CreateRenderMessageFilter, render_process_host->GetID()));
}

void AwContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
    content::RenderFrameHost* render_frame_host,
    mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
  map->Add<network_hints::mojom::NetworkHintsHandler>(
      base::BindRepeating(&BindNetworkHintsHandler));

#if BUILDFLAG(ENABLE_SPELLCHECK)
  auto create_spellcheck_host =
      [](content::RenderFrameHost* render_frame_host,
         mojo::PendingReceiver<spellcheck::mojom::SpellCheckHost> receiver) {
        mojo::MakeSelfOwnedReceiver(std::make_unique<SpellCheckHostImpl>(),
                                    std::move(receiver));
      };
  map->Add<spellcheck::mojom::SpellCheckHost>(
      base::BindRepeating(create_spellcheck_host),
      content::GetUIThreadTaskRunner({}));
#endif

  if (base::FeatureList::IsEnabled(
          features::kWebViewMediaIntegrityApiBlinkExtension)) {
    map->Add<blink::mojom::WebViewMediaIntegrityService>(
        base::BindRepeating(&BindMediaIntegrityServiceReceiver));
  }
}

void AwContentBrowserClient::
    RegisterMojoBinderPoliciesForSameOriginPrerendering(
        content::MojoBinderPolicyMap& policy_map) {
  policy_map.SetAssociatedPolicy<page_load_metrics::mojom::PageLoadMetrics>(
      content::MojoBinderAssociatedPolicy::kGrant);
}

}  // namespace android_webview