blob: afaa4a8b775873998bbce22457fa26241f72b108 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/guest_view/browser/guest_view_message_handler.h"
#include <memory>
#include "base/metrics/histogram_functions.h"
#include "components/guest_view/browser/bad_message.h"
#include "components/guest_view/browser/guest_view_base.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
using content::BrowserThread;
using content::RenderFrameHost;
namespace guest_view {
GuestViewMessageHandler::GuestViewMessageHandler(int render_process_id)
: render_process_id_(render_process_id) {}
GuestViewMessageHandler::~GuestViewMessageHandler() = default;
GuestViewManager* GuestViewMessageHandler::GetOrCreateGuestViewManager() {
auto* browser_context = GetBrowserContext();
auto* manager = GuestViewManager::FromBrowserContext(browser_context);
if (!manager) {
manager = GuestViewManager::CreateWithDelegate(
browser_context, CreateGuestViewManagerDelegate(browser_context));
}
return manager;
}
GuestViewManager* GuestViewMessageHandler::GetGuestViewManagerOrKill() {
auto* manager = GuestViewManager::FromBrowserContext(GetBrowserContext());
if (!manager) {
bad_message::ReceivedBadMessage(
render_process_id(),
bad_message::GVMF_UNEXPECTED_MESSAGE_BEFORE_GVM_CREATION);
}
return manager;
}
std::unique_ptr<GuestViewManagerDelegate>
GuestViewMessageHandler::CreateGuestViewManagerDelegate(
content::BrowserContext* context) const {
return std::make_unique<GuestViewManagerDelegate>();
}
content::BrowserContext* GuestViewMessageHandler::GetBrowserContext() const {
auto* rph = content::RenderProcessHost::FromID(render_process_id());
return rph ? rph->GetBrowserContext() : nullptr;
}
void GuestViewMessageHandler::ViewCreated(int view_instance_id,
const std::string& view_type) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!GetBrowserContext())
return;
GetOrCreateGuestViewManager()->ViewCreated(render_process_id(),
view_instance_id, view_type);
}
void GuestViewMessageHandler::ViewGarbageCollected(int view_instance_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!GetBrowserContext())
return;
GetOrCreateGuestViewManager()->ViewGarbageCollected(render_process_id(),
view_instance_id);
}
void GuestViewMessageHandler::AttachToEmbedderFrame(
int embedder_local_render_frame_id,
int element_instance_id,
int guest_instance_id,
base::Value::Dict params,
AttachToEmbedderFrameCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!GetBrowserContext()) {
std::move(callback).Run();
return;
}
// We should have a GuestViewManager at this point. If we don't then the
// embedder is misbehaving.
auto* manager = GetGuestViewManagerOrKill();
if (!manager) {
// The renderer has been killed, and this event logged, by
// `ReceivedBadMessage`, so we can just return.
std::move(callback).Run();
return;
}
GuestViewBase* guest = manager->GetGuestByInstanceIDSafely(
guest_instance_id, render_process_id());
if (!guest) {
std::move(callback).Run();
return;
}
std::unique_ptr<GuestViewBase> owned_guest =
manager->TransferOwnership(guest);
DCHECK_EQ(owned_guest.get(), guest);
content::WebContents* owner_web_contents = guest->owner_web_contents();
DCHECK(owner_web_contents);
auto* embedder_frame = RenderFrameHost::FromID(
render_process_id(), embedder_local_render_frame_id);
const bool changed_owner_web_contents =
owner_web_contents !=
content::WebContents::FromRenderFrameHost(embedder_frame);
base::UmaHistogramBoolean(
"Extensions.GuestView.ChangeOwnerWebContentsOnAttach",
changed_owner_web_contents);
if (changed_owner_web_contents) {
guest->MaybeRecreateGuestContents(
content::WebContents::FromRenderFrameHost(embedder_frame));
}
// Update the guest manager about the attachment.
// This sets up the embedder and guest pairing information inside
// the manager.
manager->AttachGuest(render_process_id(), element_instance_id,
guest_instance_id, params);
guest->AttachToOuterWebContentsFrame(
std::move(owned_guest), embedder_frame, element_instance_id,
false /* is_full_page_plugin */, std::move(callback));
}
} // namespace guest_view