blob: 6b5ce9b81c4062d703be29e3a1f8a4384d90f7de [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_BROWSER_RENDER_FRAME_HOST_RECEIVER_SET_H_
#define CONTENT_PUBLIC_BROWSER_RENDER_FRAME_HOST_RECEIVER_SET_H_
#include <map>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "content/common/content_export.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
namespace content {
class WebContents;
// Owns a set of Channel-associated interface receivers with frame context on
// message dispatch.
//
// When messages are dispatched to the implementation, the implementation can
// call GetCurrentTargetFrame() on this object (see below) to determine which
// frame sent the message.
//
// In order to expose the interface to all RenderFrames, a binder must be
// registered for the interface. Typically this is done in
// RegisterAssociatedInterfaceBindersForRenderFrameHost() in a
// ContentBrowserClient subclass. Doing that will expose the interface to all
// remote RenderFrame objects. If the WebContents is destroyed at any point, the
// receivers will automatically reset and will cease to dispatch further
// incoming messages.
//
// Because this object uses Channel-associated interface receivers, all messages
// sent via these interfaces are ordered with respect to legacy Chrome IPC
// messages on the relevant IPC::Channel (i.e. the Channel between the browser
// and whatever render process hosts the sending frame.)
template <typename Interface>
class CONTENT_EXPORT RenderFrameHostReceiverSet : public WebContentsObserver {
public:
RenderFrameHostReceiverSet(WebContents* web_contents, Interface* impl)
: WebContentsObserver(web_contents), impl_(impl) {}
~RenderFrameHostReceiverSet() override = default;
RenderFrameHostReceiverSet(const RenderFrameHostReceiverSet&) = delete;
RenderFrameHostReceiverSet& operator=(const RenderFrameHostReceiverSet&) =
delete;
void Bind(RenderFrameHost* render_frame_host,
mojo::PendingAssociatedReceiver<Interface> pending_receiver) {
// If the RenderFrameHost does not have a live RenderFrame:
// 1. There is no point in binding receivers, as the renderer should not be
// doing anything with this RenderFrameHost.
// 2. More problematic, `RenderFrameDeleted()` might not be called again
// for `render_frame_host`, potentially leaving dangling pointers to the
// RenderFrameHost (or other related objects) after the RenderFrameHost
// itself is later deleted.
if (!render_frame_host->IsRenderFrameLive()) {
return;
}
mojo::ReceiverId id =
receivers_.Add(impl_, std::move(pending_receiver), render_frame_host);
frame_to_receivers_map_[render_frame_host].push_back(id);
}
RenderFrameHost* GetCurrentTargetFrame() {
if (current_target_frame_for_testing_)
return current_target_frame_for_testing_;
return receivers_.current_context();
}
void SetCurrentTargetFrameForTesting(RenderFrameHost* render_frame_host) {
current_target_frame_for_testing_ = render_frame_host;
}
private:
// content::WebContentsObserver:
void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
auto it = frame_to_receivers_map_.find(render_frame_host);
if (it == frame_to_receivers_map_.end())
return;
for (auto id : it->second)
receivers_.Remove(id);
frame_to_receivers_map_.erase(it);
}
// Receiver set for each frame in the page. Note, bindings are reused across
// navigations that are same-site since the RenderFrameHost is reused in that
// case.
mojo::AssociatedReceiverSet<Interface, RenderFrameHost*> receivers_;
// Track which RenderFrameHosts are in the |receivers_| set so they can
// be removed them when a RenderFrameHost is removed.
std::map<RenderFrameHost*, std::vector<mojo::ReceiverId>>
frame_to_receivers_map_;
raw_ptr<RenderFrameHost> current_target_frame_for_testing_ = nullptr;
// Must outlive this class.
const raw_ptr<Interface> impl_;
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_RENDER_FRAME_HOST_RECEIVER_SET_H_