910e62b5创建于 1月15日历史提交
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h"

#include <memory>
#include <utility>

#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "components/guest_view/common/guest_view_constants.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/child_process_host.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_features.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/browser_frame_context_data.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_util.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/guest_view/app_view/app_view_guest.h"
#include "extensions/browser/guest_view/extension_options/extension_options_guest.h"
#include "extensions/browser/guest_view/guest_view_events.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/process_map.h"
#include "extensions/browser/view_type_utils.h"
#include "extensions/common/constants.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/mojom/event_dispatcher.mojom.h"
#include "extensions/common/mojom/view_type.mojom.h"
#include "extensions/common/utils/extension_utils.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"

using guest_view::GuestViewBase;
using guest_view::GuestViewManager;

namespace extensions {

// Returns a HostID instance based on the given GuestViewBase.
mojom::HostID GenerateHostIdFromGuestView(
    const guest_view::GuestViewBase& guest) {
  // Note: We return a type of kExtensions for all cases where
  // |guest.IsOwnedByExtension()| are true, as well as some additional cases
  // where that call is false but also |guest.IsOwnedByWebUI()| and
  // |guest.IsOwnedByControlledFrameEmbedder()| are false. Those appear to be
  // when the provided extension identifier is blank. Future work in this area
  // could improve the checks here so all the cases are declared relative to
  // what the GuestView instance asserts itself to be.
  mojom::HostID::HostType host_type = mojom::HostID::HostType::kExtensions;

  if (guest.IsOwnedByWebUI()) {
    host_type = mojom::HostID::HostType::kWebUi;
  } else if (guest.IsOwnedByControlledFrameEmbedder()) {
    host_type = mojom::HostID::HostType::kControlledFrameEmbedder;
  }

  return mojom::HostID(host_type, guest.owner_host());
}

// static
bool ExtensionsGuestViewManagerDelegate::IsGuestAvailableToContextWithFeature(
    const GuestViewBase* guest,
    const std::string& feature_name) {
  const Feature* feature = FeatureProvider::GetAPIFeature(feature_name);
  if (!feature) {
    return false;
  }

  content::BrowserContext* context = guest->browser_context();
  ProcessMap* process_map = ProcessMap::Get(context);
  CHECK(process_map);

  const Extension* owner_extension =
      ProcessManager::Get(context)->GetExtensionForRenderFrameHost(
          guest->owner_rfh());

  const GURL& owner_site_url = guest->GetOwnerSiteURL();
  // Ok for |owner_extension| to be nullptr, the embedder might be WebUI.
  Feature::Availability availability = feature->IsAvailableToContext(
      owner_extension,
      process_map->GetMostLikelyContextType(
          owner_extension, guest->owner_rfh()->GetProcess()->GetDeprecatedID(),
          &owner_site_url),
      owner_site_url, util::GetBrowserContextId(context),
      BrowserFrameContextData(guest->owner_rfh()));

  return availability.is_available();
}

ExtensionsGuestViewManagerDelegate::ExtensionsGuestViewManagerDelegate() =
    default;

ExtensionsGuestViewManagerDelegate::~ExtensionsGuestViewManagerDelegate() =
    default;

void ExtensionsGuestViewManagerDelegate::OnGuestAdded(
    content::WebContents* guest_web_contents) const {
  CHECK(!base::FeatureList::IsEnabled(features::kGuestViewMPArch));
  // Set the view type so extensions sees the guest view as a foreground page.
  SetViewType(guest_web_contents, mojom::ViewType::kExtensionGuest);
}

void ExtensionsGuestViewManagerDelegate::DispatchEvent(
    const std::string& event_name,
    base::Value::Dict args,
    GuestViewBase* guest,
    int instance_id) {
  CHECK(guest);
  mojom::EventFilteringInfoPtr info = mojom::EventFilteringInfo::New();
  info->has_instance_id = true;
  info->instance_id = instance_id;
  base::Value::List event_args;
  event_args.Append(std::move(args));

  // GetEventHistogramValue maps guest view event names to their histogram
  // value. It needs to be like this because the guest view component doesn't
  // know about extensions, so GuestViewEvent can't have an
  // extensions::events::HistogramValue as an argument.
  events::HistogramValue histogram_value =
      guest_view_events::GetEventHistogramValue(event_name);
  DCHECK_NE(events::UNKNOWN, histogram_value) << "Event " << event_name
                                              << " must have a histogram value";

  content::RenderFrameHost* owner = guest->owner_rfh();
  if (!owner || !ExtensionsBrowserClient::Get()->IsValidContext(
                    guest->browser_context())) {
    return;  // Could happen at tab shutdown.
  }

  EventRouter::Get(guest->browser_context())
      ->DispatchEventToSender(owner->GetProcess(), guest->browser_context(),
                              GenerateHostIdFromGuestView(*guest),
                              histogram_value, event_name,
                              extensions::kMainThreadId,
                              blink::mojom::kInvalidServiceWorkerVersionId,
                              std::move(event_args), std::move(info));
}

bool ExtensionsGuestViewManagerDelegate::IsGuestAvailableToContext(
    const GuestViewBase* guest) const {
  return IsGuestAvailableToContextWithFeature(guest, guest->GetAPINamespace());
}

bool ExtensionsGuestViewManagerDelegate::IsOwnedByExtension(
    const GuestViewBase* guest) {
  content::BrowserContext* context = guest->browser_context();
  return !!ProcessManager::Get(context)->GetExtensionForRenderFrameHost(
      guest->owner_rfh());
}

bool ExtensionsGuestViewManagerDelegate::IsOwnedByControlledFrameEmbedder(
    const GuestViewBase* guest) {
  return false;
}

void ExtensionsGuestViewManagerDelegate::RegisterAdditionalGuestViewTypes(
    GuestViewManager* manager) {
  manager->RegisterGuestViewType(AppViewGuest::Type,
                                 base::BindRepeating(&AppViewGuest::Create),
                                 base::NullCallback());
  manager->RegisterGuestViewType(
      ExtensionOptionsGuest::Type,
      base::BindRepeating(&ExtensionOptionsGuest::Create),
      base::NullCallback());
  manager->RegisterGuestViewType(
      MimeHandlerViewGuest::Type,
      base::BindRepeating(&MimeHandlerViewGuest::Create), base::NullCallback());
  manager->RegisterGuestViewType(WebViewGuest::Type,
                                 base::BindRepeating(&WebViewGuest::Create),
                                 base::BindRepeating(&WebViewGuest::CleanUp));
}

}  // namespace extensions