1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef EXTENSIONS_BROWSER_API_MESSAGING_EXTENSION_MESSAGE_PORT_H_
#define EXTENSIONS_BROWSER_API_MESSAGING_EXTENSION_MESSAGE_PORT_H_
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/types/pass_key.h"
#include "base/uuid.h"
#include "content/public/browser/global_routing_id.h"
#include "extensions/browser/api/messaging/message_port.h"
#include "extensions/browser/message_tracker.h"
#include "extensions/browser/service_worker/worker_id.h"
#include "extensions/common/api/messaging/port_id.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/mojom/message_port.mojom.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "url/origin.h"
class GURL;
namespace content {
class BrowserContext;
class RenderFrameHost;
} // namespace content
namespace IPC {
class Message;
} // namespace IPC
namespace extensions {
class ExtensionHost;
class ChannelEndpoint;
struct PortContext;
// A port that manages communication with an extension.
// The port's lifetime will end when either all receivers close the port, or
// when the opener / receiver explicitly closes the channel.
class ExtensionMessagePort : public MessagePort {
public:
// Create a port that is tied to frame(s) in a single tab.
static std::unique_ptr<ExtensionMessagePort> CreateForTab(
base::WeakPtr<ChannelDelegate> channel_delegate,
const PortId& port_id,
const ExtensionId& extension_id,
content::RenderFrameHost* render_frame_host,
bool include_child_frames);
// Create a port that is tied to all frames and service workers of an
// extension. Should only be used for a receiver port.
static std::unique_ptr<ExtensionMessagePort> CreateForExtension(
base::WeakPtr<ChannelDelegate> channel_delegate,
const PortId& port_id,
const ExtensionId& extension_id,
content::BrowserContext* browser_context);
// Creates a port for any ChannelEndpoint which can be for a render frame or
// Service Worker.
static std::unique_ptr<ExtensionMessagePort> CreateForEndpoint(
base::WeakPtr<ChannelDelegate> channel_delegate,
const PortId& port_id,
const ExtensionId& extension_id,
const ChannelEndpoint& endpoint,
mojo::PendingAssociatedRemote<extensions::mojom::MessagePort> port,
mojo::PendingAssociatedReceiver<extensions::mojom::MessagePortHost>
port_host);
ExtensionMessagePort(base::WeakPtr<ChannelDelegate> channel_delegate,
const PortId& port_id,
const ExtensionId& extension_id,
content::BrowserContext* browser_context,
base::PassKey<ExtensionMessagePort>);
ExtensionMessagePort(const ExtensionMessagePort&) = delete;
~ExtensionMessagePort() override;
ExtensionMessagePort& operator=(const ExtensionMessagePort&) = delete;
// MessagePort:
void RemoveCommonFrames(const MessagePort& port) override;
bool HasFrame(
const content::GlobalRenderFrameHostToken& frame_token) const override;
bool IsValidPort() override;
void RevalidatePort() override;
void DispatchOnConnect(mojom::ChannelType channel_type,
const std::string& channel_name,
std::optional<base::Value::Dict> source_tab,
const ExtensionApiFrameIdMap::FrameData& source_frame,
int guest_process_id,
int guest_render_frame_routing_id,
const MessagingEndpoint& source_endpoint,
const std::string& target_extension_id,
const GURL& source_url,
std::optional<url::Origin> source_origin,
const std::set<base::UnguessableToken>&
open_channel_tracking_ids) override;
void DispatchOnDisconnect(const std::string& error_message) override;
void DispatchOnMessage(const Message& message) override;
void IncrementLazyKeepaliveCount(Activity::Type activity_type) override;
void DecrementLazyKeepaliveCount(Activity::Type activity_type) override;
void OpenPort(int process_id, const PortContext& port_context) override;
void ClosePort(int process_id, int routing_id, int worker_thread_id) override;
void NotifyResponsePending() override;
private:
class ContextTracker;
struct IPCTarget;
// Registers a frame as a receiver / sender.
void RegisterFrame(content::RenderFrameHost* render_frame_host);
// Unregisters a frame as a receiver / sender. When there are no registered
// frames any more, the port closes via CloseChannel().
bool UnregisterFrame(content::RenderFrameHost* render_frame_host);
bool UnregisterFrame(const content::GlobalRenderFrameHostToken& frame_token);
// Unregisters all the frames whose outermost main frame is `main_frame`. When
// there are no registered frames any more, the port closes via
// CloseChannel().
// It returns if the port and the associated channel is closed.
bool UnregisterFramesUnderMainFrame(
content::RenderFrameHost* main_frame,
std::optional<std::string> error_message = std::nullopt);
// Methods to register/unregister a Service Worker endpoint for this port.
void RegisterWorker(const WorkerId& worker_id);
bool UnregisterWorker(const WorkerId& worker_id);
void UnregisterWorker(int render_process_id, int worker_thread_id);
// Immediately close the port and its associated channel.
void CloseChannel(std::optional<std::string> error_message = std::nullopt);
using SendCallback = base::RepeatingCallback<void(mojom::MessagePort*)>;
void SendToPort(SendCallback send_callback);
// Check if this activity of this type on this port would keep servicer worker
// alive.
bool IsServiceWorkerActivity(Activity::Type activity_type);
bool ShouldSkipFrameForBFCache(content::RenderFrameHost* render_frame_host);
void OnConnectResponse(
const PortContext& port_context,
const base::UnguessableToken& connect_dispatch_tracking_id,
bool success);
void Prune(const PortContext& port_context,
const base::UnguessableToken& connect_dispatch_tracking_id);
void ReportOpenChannelResult(
MessageTracker::OpenChannelMessagePipelineResult emit_value);
void ReportOpenChannelConnectDispatchResult(
const base::UnguessableToken& tracking_id,
MessageTracker::OpenChannelMessagePipelineResult emit_value);
ExtensionId extension_id_;
raw_ptr<content::BrowserContext> browser_context_ = nullptr;
// Whether this port corresponds to *all* extension contexts. Should only be
// true for a receiver port.
bool for_all_extension_contexts_ = false;
// When the port is used as a sender, this map contains only one element.
// If used as a receiver, it may contain any number of frames.
// This map is populated before the first message is sent to the destination,
// and shrinks over time when the port is rejected by the recipient frame, or
// when the frame is removed or unloaded.
std::map<content::GlobalRenderFrameHostToken,
mojo::AssociatedRemote<mojom::MessagePort>>
frames_;
// Service Worker endpoints for this port.
std::map<WorkerId, mojo::AssociatedRemote<mojom::MessagePort>>
service_workers_;
// The set of frames and workers that have not been connected yet. These
// should only have items during connection setup time.
std::set<content::GlobalRenderFrameHostToken> pending_frames_;
std::set<WorkerId> pending_service_workers_;
// GUIDs of Service Workers that have pending keepalive requests inflight.
std::map<WorkerId, std::vector<base::Uuid>> pending_keepalive_uuids_;
// Whether the renderer acknowledged creation of the port. This is used to
// distinguish abnormal port closure (e.g. no receivers) from explicit port
// closure (e.g. by the port.disconnect() JavaScript method in the renderer).
bool port_was_created_ = false;
// Whether one of the receivers has indicated that it will respond later and
// the opener should be expecting that response. Used to determine if we
// should notify the opener of a message port being closed before an expected
// response was received. By default this is assumed to be false until one of
// the receivers notifies us otherwise.
// Note: this is currently only relevant for messaging using
// OneTimeMessageHandlers, where the receivers are able to indicate they are
// going to respond asynchronously.
bool asynchronous_reply_pending_ = false;
// Used in IncrementLazyKeepaliveCount
raw_ptr<ExtensionHost, DanglingUntriaged> background_host_ptr_ = nullptr;
std::unique_ptr<ContextTracker> context_tracker_;
// The set of PortContexts for which we're waiting on a response to
// OnConnectResponse().
std::set<PortContext> pending_contexts_to_respond_;
// Tracking ID to every metric to emit once the result of the channel opening
// is determined.
std::set<base::UnguessableToken> pending_open_channel_tracking_ids_;
// Tracking ID to every metric to emit if the channel (this class) closes
// (destructs) before each port has responded to DispatchOnConnect IPC.
std::set<base::UnguessableToken>
pending_open_channel_connect_dispatch_tracking_ids_;
base::WeakPtrFactory<ExtensionMessagePort> weak_ptr_factory_{this};
};
} // namespace extensions
#endif // EXTENSIONS_BROWSER_API_MESSAGING_EXTENSION_MESSAGE_PORT_H_
|