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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
content / browser / renderer_host / render_frame_proxy_host.h [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_PROXY_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_PROXY_HOST_H_
#include <stdint.h>
#include <memory>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/safe_ref.h"
#include "content/browser/renderer_host/agent_scheduling_group_host.h"
#include "content/browser/site_instance_impl.h"
#include "content/common/content_export.h"
#include "content/common/frame.mojom.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_process_host.h"
#include "ipc/ipc_listener.h"
#include "ipc/ipc_sender.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/mojom/frame/frame.mojom.h"
#include "third_party/blink/public/mojom/input/focus_type.mojom-forward.h"
#include "third_party/blink/public/mojom/messaging/transferable_message.mojom-forward.h"
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-forward.h"
namespace blink {
class AssociatedInterfaceProvider;
}
namespace gfx {
class Rect;
class RectF;
}
namespace perfetto {
namespace protos {
namespace pbzero {
class RenderFrameProxyHost;
}
} // namespace protos
} // namespace perfetto
namespace content {
class BatchedProxyIPCSender;
class CrossProcessFrameConnector;
class FrameTreeNode;
class RenderViewHostImpl;
class RenderWidgetHostViewChildFrame;
class SiteInstanceGroup;
// When a page's frames are rendered by multiple processes, each renderer has a
// full copy of the frame tree. It has full RenderFrames for the frames it is
// responsible for rendering and placeholder objects (i.e.,
// `blink::RemoteFrame`) for frames rendered by other processes.
//
// This class is the browser-side host object for the placeholder. Each node in
// the frame tree has a RenderFrameHost for the active SiteInstance and a set
// of RenderFrameProxyHost objects - one for all other SiteInstanceGroups with
// references to this frame. The proxies allow us to keep existing window
// references valid over cross-process navigations and route cross-site
// asynchronous JavaScript calls, such as postMessage.
//
// RenderFrameProxyHost is created whenever a cross-site
// navigation occurs and a reference to the frame navigating needs to be kept
// alive. A RenderFrameProxyHost and a RenderFrameHost in the same
// SiteInstanceGroup can exist at the same time, but only one will be "active"
// at a time. There are two cases where the two objects will coexist:
// * When navigating cross-process and there is already a RenderFrameProxyHost
// for the new SiteInstanceGroup. A pending RenderFrameHost is created, but it
// is not used until it commits. At that point, RenderFrameHostManager
// transitions the pending RenderFrameHost to the active one and deletes the
// proxy.
// * When navigating cross-process and the existing document has an unload
// event handler. When the new navigation commits, RenderFrameHostManager
// creates a RenderFrameProxyHost for the old SiteInstanceGroup and uses it
// going forward. It also instructs the RenderFrameHost to run the unload event
// handler and is kept alive for the duration. Once the event handling is
// complete, the RenderFrameHost is deleted.
class CONTENT_EXPORT RenderFrameProxyHost
: public IPC::Listener,
public IPC::Sender,
public blink::mojom::RemoteFrameHost,
public blink::mojom::RemoteMainFrameHost {
public:
// A test observer to monitor RenderFrameProxyHosts.
class TestObserver {
public:
virtual ~TestObserver() = default;
// Called when a RenderFrameProxyHost is created.
virtual void OnCreated(RenderFrameProxyHost* host) {}
// Called when a RenderFrameProxyHost is deleted.
virtual void OnDeleted(RenderFrameProxyHost* host) {}
// Called when Remote/RemoteMainFrame mojo channels are bound to a
// RenderFrameProxyHost.
virtual void OnRemoteFrameBound(RenderFrameProxyHost* host) {}
virtual void OnRemoteMainFrameBound(RenderFrameProxyHost* host) {}
};
static void SetObserverForTesting(TestObserver* observer);
static RenderFrameProxyHost* FromID(int process_id, int routing_id);
static RenderFrameProxyHost* FromFrameToken(
int process_id,
const blink::RemoteFrameToken& frame_token);
static bool IsFrameTokenInUse(const blink::RemoteFrameToken& frame_token);
RenderFrameProxyHost(SiteInstanceGroup* site_instance_group,
scoped_refptr<RenderViewHostImpl> render_view_host,
FrameTreeNode* frame_tree_node,
const blink::RemoteFrameToken& frame_token);
RenderFrameProxyHost(const RenderFrameProxyHost&) = delete;
RenderFrameProxyHost& operator=(const RenderFrameProxyHost&) = delete;
~RenderFrameProxyHost() override;
RenderProcessHost* GetProcess() const { return process_; }
// Initializes the object and creates the `blink::RemoteFrame` in the process
// for the `site_instance_group_`. If `batched_proxy_ipc_sender` is not null,
// then the proxy will not be created immediately. It will be batch created
// later.
bool InitRenderFrameProxy(
BatchedProxyIPCSender* batched_proxy_ipc_sender = nullptr);
int GetRoutingID() const { return routing_id_; }
GlobalRoutingID GetGlobalID() const {
return GlobalRoutingID(GetProcess()->GetID(), routing_id_);
}
// Each RenderFrameProxyHost belongs to a SiteInstanceGroup, where it is a
// placeholder for a frame in a different SiteInstanceGroup.
SiteInstanceGroup* site_instance_group() const {
return site_instance_group_.get();
}
// TODO(crbug.com/40169570): FrameTree and FrameTreeNode are not const
// as with prerenderer activation the page needs to move between
// FrameTreeNodes and FrameTrees. Note that FrameTreeNode can only change for
// root nodes. As it's hard to make sure that all places handle this
// transition correctly, MPArch will remove references from this class to
// FrameTree/FrameTreeNode.
FrameTreeNode* frame_tree_node() const { return frame_tree_node_; }
void set_frame_tree_node(FrameTreeNode& frame_tree_node) {
frame_tree_node_ = &frame_tree_node;
}
// Associates the RenderWidgetHostViewChildFrame |view| with this
// RenderFrameProxyHost. If |initial_frame_size| isn't specified at this time,
// the child frame will wait until the CrossProcessFrameConnector
// receives its size from the parent via FrameHostMsg_UpdateResizeParams
// before it begins parsing the content.
void SetChildRWHView(RenderWidgetHostViewChildFrame* view,
const gfx::Size* initial_frame_size,
bool allow_paint_holding);
RenderViewHostImpl* GetRenderViewHost();
// IPC::Sender
bool Send(IPC::Message* msg) override;
// IPC::Listener
bool OnMessageReceived(const IPC::Message& msg) override;
std::string ToDebugString() override;
CrossProcessFrameConnector* cross_process_frame_connector() {
return cross_process_frame_connector_.get();
}
// Update the frame's opener in the renderer process in response to the
// opener being modified (e.g., with window.open or being set to null) in
// another renderer process.
void UpdateOpener();
// Set this proxy as the focused frame in the renderer process. This is
// called to replicate the focused frame when a frame in a different process
// becomes focused.
void SetFocusedFrame();
// Scroll |rect_to_scroll| into view, starting from this proxy's FrameOwner
// element in the frame's parent. Calling this continues a scroll started in
// the frame's current process. |rect_to_scroll| is with respect to the
// coordinates of the originating frame in OOPIF process.
void ScrollRectToVisible(const gfx::RectF& rect_to_scroll,
blink::mojom::ScrollIntoViewParamsPtr params);
// Sets render frame proxy created state. If |created| is false, any existing
// mojo connections to RenderFrameProxyHost will be closed.
void SetRenderFrameProxyCreated(bool created);
// Returns if the `blink::RemoteFrame` for this host is alive.
bool is_render_frame_proxy_live() const {
return render_frame_proxy_created_;
}
// Returns associated remote for the blink::mojom::RemoteFrame Mojo interface.
const mojo::AssociatedRemote<blink::mojom::RemoteFrame>&
GetAssociatedRemoteFrame();
// Returns associated remote for the blink::mojom::RemoteMainFrame Mojo
// interface.
const mojo::AssociatedRemote<blink::mojom::RemoteMainFrame>&
GetAssociatedRemoteMainFrame();
// blink::mojom::RemoteFrameHost
void SetInheritedEffectiveTouchAction(cc::TouchAction touch_action) override;
void UpdateRenderThrottlingStatus(bool is_throttled,
bool subtree_throttled,
bool display_locked) override;
void VisibilityChanged(blink::mojom::FrameVisibility visibility) override;
void DidFocusFrame() override;
void CheckCompleted() override;
void CapturePaintPreviewOfCrossProcessSubframe(
const gfx::Rect& clip_rect,
const base::UnguessableToken& guid) override;
void SetIsInert(bool inert) override;
void DidChangeOpener(
const std::optional<blink::LocalFrameToken>& opener_frame_token) override;
void AdvanceFocus(blink::mojom::FocusType focus_type,
const blink::LocalFrameToken& source_frame_token) override;
void RouteMessageEvent(
const std::optional<blink::LocalFrameToken>& source_frame_token,
const url::Origin& source_origin,
const std::u16string& target_origin,
blink::TransferableMessage message) override;
void PrintCrossProcessSubframe(const gfx::Rect& rect,
int document_cookie) override;
void Detach() override;
void UpdateViewportIntersection(
blink::mojom::ViewportIntersectionStatePtr intersection_state,
const std::optional<blink::FrameVisualProperties>& visual_properties)
override;
void SynchronizeVisualProperties(
const blink::FrameVisualProperties& frame_visual_properties) override;
void OpenURL(blink::mojom::OpenURLParamsPtr params) override;
// blink::mojom::RemoteMainFrameHost overrides:
void FocusPage() override;
void TakeFocus(bool reverse) override;
void UpdateTargetURL(
const GURL& url,
blink::mojom::RemoteMainFrameHost::UpdateTargetURLCallback callback)
override;
void RouteCloseEvent() override;
// Requests a viz::LocalSurfaceId to enable auto-resize mode from the parent
// renderer.
void EnableAutoResize(const gfx::Size& min_size, const gfx::Size& max_size);
// Requests a viz::LocalSurfaceId to disable auto-resize mode from the parent
// renderer.
void DisableAutoResize();
void DidUpdateVisualProperties(const cc::RenderFrameMetadata& metadata);
void ChildProcessGone();
bool IsInertForTesting();
mojo::PendingAssociatedReceiver<blink::mojom::RemoteFrame>
BindRemoteFrameReceiverForTesting();
mojo::PendingAssociatedReceiver<blink::mojom::RemoteMainFrame>
BindRemoteMainFrameReceiverForTesting();
const blink::RemoteFrameToken& GetFrameToken() const { return frame_token_; }
// Bind mojo endpoints of the Remote/RemoteMainFrame in blink and pass unbound
// corresponding endpoints. The corresponding endpoints should be transferred
// and bound in blink.
blink::mojom::RemoteFrameInterfacesFromBrowserPtr
CreateAndBindRemoteFrameInterfaces();
blink::mojom::RemoteMainFrameInterfacesPtr
CreateAndBindRemoteMainFrameInterfaces();
// Bind mojo endpoints of the Remote/RemoteMainFrame in blink.
void BindRemoteFrameInterfaces(
mojo::PendingAssociatedRemote<blink::mojom::RemoteFrame>,
mojo::PendingAssociatedReceiver<blink::mojom::RemoteFrameHost>);
void BindRemoteMainFrameInterfaces(
mojo::PendingAssociatedRemote<blink::mojom::RemoteMainFrame>
remote_main_frame,
mojo::PendingAssociatedReceiver<blink::mojom::RemoteMainFrameHost>
remote_main_frame_host_receiver);
// Invalidate the mojo connections between this RenderFrameProxyHost and its
// associated instances in renderer, allowing the endpoints to be re-bound.
// This is needed when:
// - the renderer side object goes away due to the renderer process going away
// (i.e. crashing)
// - undoing a `CommitNavigation()` that has already been sent to a
// speculative RenderFrameHost by swapping it back to a
// `blink::RemoteFrame`.
void TearDownMojoConnection();
using TraceProto = perfetto::protos::pbzero::RenderFrameProxyHost;
// Write a representation of this object into a trace.
void WriteIntoTrace(perfetto::TracedProto<TraceProto> proto) const;
base::SafeRef<RenderFrameProxyHost> GetSafeRef();
private:
// These interceptors need access to frame_host_receiver_for_testing().
friend class InitiatorClosingOpenURLInterceptor;
friend class RemoteFrameHostInterceptor;
friend class UpdateViewportIntersectionMessageFilter;
friend class SynchronizeVisualPropertiesInterceptor;
// Helper to retrieve the |AgentSchedulingGroup| this proxy host is associated
// with.
AgentSchedulingGroupHost& GetAgentSchedulingGroup();
// Helper to compute the serialized source origin from an actual source origin
// for postMessage. This will ultimately be exposed to JavaScript via the
// message's event.origin field.
std::u16string SerializePostMessageSourceOrigin(
const url::Origin& source_origin);
// Needed for tests to be able to swap the implementation and intercept calls.
mojo::AssociatedReceiver<blink::mojom::RemoteFrameHost>&
frame_host_receiver_for_testing() {
return remote_frame_host_receiver_;
}
// This RenderFrameProxyHost's routing id.
int routing_id_;
// The SiteInstanceGroup this RenderFrameProxyHost belongs to, where it is a
// placeholder for a frame in a different SiteInstanceGroup.
scoped_refptr<SiteInstanceGroup> site_instance_group_;
// The renderer process this RenderFrameProxyHost is associated with. It is
// equivalent to the result of site_instance_group_->GetProcess(), but that
// method has the side effect of creating the process if it doesn't exist.
// Cache a pointer to avoid unnecessary process creation.
raw_ptr<RenderProcessHost> process_;
// The node in the frame tree where this proxy is located.
raw_ptr<FrameTreeNode> frame_tree_node_;
// True if we have a live `blink::RemoteFrame` for this host.
bool render_frame_proxy_created_;
// When a RenderFrameHost is in a different process from its parent in the
// frame tree, this class connects its associated RenderWidgetHostView
// to this RenderFrameProxyHost, which corresponds to the same frame in the
// parent's renderer process.
std::unique_ptr<CrossProcessFrameConnector> cross_process_frame_connector_;
// The RenderViewHost that this RenderFrameProxyHost is associated with.
//
// It is kept alive as long as any RenderFrameHosts or RenderFrameProxyHosts
// are using it.
//
// TODO(creis): RenderViewHost will eventually go away and be replaced with
// some form of page context.
scoped_refptr<RenderViewHostImpl> render_view_host_;
std::unique_ptr<blink::AssociatedInterfaceProvider>
remote_associated_interfaces_;
// Holder of Mojo connection with the Frame service in Blink.
mojo::AssociatedRemote<blink::mojom::RemoteFrame> remote_frame_;
// Holder of Mojo connection with the RemoteMainFrame in Blink. This remote
// will be valid when the frame is the active main frame.
mojo::AssociatedRemote<blink::mojom::RemoteMainFrame> remote_main_frame_;
mojo::AssociatedReceiver<blink::mojom::RemoteFrameHost>
remote_frame_host_receiver_{this};
mojo::AssociatedReceiver<blink::mojom::RemoteMainFrameHost>
remote_main_frame_host_receiver_{this};
blink::RemoteFrameToken frame_token_;
base::WeakPtrFactory<RenderFrameProxyHost> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_FRAME_PROXY_HOST_H_