prerendering: Migrate to one Activate IPC per RenderView only.
Before this CL, we had an Activate IPC per RenderView and also an
Activate IPC for each document. This CL removes the per-document one.
This fixes a race where a document created in the renderer before the
RenderView IPC arrives starts with document.prerendering true, but it
never receives the per-document IPC so never transitions to
document.prerendering false.
This is the next step after commit 84e9a9b442
. See [1], [2] for more
details on the design decision.
This CL does not add tests because it is difficult to test the above
race condition. The existing tests including ones added in
https://chromium-review.googlesource.com/c/chromium/src/+/3034321 should
continue to pass.
[1] https://groups.google.com/a/chromium.org/g/navigation-dev/c/v3T8NfWPTg8/m/brmF98nKAAAJ
[2] https://docs.google.com/document/d/1S8_ilRC_TkDa4Wz3PvBPYhhqIuGNHDX0DKsvjMFotKM/edit?usp=sharing
Bug: 1229552
Change-Id: Iabadf0ed2c1ca36b1153553aeed0f9c412a4ba49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3033843
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: Alexander Timin <altimin@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#904994}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
7319949d93
commit
f78c2191a9
content
mojo/public/cpp/bindings
third_party/blink
public
mojom
renderer
@ -88,11 +88,20 @@ void MojoBinderPolicyApplier::PrepareToGrantAll() {
|
||||
void MojoBinderPolicyApplier::GrantAll() {
|
||||
DCHECK_NE(mode_, Mode::kGrantAll);
|
||||
|
||||
// GrantAll() should be called inside a Mojo message call stack, because it
|
||||
// binds deferred receivers by invoking
|
||||
// BrowserInterfaceBroker::BindInterface(), which assumes it is called within
|
||||
// a Mojo messaging call. See https://crbug.com/1217977 for more information.
|
||||
DCHECK(mojo::GetBadMessageCallback());
|
||||
// Check that we are in a Mojo message dispatch, since the deferred binders
|
||||
// might call mojo::ReportBadMessage().
|
||||
//
|
||||
// TODO(https://crbug.com/1217977): Give the deferred_binders_ a
|
||||
// BadMessageCallback and forbid them from using mojo::ReportBadMessage()
|
||||
// directly. We are currently in the message stack of one of the PageBroadcast
|
||||
// Mojo callbacks handled by RenderViewHost, so if a binder calls
|
||||
// mojo::ReportBadMessage() it kills possibly the wrong renderer. Even if we
|
||||
// only run the binders associated with the RVH for each message per-RVH,
|
||||
// there are still subtle problems with running all these callbacks at once:
|
||||
// for example, mojo::GetMessageCallback()/mojo::ReportBadMessage() can only
|
||||
// be called once per message dispatch.
|
||||
DCHECK(mojo::IsInMessageDispatch());
|
||||
|
||||
mode_ = Mode::kGrantAll;
|
||||
|
||||
// It's safe to iterate over `deferred_binders_` because no more callbacks
|
||||
|
@ -108,8 +108,12 @@ class MockPageBroadcast : public blink::mojom::PageBroadcast {
|
||||
SetPageLifecycleStateCallback callback),
|
||||
(override));
|
||||
MOCK_METHOD(void, AudioStateChanged, (bool is_audio_playing), (override));
|
||||
MOCK_METHOD(void, ActivatePrerenderedPage, (), (override));
|
||||
MOCK_METHOD(void, SetInsidePortal, (bool is_inside_portal), (override));
|
||||
MOCK_METHOD(void,
|
||||
ActivatePrerenderedPage,
|
||||
(base::TimeTicks navigation_start,
|
||||
ActivatePrerenderedPageCallback callback),
|
||||
(override));
|
||||
MOCK_METHOD(void,
|
||||
UpdateWebPreferences,
|
||||
(const ::blink::web_pref::WebPreferences& preferences),
|
||||
|
@ -4,12 +4,14 @@
|
||||
|
||||
#include "content/browser/renderer_host/page_impl.h"
|
||||
|
||||
#include "base/barrier_closure.h"
|
||||
#include "content/browser/manifest/manifest_manager_host.h"
|
||||
#include "content/browser/renderer_host/frame_tree_node.h"
|
||||
#include "content/browser/renderer_host/page_delegate.h"
|
||||
#include "content/browser/renderer_host/render_frame_host_delegate.h"
|
||||
#include "content/browser/renderer_host/render_frame_host_impl.h"
|
||||
#include "content/browser/renderer_host/render_view_host_delegate.h"
|
||||
#include "content/browser/renderer_host/render_view_host_impl.h"
|
||||
#include "content/public/browser/render_view_host.h"
|
||||
#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
|
||||
|
||||
@ -91,6 +93,61 @@ void PageImpl::SetContentsMimeType(std::string mime_type) {
|
||||
contents_mime_type_ = std::move(mime_type);
|
||||
}
|
||||
|
||||
void PageImpl::SetActivationStartTime(base::TimeTicks activation_start) {
|
||||
DCHECK(!activation_start_time_for_prerendering_);
|
||||
activation_start_time_for_prerendering_ = activation_start;
|
||||
}
|
||||
|
||||
void PageImpl::ActivateForPrerendering(
|
||||
std::set<RenderViewHostImpl*>& render_view_hosts) {
|
||||
base::OnceClosure did_activate_render_views =
|
||||
base::BindOnce(&PageImpl::DidActivateAllRenderViewsForPrerendering,
|
||||
weak_factory_.GetWeakPtr());
|
||||
|
||||
base::RepeatingClosure barrier = base::BarrierClosure(
|
||||
render_view_hosts.size(), std::move(did_activate_render_views));
|
||||
for (RenderViewHostImpl* rvh : render_view_hosts) {
|
||||
base::TimeTicks navigation_start_to_send;
|
||||
// Only send navigation_start to the RenderViewHost for the main frame to
|
||||
// avoid sending the info cross-origin. Only this RenderViewHost needs the
|
||||
// info, as we expect the other RenderViewHosts are made for cross-origin
|
||||
// iframes which have not yet loaded their document. To the renderer, it
|
||||
// just looks like an ongoing navigation is happening in the frame and has
|
||||
// not yet committed. These RenderViews still need to know about activation
|
||||
// so their documents are created in the non-prerendered state once their
|
||||
// navigation is committed.
|
||||
if (main_document_.GetRenderViewHost() == rvh)
|
||||
navigation_start_to_send = *activation_start_time_for_prerendering_;
|
||||
|
||||
rvh->ActivatePrerenderedPage(navigation_start_to_send, barrier);
|
||||
}
|
||||
|
||||
// Prepare each RenderFrameHostImpl in this Page for activation.
|
||||
// TODO(https://crbug.com/1232528): Currently we check GetPage() below because
|
||||
// RenderFrameHostImpls may be in a different Page, if, e.g., they are in an
|
||||
// inner WebContents. These are in a different FrameTree which might not know
|
||||
// it is being prerendered. We should teach these FrameTrees that they are
|
||||
// being prerendered, or ban inner FrameTrees in a prerendering page.
|
||||
main_document_.ForEachRenderFrameHost(base::BindRepeating(
|
||||
[](PageImpl* page, RenderFrameHostImpl* rfh) {
|
||||
if (&rfh->GetPage() != page)
|
||||
return;
|
||||
rfh->RendererWillActivateForPrerendering();
|
||||
},
|
||||
this));
|
||||
}
|
||||
|
||||
void PageImpl::DidActivateAllRenderViewsForPrerendering() {
|
||||
// Tell each RenderFrameHostImpl in this Page that activation finished.
|
||||
main_document_.ForEachRenderFrameHost(base::BindRepeating(
|
||||
[](PageImpl* page, RenderFrameHostImpl* rfh) {
|
||||
if (&rfh->GetPage() != page)
|
||||
return;
|
||||
rfh->RendererDidActivateForPrerendering();
|
||||
},
|
||||
this));
|
||||
}
|
||||
|
||||
RenderFrameHost& PageImpl::GetMainDocumentHelper() {
|
||||
return main_document_;
|
||||
}
|
||||
|
@ -6,8 +6,11 @@
|
||||
#define CONTENT_BROWSER_RENDERER_HOST_PAGE_IMPL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/time/time.h"
|
||||
#include "content/browser/fenced_frame/fenced_frame_url_mapping.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/public/browser/page.h"
|
||||
@ -22,6 +25,7 @@ namespace content {
|
||||
|
||||
class PageDelegate;
|
||||
class RenderFrameHostImpl;
|
||||
class RenderViewHostImpl;
|
||||
|
||||
// This implements the Page interface that is exposed to embedders of content,
|
||||
// and adds things only visible to content.
|
||||
@ -92,7 +96,21 @@ class CONTENT_EXPORT PageImpl : public Page {
|
||||
return anonymous_iframes_nonce_;
|
||||
}
|
||||
|
||||
// Sets the start time of the prerender activation navigation for this page.
|
||||
// TODO(falken): Plumb NavigationRequest to
|
||||
// RenderFrameHostManager::CommitPending and remove this.
|
||||
void SetActivationStartTime(base::TimeTicks activation_start);
|
||||
|
||||
// Called during the prerender activation navigation. Sends an IPC to the
|
||||
// RenderViews in the renderers, instructing them to transition their
|
||||
// documents from prerendered to activated. Tells the corresponding
|
||||
// RenderFrameHostImpls that the renderer will be activating their documents.
|
||||
void ActivateForPrerendering(
|
||||
std::set<RenderViewHostImpl*>& render_view_hosts_to_activate);
|
||||
|
||||
private:
|
||||
void DidActivateAllRenderViewsForPrerendering();
|
||||
|
||||
// This method is needed to ensure that PageImpl can both implement a Page's
|
||||
// method and define a new GetMainDocument(). Please refer to page.h for more
|
||||
// details.
|
||||
@ -155,6 +173,16 @@ class CONTENT_EXPORT PageImpl : public Page {
|
||||
// key of anonymous iframes which are children of this page's document.
|
||||
const base::UnguessableToken anonymous_iframes_nonce_ =
|
||||
base::UnguessableToken::Create();
|
||||
|
||||
// Prerender2: The start time of the activation navigation for prerendering,
|
||||
// which is passed to the renderer process, and will be accessible in the
|
||||
// prerendered page as PerformanceNavigationTiming.activationStart. Set after
|
||||
// navigation commit.
|
||||
// TODO(falken): Plumb NavigationRequest to
|
||||
// RenderFrameHostManager::CommitPending and remove this.
|
||||
absl::optional<base::TimeTicks> activation_start_time_for_prerendering_;
|
||||
|
||||
base::WeakPtrFactory<PageImpl> weak_factory_{this};
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
@ -3303,24 +3303,24 @@ void RenderFrameHostImpl::FrameSizeChanged(const gfx::Size& frame_size) {
|
||||
delegate_->FrameSizeChanged(this, frame_size);
|
||||
}
|
||||
|
||||
void RenderFrameHostImpl::DidActivateForPrerendering() {
|
||||
void RenderFrameHostImpl::RendererDidActivateForPrerendering() {
|
||||
DCHECK(blink::features::IsPrerender2Enabled());
|
||||
if (!is_notifying_activation_for_prerendering_) {
|
||||
mojo::ReportBadMessage("RFHI: DidActivateForPrerendering is unexpected");
|
||||
return;
|
||||
}
|
||||
is_notifying_activation_for_prerendering_ = false;
|
||||
|
||||
// The renderer calls `DidActivateForPrerendering()` to notify that it fired
|
||||
// the prerenderingchange event on a document. The browser now runs any
|
||||
// binders that were deferred during prerendering. This corresponds to the
|
||||
// following steps of the activate algorithm:
|
||||
// RendererDidActivateForPrerendering() is called after the renderer has
|
||||
// notified that it fired the prerenderingchange event on the documents. The
|
||||
// browser now runs any binders that were deferred during prerendering. This
|
||||
// corresponds to the following steps of the activate algorithm:
|
||||
//
|
||||
// https://jeremyroman.github.io/alternate-loading-modes/#prerendering-browsing-context-activate
|
||||
// Step 8.3.4. "For each steps in doc's post-prerendering activation steps
|
||||
// list:"
|
||||
// Step 8.3.4.1. "Run steps."
|
||||
broker_.ReleaseMojoBinderPolicies();
|
||||
|
||||
// Release Mojo capability control to run the binders. The RenderFrameHostImpl
|
||||
// may have been created after activation started, in which case it already
|
||||
// does not have Mojo capability control applied.
|
||||
if (broker_.GetMojoBinderPolicyApplier())
|
||||
broker_.ReleaseMojoBinderPolicies();
|
||||
}
|
||||
|
||||
void RenderFrameHostImpl::OnCreateChildFrame(
|
||||
@ -8829,10 +8829,10 @@ void RenderFrameHostImpl::CancelPrerenderingByMojoBinderPolicy(
|
||||
CancelPrerendering(PrerenderHost::FinalStatus::kMojoBinderPolicy);
|
||||
}
|
||||
|
||||
void RenderFrameHostImpl::ActivateForPrerendering() {
|
||||
void RenderFrameHostImpl::RendererWillActivateForPrerendering() {
|
||||
DCHECK(blink::features::IsPrerender2Enabled());
|
||||
|
||||
// Loosen the policies of the mojo capability control during dispatching the
|
||||
// Loosen the policies of the Mojo capability control during dispatching the
|
||||
// prerenderingchange event in Blink, because the page may start legitimately
|
||||
// using controlled interfaces once prerenderingchange is dispatched. We
|
||||
// cannot release policies at this point, i.e., we cannot run the deferred
|
||||
@ -8842,24 +8842,6 @@ void RenderFrameHostImpl::ActivateForPrerendering() {
|
||||
auto* applier = broker_.GetMojoBinderPolicyApplier();
|
||||
DCHECK(applier) << "prerendering pages should have a policy applier";
|
||||
applier->PrepareToGrantAll();
|
||||
|
||||
DCHECK(!is_notifying_activation_for_prerendering_);
|
||||
is_notifying_activation_for_prerendering_ = true;
|
||||
|
||||
// Currently cross origin iframes are deferred. So the origin must be same
|
||||
// as the main frame's origin. But if we will decide not to defer the cross
|
||||
// origin iframes, we need to remove the DCHECK_EQ and change the code not
|
||||
// to send |activation_start_time_for_prerendering| to the renderer.
|
||||
DCHECK_EQ(GetLastCommittedOrigin(), GetMainFrame()->GetLastCommittedOrigin());
|
||||
|
||||
// Notify the renderer of activation to update the prerendering state and
|
||||
// dispatch the prerenderingchange event.
|
||||
GetAssociatedLocalFrame()->ActivateForPrerendering(
|
||||
*GetMainFrame()
|
||||
->document_associated_data_->activation_start_time_for_prerendering);
|
||||
|
||||
for (auto& child : children_)
|
||||
child->current_frame_host()->ActivateForPrerendering();
|
||||
}
|
||||
|
||||
void RenderFrameHostImpl::BindMediaInterfaceFactoryReceiver(
|
||||
@ -10004,18 +9986,7 @@ bool RenderFrameHostImpl::DidCommitNavigationInternal(
|
||||
// Set the NavigationStart time for
|
||||
// PerformanceNavigationTiming.activationStart.
|
||||
// https://jeremyroman.github.io/alternate-loading-modes/#performance-navigation-timing-extension
|
||||
|
||||
// Currently, prerendering is only supported on same-origin pages. When
|
||||
// supporting cross-origin prerendering (https://crbug.com/1176054), we
|
||||
// need to change this CHECK to "if ()" not to send the activation start
|
||||
// time to the prerendering page so that it is not used to send
|
||||
// identifiers between origins.
|
||||
CHECK_EQ(GetLastCommittedOrigin(),
|
||||
navigation_request->GetOriginToCommit());
|
||||
DCHECK(
|
||||
!document_associated_data_->activation_start_time_for_prerendering);
|
||||
document_associated_data_->activation_start_time_for_prerendering =
|
||||
navigation_request->NavigationStart();
|
||||
GetPage().SetActivationStartTime(navigation_request->NavigationStart());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -1717,9 +1717,15 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
void CancelPrerenderingByMojoBinderPolicy(const std::string& interface_name);
|
||||
|
||||
// Prerender2:
|
||||
// Tells the renderer to dispatch the prerenderingchange event. Expects to
|
||||
// receive an acknowledgement via DidActivateForPrerendering().
|
||||
void ActivateForPrerendering();
|
||||
// Called when the Activate IPC is sent to the renderer. Puts the
|
||||
// MojoPolicyBinderApplier in "loose" mode via PrepareToGrantAll() until
|
||||
// DidActivateForPrerending() is called.
|
||||
void RendererWillActivateForPrerendering();
|
||||
|
||||
// Prerender2:
|
||||
// Called when the Activate IPC is acknowledged by the renderer. Relinquishes
|
||||
// the MojoPolicyBinderApplier.
|
||||
void RendererDidActivateForPrerendering();
|
||||
|
||||
// https://mikewest.github.io/corpp/#initialize-embedder-policy-for-global
|
||||
const network::CrossOriginEmbedderPolicy& cross_origin_embedder_policy()
|
||||
@ -2025,7 +2031,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
const absl::optional<std::u16string>& source_id,
|
||||
const absl::optional<std::u16string>& untrusted_stack_trace) override;
|
||||
void FrameSizeChanged(const gfx::Size& frame_size) override;
|
||||
void DidActivateForPrerendering() override;
|
||||
|
||||
// blink::LocalMainFrameHost overrides:
|
||||
void ScaleFactorChanged(float scale) override;
|
||||
@ -3746,12 +3751,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
// The Page object associated with the main document. It is nullptr for
|
||||
// subframes.
|
||||
std::unique_ptr<PageImpl> owned_page;
|
||||
|
||||
// Prerender2:
|
||||
// The activation start time for prerendering which is passed to the
|
||||
// renderer process, and will be accessible in the prerendered page as
|
||||
// PerformanceNavigationTiming.activationStart.
|
||||
absl::optional<base::TimeTicks> activation_start_time_for_prerendering;
|
||||
};
|
||||
|
||||
std::unique_ptr<DocumentAssociatedData> document_associated_data_;
|
||||
@ -3844,11 +3843,6 @@ class CONTENT_EXPORT RenderFrameHostImpl
|
||||
// class for more information.
|
||||
scoped_refptr<PolicyContainerHost> policy_container_host_;
|
||||
|
||||
// Prerender2:
|
||||
// This is true while notifying the frame in the renderer of activation for
|
||||
// prerendering.
|
||||
bool is_notifying_activation_for_prerendering_ = false;
|
||||
|
||||
// The current document's HTTP response head. This is used by back-forward
|
||||
// cache, for navigating a second time toward the same document.
|
||||
network::mojom::URLResponseHeadPtr last_response_head_;
|
||||
|
@ -3297,10 +3297,8 @@ void RenderFrameHostManager::CommitPending(
|
||||
} else {
|
||||
DCHECK_EQ(prev_state,
|
||||
RenderFrameHostImpl::LifecycleStateImpl::kPrerendering);
|
||||
for (RenderViewHostImpl* rvh : render_view_hosts_to_restore) {
|
||||
rvh->ActivatePrerenderedPage();
|
||||
}
|
||||
current_frame_host()->ActivateForPrerendering();
|
||||
current_frame_host()->GetPage().ActivateForPrerendering(
|
||||
render_view_hosts_to_restore);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,13 +560,16 @@ void RenderViewHostImpl::LeaveBackForwardCache(
|
||||
is_in_back_forward_cache_, std::move(page_restore_params));
|
||||
}
|
||||
|
||||
void RenderViewHostImpl::ActivatePrerenderedPage() {
|
||||
// Null in some unit tests that use TestRenderViewHost.
|
||||
// TODO(falken): Bind this in tests.
|
||||
if (!page_broadcast_)
|
||||
return;
|
||||
|
||||
page_broadcast_->ActivatePrerenderedPage();
|
||||
void RenderViewHostImpl::ActivatePrerenderedPage(
|
||||
base::TimeTicks activation_start,
|
||||
base::OnceClosure callback) {
|
||||
// TODO(https://crbug.com/1217977): Consider using a ScopedClosureRunner here
|
||||
// in case the renderer crashes before it can send us the callback. But we
|
||||
// can't do that until the linked bug is fixed, or else we can reach
|
||||
// DidActivateForPrerendering() outside of a Mojo message dispatch which
|
||||
// breaks the DCHECK for releasing Mojo Capability Control.
|
||||
page_broadcast_->ActivatePrerenderedPage(activation_start,
|
||||
std::move(callback));
|
||||
}
|
||||
|
||||
void RenderViewHostImpl::SetFrameTreeVisibility(
|
||||
|
@ -240,7 +240,8 @@ class CONTENT_EXPORT RenderViewHostImpl
|
||||
|
||||
bool is_in_back_forward_cache() const { return is_in_back_forward_cache_; }
|
||||
|
||||
void ActivatePrerenderedPage();
|
||||
void ActivatePrerenderedPage(base::TimeTicks activation_start,
|
||||
base::OnceClosure callback);
|
||||
|
||||
void SetFrameTreeVisibility(blink::mojom::PageVisibilityState visibility);
|
||||
|
||||
|
@ -165,9 +165,6 @@ void FakeLocalFrame::MixedContentFound(
|
||||
bool had_redirect,
|
||||
network::mojom::SourceLocationPtr source_location) {}
|
||||
|
||||
void FakeLocalFrame::ActivateForPrerendering(base::TimeTicks activation_start) {
|
||||
}
|
||||
|
||||
void FakeLocalFrame::BindDevToolsAgent(
|
||||
mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgentHost> host,
|
||||
mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> receiver) {}
|
||||
|
@ -124,7 +124,6 @@ class FakeLocalFrame : public blink::mojom::LocalFrame {
|
||||
const GURL& url_before_redirects,
|
||||
bool had_redirect,
|
||||
network::mojom::SourceLocationPtr source_location) override;
|
||||
void ActivateForPrerendering(base::TimeTicks activation_start) override;
|
||||
void BindDevToolsAgent(
|
||||
mojo::PendingAssociatedRemote<blink::mojom::DevToolsAgentHost> host,
|
||||
mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> receiver)
|
||||
|
@ -372,6 +372,8 @@ static_library("test_support") {
|
||||
"test_navigation_url_loader_factory.h",
|
||||
"test_overscroll_delegate.cc",
|
||||
"test_overscroll_delegate.h",
|
||||
"test_page_broadcast.cc",
|
||||
"test_page_broadcast.h",
|
||||
"test_render_frame.cc",
|
||||
"test_render_frame.h",
|
||||
"test_render_frame_host.cc",
|
||||
|
46
content/test/test_page_broadcast.cc
Normal file
46
content/test/test_page_broadcast.cc
Normal file
@ -0,0 +1,46 @@
|
||||
// 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.
|
||||
|
||||
#include "content/test/test_page_broadcast.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
TestPageBroadcast::TestPageBroadcast(
|
||||
mojo::PendingAssociatedReceiver<blink::mojom::PageBroadcast> receiver)
|
||||
: receiver_(this, std::move(receiver)) {}
|
||||
|
||||
TestPageBroadcast::~TestPageBroadcast() = default;
|
||||
|
||||
// The user should add functionality as needed.
|
||||
|
||||
void TestPageBroadcast::SetPageLifecycleState(
|
||||
blink::mojom::PageLifecycleStatePtr state,
|
||||
blink::mojom::PageRestoreParamsPtr page_restore_params,
|
||||
SetPageLifecycleStateCallback callback) {
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void TestPageBroadcast::AudioStateChanged(bool is_audio_playing) {}
|
||||
|
||||
void TestPageBroadcast::ActivatePrerenderedPage(
|
||||
base::TimeTicks activation_start,
|
||||
ActivatePrerenderedPageCallback callback) {
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void TestPageBroadcast::SetInsidePortal(bool is_inside_portal) {}
|
||||
|
||||
void TestPageBroadcast::UpdateWebPreferences(
|
||||
const blink::web_pref::WebPreferences& preferences) {}
|
||||
|
||||
void TestPageBroadcast::UpdateRendererPreferences(
|
||||
const blink::RendererPreferences& preferences) {}
|
||||
|
||||
void TestPageBroadcast::SetHistoryOffsetAndLength(int32_t history_offset,
|
||||
int32_t history_length) {}
|
||||
|
||||
void TestPageBroadcast::SetPageBaseBackgroundColor(
|
||||
absl::optional<SkColor> color) {}
|
||||
|
||||
} // namespace content
|
42
content/test/test_page_broadcast.h
Normal file
42
content/test/test_page_broadcast.h
Normal file
@ -0,0 +1,42 @@
|
||||
// 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_TEST_TEST_PAGE_BROADCAST_H_
|
||||
#define CONTENT_TEST_TEST_PAGE_BROADCAST_H_
|
||||
|
||||
#include "third_party/blink/public/mojom/page/page.mojom.h"
|
||||
|
||||
#include "mojo/public/cpp/bindings/associated_receiver.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
class TestPageBroadcast : public blink::mojom::PageBroadcast {
|
||||
public:
|
||||
explicit TestPageBroadcast(
|
||||
mojo::PendingAssociatedReceiver<blink::mojom::PageBroadcast> receiver);
|
||||
~TestPageBroadcast() override;
|
||||
|
||||
private:
|
||||
void SetPageLifecycleState(
|
||||
blink::mojom::PageLifecycleStatePtr state,
|
||||
blink::mojom::PageRestoreParamsPtr page_restore_params,
|
||||
SetPageLifecycleStateCallback callback) override;
|
||||
void AudioStateChanged(bool is_audio_playing) override;
|
||||
void ActivatePrerenderedPage(base::TimeTicks activation_start,
|
||||
ActivatePrerenderedPageCallback) override;
|
||||
void SetInsidePortal(bool is_inside_portal) override;
|
||||
void UpdateWebPreferences(
|
||||
const blink::web_pref::WebPreferences& preferences) override;
|
||||
void UpdateRendererPreferences(
|
||||
const blink::RendererPreferences& preferences) override;
|
||||
void SetHistoryOffsetAndLength(int32_t history_offset,
|
||||
int32_t history_length) override;
|
||||
void SetPageBaseBackgroundColor(absl::optional<SkColor> color) override;
|
||||
|
||||
mojo::AssociatedReceiver<blink::mojom::PageBroadcast> receiver_;
|
||||
};
|
||||
|
||||
} // namespace content
|
||||
|
||||
#endif // CONTENT_TEST_TEST_PAGE_BROADCAST_H_
|
@ -26,6 +26,7 @@
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "content/public/common/content_client.h"
|
||||
#include "content/public/common/drop_data.h"
|
||||
#include "content/test/test_page_broadcast.h"
|
||||
#include "content/test/test_render_frame_host.h"
|
||||
#include "content/test/test_render_view_host.h"
|
||||
#include "content/test/test_web_contents.h"
|
||||
@ -324,6 +325,11 @@ bool TestRenderViewHost::CreateRenderView(
|
||||
proxy_host->SetRenderFrameProxyCreated(true);
|
||||
}
|
||||
|
||||
mojo::AssociatedRemote<blink::mojom::PageBroadcast> broadcast_remote;
|
||||
page_broadcast_ = std::make_unique<TestPageBroadcast>(
|
||||
broadcast_remote.BindNewEndpointAndPassDedicatedReceiver());
|
||||
BindPageBroadcast(broadcast_remote.Unbind());
|
||||
|
||||
opener_frame_token_ = opener_frame_token;
|
||||
DCHECK(IsRenderViewLive());
|
||||
return true;
|
||||
|
@ -50,6 +50,7 @@ namespace content {
|
||||
class FrameTree;
|
||||
class SiteInstance;
|
||||
class TestRenderFrameHost;
|
||||
class TestPageBroadcast;
|
||||
class TestWebContents;
|
||||
|
||||
// TestRenderWidgetHostView ----------------------------------------------------
|
||||
@ -260,6 +261,8 @@ class TestRenderViewHost
|
||||
// See opener_frame_token() above.
|
||||
absl::optional<blink::FrameToken> opener_frame_token_;
|
||||
|
||||
std::unique_ptr<TestPageBroadcast> page_broadcast_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestRenderViewHost);
|
||||
};
|
||||
|
||||
|
@ -569,6 +569,10 @@ ReportBadMessageCallback GetBadMessageCallback() {
|
||||
return context->GetBadMessageCallback();
|
||||
}
|
||||
|
||||
bool IsInMessageDispatch() {
|
||||
return internal::MessageDispatchContext::current();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
MessageHeaderV2::MessageHeaderV2() = default;
|
||||
|
@ -406,6 +406,11 @@ void ReportBadMessage(const std::string& error);
|
||||
COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
|
||||
ReportBadMessageCallback GetBadMessageCallback();
|
||||
|
||||
// Returns true if called directly within the stack frame of a message dispatch.
|
||||
// Unlike GetBadMessageCallback(), this can be called multiple times.
|
||||
COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
|
||||
bool IsInMessageDispatch();
|
||||
|
||||
} // namespace mojo
|
||||
|
||||
#endif // MOJO_PUBLIC_CPP_BINDINGS_MESSAGE_H_
|
||||
|
11
third_party/blink/public/mojom/frame/frame.mojom
vendored
11
third_party/blink/public/mojom/frame/frame.mojom
vendored
@ -556,10 +556,6 @@ interface LocalFrameHost {
|
||||
// navigation.
|
||||
FrameSizeChanged(gfx.mojom.Size size);
|
||||
|
||||
// Used when a prerendered page is activated. Notifies the browser that the
|
||||
// document in this frame dispatched the prerenderingchange event.
|
||||
DidActivateForPrerendering();
|
||||
|
||||
// Notifies the frame that the document preferred color scheme has changed
|
||||
// due to DevTools media emulation.
|
||||
DidUpdatePreferredColorScheme(PreferredColorScheme preferred_color_scheme);
|
||||
@ -815,13 +811,6 @@ interface LocalFrame {
|
||||
bool had_redirect,
|
||||
network.mojom.SourceLocation? source_location);
|
||||
|
||||
// Sent to a prerendered frame to inform it that it is being activated.
|
||||
// The document in the frame updates `document.prerendering` and dispatches
|
||||
// the prerenderingchange event.
|
||||
// |activation_start| is the time that activation started for use in
|
||||
// PerformanceNavigationTiming.
|
||||
ActivateForPrerendering(mojo_base.mojom.TimeTicks activation_start);
|
||||
|
||||
// Returns a DevToolsAgent interface for this frame, used for
|
||||
// remote debugging. See DevToolsAgent for details.
|
||||
// Returned DevToolsAgent must be associated with navigation control,
|
||||
|
15
third_party/blink/public/mojom/page/page.mojom
vendored
15
third_party/blink/public/mojom/page/page.mojom
vendored
@ -62,8 +62,19 @@ interface PageBroadcast {
|
||||
// Notifies the renderer when audio is started or stopped.
|
||||
AudioStateChanged(bool is_audio_playing);
|
||||
|
||||
// Notifies renderers when a prerendered page is activated.
|
||||
ActivatePrerenderedPage();
|
||||
// Notifies the renderer when a prerendered page is activated. The renderer
|
||||
// is expected to update `document.prerendering` and dispatch the
|
||||
// prerenderingchange event on relevant documents.
|
||||
//
|
||||
// `activation_start` is when the activation navigation started for use in
|
||||
// PerformanceNavigationTiming. It is 0 if this blink::WebViewImpl does not
|
||||
// host the main frame, to avoid sending the data cross-origin.
|
||||
//
|
||||
// The renderer calls the callback once all documents in the
|
||||
// blink::WebViewImpl finished activating.
|
||||
//
|
||||
// TODO(falken): Move this to SetPageLifecycleState.
|
||||
ActivatePrerenderedPage(mojo_base.mojom.TimeTicks activation_start) => ();
|
||||
|
||||
// Notifies renderers when a portal web contents is activated or if a
|
||||
// web contents is adopted as a portal.
|
||||
|
@ -8209,9 +8209,6 @@ void Document::ActivateForPrerendering(base::TimeTicks activation_start) {
|
||||
// Step 8.3.5 "For each steps in doc’s post-prerendering activation steps
|
||||
// list:"
|
||||
RunPostPrerenderingActivationSteps();
|
||||
|
||||
if (LocalFrame* frame = GetFrame())
|
||||
frame->DidActivateForPrerendering();
|
||||
}
|
||||
|
||||
void Document::AddWillDispatchPrerenderingchangeCallback(
|
||||
|
@ -3144,8 +3144,39 @@ void WebViewImpl::UpdateFontRenderingFromRendererPrefs() {
|
||||
#endif // !defined(OS_MAC)
|
||||
}
|
||||
|
||||
void WebViewImpl::ActivatePrerenderedPage() {
|
||||
void WebViewImpl::ActivatePrerenderedPage(
|
||||
base::TimeTicks activation_start,
|
||||
ActivatePrerenderedPageCallback callback) {
|
||||
DCHECK(features::IsPrerender2Enabled());
|
||||
|
||||
// From here all new documents will have prerendering false.
|
||||
GetPage()->SetIsPrerendering(false);
|
||||
|
||||
// Collect local documents. This is because we are about to run the
|
||||
// prerenderchange event and post-prerendering activation steps on each
|
||||
// document, which could mutate the frame tree and make iteration over it
|
||||
// complicated.
|
||||
HeapVector<Member<Document>> documents;
|
||||
for (Frame* frame = GetPage()->MainFrame(); frame;
|
||||
frame = frame->Tree().TraverseNext()) {
|
||||
if (auto* local_frame = DynamicTo<LocalFrame>(frame))
|
||||
documents.push_back(local_frame->GetDocument());
|
||||
}
|
||||
|
||||
// A null `activation_start` is sent to the WebViewImpl that does not host the
|
||||
// main frame, in which case we expect that it does not have any documents
|
||||
// since cross-origin documents are not loaded during prerendering.
|
||||
DCHECK(documents.size() == 0 || !activation_start.is_null());
|
||||
|
||||
// While the spec says to post a task on the networking task source for each
|
||||
// document, we don't post a task here for simplicity. This allows dispatching
|
||||
// the event on all documents without a chance for other IPCs from the browser
|
||||
// to arrive in the intervening time, resulting in an unclear state.
|
||||
for (auto& document : documents) {
|
||||
document->ActivateForPrerendering(activation_start);
|
||||
}
|
||||
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void WebViewImpl::SetInsidePortal(bool inside_portal) {
|
||||
|
@ -279,7 +279,9 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
mojom::blink::PageRestoreParamsPtr page_restore_params,
|
||||
SetPageLifecycleStateCallback callback) override;
|
||||
void AudioStateChanged(bool is_audio_playing) override;
|
||||
void ActivatePrerenderedPage() override;
|
||||
void ActivatePrerenderedPage(
|
||||
base::TimeTicks activation_start,
|
||||
ActivatePrerenderedPageCallback callback) override;
|
||||
void SetInsidePortal(bool is_inside_portal) override;
|
||||
void UpdateWebPreferences(
|
||||
const blink::web_pref::WebPreferences& preferences) override;
|
||||
|
@ -2461,11 +2461,6 @@ bool LocalFrame::SwapIn() {
|
||||
return client->SwapIn(WebFrame::FromCoreFrame(GetProvisionalOwnerFrame()));
|
||||
}
|
||||
|
||||
void LocalFrame::DidActivateForPrerendering() {
|
||||
DCHECK(features::IsPrerender2Enabled());
|
||||
GetLocalFrameHostRemote().DidActivateForPrerendering();
|
||||
}
|
||||
|
||||
void LocalFrame::LoadJavaScriptURL(const KURL& url) {
|
||||
// Protect privileged pages against bookmarklets and other JavaScript
|
||||
// manipulations.
|
||||
|
@ -695,10 +695,6 @@ class CORE_EXPORT LocalFrame final : public Frame,
|
||||
return window_controls_overlay_rect_;
|
||||
}
|
||||
|
||||
// Called after the document in this frame dispatched the prerenderingchange
|
||||
// event.
|
||||
void DidActivateForPrerendering();
|
||||
|
||||
void LoadJavaScriptURL(const KURL& url);
|
||||
|
||||
void SetEvictCachedSessionStorageOnFreezeOrUnload();
|
||||
|
@ -992,22 +992,6 @@ void LocalFrameMojoHandler::MixedContentFound(
|
||||
was_allowed, url_before_redirects, had_redirect, std::move(source));
|
||||
}
|
||||
|
||||
void LocalFrameMojoHandler::ActivateForPrerendering(
|
||||
base::TimeTicks activation_start) {
|
||||
DCHECK(features::IsPrerender2Enabled());
|
||||
|
||||
// https://jeremyroman.github.io/alternate-loading-modes/#prerendering-browsing-context-activate
|
||||
// Step 8.2. "Let inclusiveDescendants be successorBC extended with
|
||||
// successorBC's active document's list of the descendant browsing contexts."
|
||||
// Step 8.3. "For each bc of inclusiveDescendants, queue a global task on the
|
||||
// networking task source, given bc's active window, to perform the following
|
||||
// steps:"
|
||||
frame_->GetTaskRunner(TaskType::kNetworking)
|
||||
->PostTask(FROM_HERE,
|
||||
WTF::Bind(&Document::ActivateForPrerendering,
|
||||
WrapPersistent(GetDocument()), activation_start));
|
||||
}
|
||||
|
||||
void LocalFrameMojoHandler::BindDevToolsAgent(
|
||||
mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host,
|
||||
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver) {
|
||||
|
@ -172,7 +172,6 @@ class LocalFrameMojoHandler
|
||||
const KURL& url_before_redirects,
|
||||
bool had_redirect,
|
||||
network::mojom::blink::SourceLocationPtr source_location) final;
|
||||
void ActivateForPrerendering(base::TimeTicks activation_start) final;
|
||||
void BindDevToolsAgent(
|
||||
mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host,
|
||||
mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver)
|
||||
|
@ -232,8 +232,6 @@ void FakeLocalFrameHost::DidAddMessageToConsole(
|
||||
|
||||
void FakeLocalFrameHost::FrameSizeChanged(const gfx::Size& frame_size) {}
|
||||
|
||||
void FakeLocalFrameHost::DidActivateForPrerendering() {}
|
||||
|
||||
void FakeLocalFrameHost::DidUpdatePreferredColorScheme(
|
||||
blink::mojom::PreferredColorScheme preferred_color_scheme) {}
|
||||
|
||||
|
@ -158,7 +158,6 @@ class FakeLocalFrameHost : public mojom::blink::LocalFrameHost {
|
||||
const WTF::String& source_id,
|
||||
const WTF::String& untrusted_stack_trace) override;
|
||||
void FrameSizeChanged(const gfx::Size& frame_size) override;
|
||||
void DidActivateForPrerendering() override;
|
||||
void DidUpdatePreferredColorScheme(
|
||||
blink::mojom::PreferredColorScheme preferred_color_scheme) override;
|
||||
|
||||
|
Reference in New Issue
Block a user