Commit cc50c0ec authored by Hiroki Nakagawa's avatar Hiroki Nakagawa Committed by Commit Bot

Prerender: Merge mojom::PrerenderHandle into mojom::PrerenderProcessor

For code simplification, this CL merges mojom::PrerenderHandle into
mojom::PrerenerProcessor. These interfaces were very similar: These were
materialized per <link rel=prerender> element, and used for sending
messages from a renderer process to the browser process.

To merge them, this CL...

- assigns unique identifier per LinkPreload instance. This is used for
  canceling or abandoning prerendering from PrerenderProcessorImpl.
- removes PrerenderHandleProxy that implemented mojom::PrerenderHandle.

Bonus: This cleanup will make it easier to reuse the mojom interfaces
for the prerender V2 implementation we are now planning (see the issue).

Change-Id: If731c50408c4e125b3e71a70bef9bbf680eb073f
Bug: 1126305
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2413830Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarRobert Ogden <robertogden@chromium.org>
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810968}
parent d798762c
...@@ -410,18 +410,14 @@ class PrerenderTest : public testing::Test { ...@@ -410,18 +410,14 @@ class PrerenderTest : public testing::Test {
clients_.Add(std::make_unique<DummyPrerenderHandleClient>(), clients_.Add(std::make_unique<DummyPrerenderHandleClient>(),
handle_client.InitWithNewPipeAndPassReceiver()); handle_client.InitWithNewPipeAndPassReceiver());
mojo::PendingRemote<blink::mojom::PrerenderHandle> handle;
// This could delete an existing prerender as a side-effect. // This could delete an existing prerender as a side-effect.
bool added = prerender_link_manager()->OnAddPrerender( base::Optional<int> prerender_id =
prerender_link_manager()->OnStartPrerender(
render_process_id, render_view_id, std::move(attributes), render_process_id, render_view_id, std::move(attributes),
std::move(handle_client), handle.InitWithNewPipeAndPassReceiver()); std::move(handle_client));
// We don't care about retaining the |handle|, so just let it be discarded.
// The PrerenderLinkManager won't care.
// Check if the new prerender request was added and running. // Check if the new prerender request was added and running.
return added && LastPrerenderIsRunning(); return prerender_id && LastPrerenderIsRunning();
} }
// Shorthand to add a simple prerender with a reasonable source. Returns // Shorthand to add a simple prerender with a reasonable source. Returns
...@@ -444,25 +440,25 @@ class PrerenderTest : public testing::Test { ...@@ -444,25 +440,25 @@ class PrerenderTest : public testing::Test {
void AbandonFirstPrerender() { void AbandonFirstPrerender() {
CHECK(!prerender_link_manager()->prerenders_.empty()); CHECK(!prerender_link_manager()->prerenders_.empty());
prerender_link_manager()->OnAbandonPrerender( prerender_link_manager()->OnAbandonPrerender(
prerender_link_manager()->prerenders_.front().get()); prerender_link_manager()->prerenders_.front()->prerender_id);
} }
void AbandonLastPrerender() { void AbandonLastPrerender() {
CHECK(!prerender_link_manager()->prerenders_.empty()); CHECK(!prerender_link_manager()->prerenders_.empty());
prerender_link_manager()->OnAbandonPrerender( prerender_link_manager()->OnAbandonPrerender(
prerender_link_manager()->prerenders_.back().get()); prerender_link_manager()->prerenders_.back()->prerender_id);
} }
void CancelFirstPrerender() { void CancelFirstPrerender() {
CHECK(!prerender_link_manager()->prerenders_.empty()); CHECK(!prerender_link_manager()->prerenders_.empty());
prerender_link_manager()->OnCancelPrerender( prerender_link_manager()->OnCancelPrerender(
prerender_link_manager()->prerenders_.front().get()); prerender_link_manager()->prerenders_.front()->prerender_id);
} }
void CancelLastPrerender() { void CancelLastPrerender() {
CHECK(!prerender_link_manager()->prerenders_.empty()); CHECK(!prerender_link_manager()->prerenders_.empty());
prerender_link_manager()->OnCancelPrerender( prerender_link_manager()->OnCancelPrerender(
prerender_link_manager()->prerenders_.back().get()); prerender_link_manager()->prerenders_.back()->prerender_id);
} }
void DisablePrerender() { void DisablePrerender() {
......
...@@ -39,79 +39,14 @@ using content::SessionStorageNamespace; ...@@ -39,79 +39,14 @@ using content::SessionStorageNamespace;
namespace prerender { namespace prerender {
// Implementation of the interface used to control a requested prerender. namespace {
class PrerenderLinkManager::PrerenderHandleProxy
: public blink::mojom::PrerenderHandle {
public:
PrerenderHandleProxy(
PrerenderLinkManager* prerender_link_manager,
PrerenderLinkManager::LinkPrerender* link_prerender,
mojo::PendingReceiver<blink::mojom::PrerenderHandle> handle)
: prerender_link_manager_(prerender_link_manager),
link_prerender_(link_prerender),
receiver_(this, std::move(handle)) {}
~PrerenderHandleProxy() override = default;
// blink::mojom::PrerenderHandle implementation
void Cancel() override {
prerender_link_manager_->OnCancelPrerender(link_prerender_);
}
void Abandon() override {
prerender_link_manager_->OnAbandonPrerender(link_prerender_);
}
private:
PrerenderLinkManager* prerender_link_manager_;
LinkPrerender* link_prerender_;
mojo::Receiver<blink::mojom::PrerenderHandle> receiver_;
};
// Used to store state about a requested prerender.
class PrerenderLinkManager::LinkPrerender {
public:
LinkPrerender(
int launcher_render_process_id,
int launcher_render_view_id,
blink::mojom::PrerenderAttributesPtr attributes,
mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client,
base::TimeTicks creation_time,
PrerenderContents* deferred_launcher);
~LinkPrerender();
LinkPrerender(const LinkPrerender& other) = delete;
LinkPrerender& operator=(const LinkPrerender& other) = delete;
// Parameters from PrerenderLinkManager::OnAddPrerender():
int launcher_render_process_id;
int launcher_render_view_id;
GURL url;
blink::mojom::PrerenderRelType rel_type;
content::Referrer referrer;
url::Origin initiator_origin;
gfx::Size size;
// Notification interface back to the requestor of this prerender.
mojo::Remote<blink::mojom::PrerenderHandleClient> remote_handle_client;
// Control interface used by the requestor of this prerender. Owned by this
// class to ensure that it gets destroyed at the same time.
std::unique_ptr<PrerenderHandleProxy> handle_proxy;
// The time at which this Prerender was added to PrerenderLinkManager.
base::TimeTicks creation_time;
// If non-null, this link prerender was launched by an unswapped prerender,
// |deferred_launcher|. When |deferred_launcher| is swapped in, the field is
// set to null.
PrerenderContents* deferred_launcher;
// Initially null, |handle| is set once we start this prerender. It is owned int GetNextPrerenderId() {
// by this struct, and must be deleted before destructing this struct. static int next_id = 1;
std::unique_ptr<PrerenderHandle> handle; return next_id++;
}
// True if this prerender has been abandoned by its launcher. } // namespace
bool has_been_abandoned;
};
PrerenderLinkManager::LinkPrerender::LinkPrerender( PrerenderLinkManager::LinkPrerender::LinkPrerender(
int launcher_render_process_id, int launcher_render_process_id,
...@@ -130,7 +65,8 @@ PrerenderLinkManager::LinkPrerender::LinkPrerender( ...@@ -130,7 +65,8 @@ PrerenderLinkManager::LinkPrerender::LinkPrerender(
remote_handle_client(std::move(handle_client)), remote_handle_client(std::move(handle_client)),
creation_time(creation_time), creation_time(creation_time),
deferred_launcher(deferred_launcher), deferred_launcher(deferred_launcher),
has_been_abandoned(false) {} has_been_abandoned(false),
prerender_id(GetNextPrerenderId()) {}
PrerenderLinkManager::LinkPrerender::~LinkPrerender() { PrerenderLinkManager::LinkPrerender::~LinkPrerender() {
DCHECK_EQ(nullptr, handle.get()) DCHECK_EQ(nullptr, handle.get())
...@@ -151,12 +87,11 @@ PrerenderLinkManager::~PrerenderLinkManager() { ...@@ -151,12 +87,11 @@ PrerenderLinkManager::~PrerenderLinkManager() {
} }
} }
bool PrerenderLinkManager::OnAddPrerender( base::Optional<int> PrerenderLinkManager::OnStartPrerender(
int launcher_render_process_id, int launcher_render_process_id,
int launcher_render_view_id, int launcher_render_view_id,
blink::mojom::PrerenderAttributesPtr attributes, blink::mojom::PrerenderAttributesPtr attributes,
mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client, mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client) {
mojo::PendingReceiver<blink::mojom::PrerenderHandle> handle) {
// TODO(crbug.com/722453): Use a dedicated build flag for GuestView. // TODO(crbug.com/722453): Use a dedicated build flag for GuestView.
#if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA) #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_FUCHSIA)
content::RenderViewHost* rvh = content::RenderViewHost::FromID( content::RenderViewHost* rvh = content::RenderViewHost::FromID(
...@@ -166,7 +101,7 @@ bool PrerenderLinkManager::OnAddPrerender( ...@@ -166,7 +101,7 @@ bool PrerenderLinkManager::OnAddPrerender(
// Guests inside <webview> do not support cross-process navigation and so we // Guests inside <webview> do not support cross-process navigation and so we
// do not allow guests to prerender content. // do not allow guests to prerender content.
if (guest_view::GuestViewBase::IsGuest(web_contents)) if (guest_view::GuestViewBase::IsGuest(web_contents))
return false; return base::nullopt;
#endif #endif
// Check if the launcher is itself an unswapped prerender. // Check if the launcher is itself an unswapped prerender.
...@@ -178,7 +113,7 @@ bool PrerenderLinkManager::OnAddPrerender( ...@@ -178,7 +113,7 @@ bool PrerenderLinkManager::OnAddPrerender(
// The launcher is a prerender about to be destroyed asynchronously, but // The launcher is a prerender about to be destroyed asynchronously, but
// its AddLinkRelPrerender message raced with shutdown. Ignore it. // its AddLinkRelPrerender message raced with shutdown. Ignore it.
DCHECK_NE(FINAL_STATUS_USED, prerender_contents->final_status()); DCHECK_NE(FINAL_STATUS_USED, prerender_contents->final_status());
return false; return base::nullopt;
} }
auto prerender = std::make_unique<LinkPrerender>( auto prerender = std::make_unique<LinkPrerender>(
...@@ -186,18 +121,12 @@ bool PrerenderLinkManager::OnAddPrerender( ...@@ -186,18 +121,12 @@ bool PrerenderLinkManager::OnAddPrerender(
std::move(attributes), std::move(handle_client), std::move(attributes), std::move(handle_client),
manager_->GetCurrentTimeTicks(), prerender_contents); manager_->GetCurrentTimeTicks(), prerender_contents);
// Setup implementation of blink::mojom::PrerenderHandle as a proxy to the
// real PrerenderHandle. The first two raw pointers are safe as the proxy is
// owned by |prerender| which is owned by |this|.
prerender->handle_proxy = std::make_unique<PrerenderHandleProxy>(
this, prerender.get(), std::move(handle));
// Observe disconnect of the client and treat as equivalent to explicit // Observe disconnect of the client and treat as equivalent to explicit
// abandonment. Similar to above, the raw pointer to |this| is safe because // abandonment. Similar to above, the raw pointer to |this| is safe because
// |prerender| is owned by |this|. // |prerender| is owned by |this|.
prerender->remote_handle_client.set_disconnect_handler( prerender->remote_handle_client.set_disconnect_handler(
base::BindOnce(&PrerenderLinkManager::OnAbandonPrerender, base::BindOnce(&PrerenderLinkManager::OnAbandonPrerender,
base::Unretained(this), prerender.get())); base::Unretained(this), prerender->prerender_id));
// Stash pointer used only for comparison later. // Stash pointer used only for comparison later.
const LinkPrerender* prerender_ptr = prerender.get(); const LinkPrerender* prerender_ptr = prerender.get();
...@@ -209,15 +138,24 @@ bool PrerenderLinkManager::OnAddPrerender( ...@@ -209,15 +138,24 @@ bool PrerenderLinkManager::OnAddPrerender(
// Check if the prerender we added is still at the end of the list. It // Check if the prerender we added is still at the end of the list. It
// may have been discarded by StartPrerenders(). // may have been discarded by StartPrerenders().
return !prerenders_.empty() && prerenders_.back().get() == prerender_ptr; if (!prerenders_.empty() && prerenders_.back().get() == prerender_ptr)
return prerender_ptr->prerender_id;
return base::nullopt;
} }
void PrerenderLinkManager::OnCancelPrerender(LinkPrerender* prerender) { void PrerenderLinkManager::OnCancelPrerender(int prerender_id) {
LinkPrerender* prerender = FindByPrerenderId(prerender_id);
if (!prerender)
return;
CancelPrerender(prerender); CancelPrerender(prerender);
StartPrerenders(); StartPrerenders();
} }
void PrerenderLinkManager::OnAbandonPrerender(LinkPrerender* prerender) { void PrerenderLinkManager::OnAbandonPrerender(int prerender_id) {
LinkPrerender* prerender = FindByPrerenderId(prerender_id);
if (!prerender)
return;
if (!prerender->handle) { if (!prerender->handle) {
RemovePrerender(prerender); RemovePrerender(prerender);
return; return;
...@@ -368,6 +306,15 @@ PrerenderLinkManager::FindByPrerenderHandle(PrerenderHandle* prerender_handle) { ...@@ -368,6 +306,15 @@ PrerenderLinkManager::FindByPrerenderHandle(PrerenderHandle* prerender_handle) {
return nullptr; return nullptr;
} }
PrerenderLinkManager::LinkPrerender* PrerenderLinkManager::FindByPrerenderId(
int prerender_id) {
for (auto& prerender : prerenders_) {
if (prerender->prerender_id == prerender_id)
return prerender.get();
}
return nullptr;
}
void PrerenderLinkManager::RemovePrerender(LinkPrerender* prerender) { void PrerenderLinkManager::RemovePrerender(LinkPrerender* prerender) {
for (auto it = prerenders_.begin(); it != prerenders_.end(); ++it) { for (auto it = prerenders_.begin(); it != prerenders_.end(); ++it) {
LinkPrerender* current_prerender = it->get(); LinkPrerender* current_prerender = it->get();
...@@ -400,7 +347,8 @@ void PrerenderLinkManager::Shutdown() { ...@@ -400,7 +347,8 @@ void PrerenderLinkManager::Shutdown() {
has_shutdown_ = true; has_shutdown_ = true;
} }
// In practice, this is always called from PrerenderLinkManager::OnAddPrerender. // In practice, this is always called from
// PrerenderLinkManager::OnStartPrerender().
void PrerenderLinkManager::OnPrerenderStart(PrerenderHandle* prerender_handle) { void PrerenderLinkManager::OnPrerenderStart(PrerenderHandle* prerender_handle) {
LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle); LinkPrerender* prerender = FindByPrerenderHandle(prerender_handle);
if (!prerender) if (!prerender)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "components/prerender/browser/prerender_handle.h" #include "components/prerender/browser/prerender_handle.h"
...@@ -36,14 +37,24 @@ class PrerenderLinkManager : public KeyedService, ...@@ -36,14 +37,24 @@ class PrerenderLinkManager : public KeyedService,
explicit PrerenderLinkManager(PrerenderManager* manager); explicit PrerenderLinkManager(PrerenderManager* manager);
~PrerenderLinkManager() override; ~PrerenderLinkManager() override;
// A <link rel=prerender ...> element has been inserted into the document. // Called when a <link rel=prerender ...> element has been inserted into the
// Returns true if a prerender was added. // document. Returns the prerender id that is used for canceling or abandoning
bool OnAddPrerender( // prerendering. Returns base::nullopt if the prerender was not started.
base::Optional<int> OnStartPrerender(
int launcher_render_process_id, int launcher_render_process_id,
int launcher_render_view_id, int launcher_render_view_id,
blink::mojom::PrerenderAttributesPtr attributes, blink::mojom::PrerenderAttributesPtr attributes,
mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client, mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client);
mojo::PendingReceiver<blink::mojom::PrerenderHandle> handle);
// Called when a <link rel=prerender ...> element has been explicitly removed
// from a document.
void OnCancelPrerender(int prerender_id);
// Called when a renderer launching <link rel=prerender ...> has navigated
// away from the launching page, the launching renderer process has crashed,
// or perhaps the renderer process was fast-closed when the last render view
// in it was closed.
void OnAbandonPrerender(int prerender_id);
private: private:
friend class PrerenderBrowserTest; friend class PrerenderBrowserTest;
...@@ -51,19 +62,53 @@ class PrerenderLinkManager : public KeyedService, ...@@ -51,19 +62,53 @@ class PrerenderLinkManager : public KeyedService,
// WebViewTest.NoPrerenderer needs to access the private IsEmpty() method. // WebViewTest.NoPrerenderer needs to access the private IsEmpty() method.
FRIEND_TEST_ALL_PREFIXES(::WebViewTest, NoPrerenderer); FRIEND_TEST_ALL_PREFIXES(::WebViewTest, NoPrerenderer);
class PrerenderHandleProxy;
class LinkPrerender;
class PendingPrerenderManager; class PendingPrerenderManager;
// A <link rel=prerender ...> element has been explicitly removed from a // Used to store state about a requested prerender.
// document. struct LinkPrerender {
void OnCancelPrerender(LinkPrerender* link_prerender); LinkPrerender(
int launcher_render_process_id,
int launcher_render_view_id,
blink::mojom::PrerenderAttributesPtr attributes,
mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client,
base::TimeTicks creation_time,
PrerenderContents* deferred_launcher);
~LinkPrerender();
LinkPrerender(const LinkPrerender& other) = delete;
LinkPrerender& operator=(const LinkPrerender& other) = delete;
// Parameters from PrerenderLinkManager::OnStartPrerender():
const int launcher_render_process_id;
const int launcher_render_view_id;
const GURL url;
const blink::mojom::PrerenderRelType rel_type;
const content::Referrer referrer;
const url::Origin initiator_origin;
const gfx::Size size;
// Notification interface back to the requestor of this prerender.
mojo::Remote<blink::mojom::PrerenderHandleClient> remote_handle_client;
// The time at which this Prerender was added to PrerenderLinkManager.
const base::TimeTicks creation_time;
// If non-null, this link prerender was launched by an unswapped prerender,
// |deferred_launcher|. When |deferred_launcher| is swapped in, the field is
// set to null.
const PrerenderContents* deferred_launcher;
// Initially null, |handle| is set once we start this prerender. It is owned
// by this struct, and must be deleted before destructing this struct.
std::unique_ptr<PrerenderHandle> handle;
// True if this prerender has been abandoned by its launcher.
bool has_been_abandoned;
// A renderer launching <link rel=prerender ...> has navigated away from the // The unique ID of this prerender. Used for canceling or abandoning
// launching page, the launching renderer process has crashed, or perhaps the // prerendering.
// renderer process was fast-closed when the last render view in it was const int prerender_id;
// closed. };
void OnAbandonPrerender(LinkPrerender* link_prerender);
bool IsEmpty() const; bool IsEmpty() const;
...@@ -77,6 +122,7 @@ class PrerenderLinkManager : public KeyedService, ...@@ -77,6 +122,7 @@ class PrerenderLinkManager : public KeyedService,
void StartPrerenders(); void StartPrerenders();
LinkPrerender* FindByPrerenderHandle(PrerenderHandle* prerender_handle); LinkPrerender* FindByPrerenderHandle(PrerenderHandle* prerender_handle);
LinkPrerender* FindByPrerenderId(int prerender_id);
// Removes |prerender| from the the prerender link manager. Deletes the // Removes |prerender| from the the prerender link manager. Deletes the
// PrerenderHandle as needed. // PrerenderHandle as needed.
......
...@@ -36,32 +36,62 @@ void PrerenderProcessorImpl::Create( ...@@ -36,32 +36,62 @@ void PrerenderProcessorImpl::Create(
std::move(receiver)); std::move(receiver));
} }
void PrerenderProcessorImpl::AddPrerender( void PrerenderProcessorImpl::Start(
blink::mojom::PrerenderAttributesPtr attributes, blink::mojom::PrerenderAttributesPtr attributes,
mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client, mojo::PendingRemote<blink::mojom::PrerenderHandleClient> handle_client) {
mojo::PendingReceiver<blink::mojom::PrerenderHandle> handle) {
if (!attributes->initiator_origin.opaque() && if (!attributes->initiator_origin.opaque() &&
!content::ChildProcessSecurityPolicy::GetInstance() !content::ChildProcessSecurityPolicy::GetInstance()
->CanAccessDataForOrigin(render_process_id_, ->CanAccessDataForOrigin(render_process_id_,
attributes->initiator_origin.GetURL())) { attributes->initiator_origin.GetURL())) {
mojo::ReportBadMessage("PMF_INVALID_INITIATOR_ORIGIN"); mojo::ReportBadMessage("PPI_INVALID_INITIATOR_ORIGIN");
return; return;
} }
content::RenderFrameHost* render_frame_host = // Start() must be called only one time.
if (prerender_id_) {
mojo::ReportBadMessage("PPI_START_TWICE");
return;
}
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id_); content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
if (!render_frame_host) if (!render_frame_host)
return; return;
PrerenderLinkManager* link_manager = delegate_->GetPrerenderLinkManager( auto* link_manager = GetPrerenderLinkManager();
render_frame_host->GetProcess()->GetBrowserContext());
if (!link_manager) if (!link_manager)
return; return;
link_manager->OnAddPrerender( DCHECK(!prerender_id_);
prerender_id_ = link_manager->OnStartPrerender(
render_process_id_, render_process_id_,
render_frame_host->GetRenderViewHost()->GetRoutingID(), render_frame_host->GetRenderViewHost()->GetRoutingID(),
std::move(attributes), std::move(handle_client), std::move(handle)); std::move(attributes), std::move(handle_client));
}
void PrerenderProcessorImpl::Cancel() {
if (!prerender_id_)
return;
auto* link_manager = GetPrerenderLinkManager();
if (link_manager)
link_manager->OnCancelPrerender(*prerender_id_);
}
void PrerenderProcessorImpl::Abandon() {
if (!prerender_id_)
return;
auto* link_manager = GetPrerenderLinkManager();
if (link_manager)
link_manager->OnAbandonPrerender(*prerender_id_);
}
PrerenderLinkManager* PrerenderProcessorImpl::GetPrerenderLinkManager() {
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
if (!render_frame_host)
return nullptr;
return delegate_->GetPrerenderLinkManager(
render_frame_host->GetProcess()->GetBrowserContext());
} }
} // namespace prerender } // namespace prerender
...@@ -28,15 +28,22 @@ class PrerenderProcessorImpl : public blink::mojom::PrerenderProcessor { ...@@ -28,15 +28,22 @@ class PrerenderProcessorImpl : public blink::mojom::PrerenderProcessor {
std::unique_ptr<PrerenderProcessorImplDelegate> delegate); std::unique_ptr<PrerenderProcessorImplDelegate> delegate);
// blink::mojom::PrerenderProcessor implementation // blink::mojom::PrerenderProcessor implementation
void AddPrerender( void Start(
blink::mojom::PrerenderAttributesPtr attributes, blink::mojom::PrerenderAttributesPtr attributes,
mojo::PendingRemote<blink::mojom::PrerenderHandleClient> client, mojo::PendingRemote<blink::mojom::PrerenderHandleClient> client) override;
mojo::PendingReceiver<blink::mojom::PrerenderHandle> handle) override; void Cancel() override;
void Abandon() override;
private: private:
int render_process_id_; PrerenderLinkManager* GetPrerenderLinkManager();
int render_frame_id_;
std::unique_ptr<PrerenderProcessorImplDelegate> delegate_; const int render_process_id_;
const int render_frame_id_;
const std::unique_ptr<PrerenderProcessorImplDelegate> delegate_;
// The ID of PrerenderLinkManager::LinkPrerender. Used for canceling or
// abandoning prerendering.
base::Optional<int> prerender_id_;
}; };
} // namespace prerender } // namespace prerender
......
...@@ -9,37 +9,27 @@ import "ui/gfx/geometry/mojom/geometry.mojom"; ...@@ -9,37 +9,27 @@ import "ui/gfx/geometry/mojom/geometry.mojom";
import "url/mojom/origin.mojom"; import "url/mojom/origin.mojom";
import "url/mojom/url.mojom"; import "url/mojom/url.mojom";
// These are messages sent from the browser to the renderer in relation to // This interface is used to notify of events on prerendering from the browser
// running prerenders. // process to a renderer process that requested prerendering. This is created
// per prerender request, for example, when a new <link rel=prerender> element
// is added, when the element's href is changed, etc.
//
// TODO(https://crbug.com/1126305): Rename this interface to
// PrerenderProcessorClient.
interface PrerenderHandleClient { interface PrerenderHandleClient {
// Signals to launcher that a prerender is running. // Notifies that a prerender started.
OnPrerenderStart(); OnPrerenderStart();
// Signals to launcher that a prerender has stopped loading. // Notifies that a prerender has stopped loading.
OnPrerenderStopLoading(); OnPrerenderStopLoading();
// Signals to launcher that a prerender has had it's 'domcontentloaded' event. // Notifies that a prerender has had it's 'domcontentloaded' event.
OnPrerenderDomContentLoaded(); OnPrerenderDomContentLoaded();
// Signals to a launcher that a prerender is no longer running. // Notifies that a prerender is no longer running.
OnPrerenderStop(); OnPrerenderStop();
}; };
// The renderer sends messages to the browser process over this interface. A
// handle to a requested prerender. Dropping a connection to the handle is
// treated equivalently to calling the Abandon method.
interface PrerenderHandle {
// Notifies on removal of a <link rel=prerender> element from the document.
// This method does not trigger an OnPrerenderStop() call.
Cancel();
// A prerender is abandoned when it's navigated away from or suspended in the
// page cache. This is a weaker signal than Cancel(), since the launcher
// hasn't indicated that the prerender isn't wanted, and we may end up using
// it after, for instance, a short redirect chain.
Abandon();
};
enum PrerenderRelType { enum PrerenderRelType {
// https://html.spec.whatwg.org/C/#link-type-prerender // https://html.spec.whatwg.org/C/#link-type-prerender
kPrerender, kPrerender,
...@@ -56,16 +46,31 @@ struct PrerenderAttributes { ...@@ -56,16 +46,31 @@ struct PrerenderAttributes {
gfx.mojom.Size view_size; gfx.mojom.Size view_size;
}; };
// The renderer sends messages to the browser process over this interface. Used // This interface is used to request prerendering from a renderer process to the
// by a renderer loading a web page to process prerender / prefetch requests, // browser process. This is created per prerender request, for example, when a
// that are generally in the form of <link rel> tags that the web page author // new <link rel=prerender> element is added, when the element's href is
// provided as hints. // changed, etc.
interface PrerenderProcessor { interface PrerenderProcessor {
// Called to add a prerender request to the queue for processing. The // Requests the browesr process to start prerendering with
// |prerender_handle_client| will be notified as the prerendering makes // |prerender_attribute|. |prerender_handle_client| will be notified as the
// progress, and |prerender_handle| provides the caller with the ability to // prerendering makes progress. This must be called only one time before any
// further control the prerender. // other functions.
AddPrerender(PrerenderAttributes prerender_attribute, Start(PrerenderAttributes prerender_attribute,
pending_remote<PrerenderHandleClient> prerender_handle_client, pending_remote<PrerenderHandleClient> prerender_handle_client);
pending_receiver<PrerenderHandle> prerender_handle);
// Cancels the ongoing prerendering. This is supposed to be called when the
// <link rel=prerender> element is removed, the element's href is changed,
// etc. This must be called after Start(). This does not trigger
// OnPrerenderStop() on PrerenderHandleClient.
Cancel();
// Abandons the ongoing prerendering. This is supposed to be called when the
// page navigates away or gets suspended. This is a weaker signal than
// Cancel(), since the requester hasn't indicated that the prerender isn't
// wanted, and we may end up using it after, for example, a short redirect
// chain. This must be called after Start().
//
// TODO(https://crbug.com/1130360): The actual behavior doesn't match this
// comment due to the issue. Fix the behavior or update this comment.
Abandon();
}; };
...@@ -66,22 +66,20 @@ PrerenderHandle* PrerenderHandle::Create( ...@@ -66,22 +66,20 @@ PrerenderHandle* PrerenderHandle::Create(
attributes->view_size = attributes->view_size =
gfx::Size(document.GetFrame()->GetMainFrameViewportSize()); gfx::Size(document.GetFrame()->GetMainFrameViewportSize());
mojo::Remote<mojom::blink::PrerenderProcessor> prerender_processor; HeapMojoRemote<mojom::blink::PrerenderProcessor> prerender_processor(context);
context->GetBrowserInterfaceBroker().GetInterface( context->GetBrowserInterfaceBroker().GetInterface(
prerender_processor.BindNewPipeAndPassReceiver()); prerender_processor.BindNewPipeAndPassReceiver(
context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
mojo::PendingRemote<mojom::blink::PrerenderHandleClient> mojo::PendingRemote<mojom::blink::PrerenderHandleClient>
prerender_handle_client; prerender_handle_client;
auto receiver = prerender_handle_client.InitWithNewPipeAndPassReceiver(); auto receiver = prerender_handle_client.InitWithNewPipeAndPassReceiver();
HeapMojoRemote<mojom::blink::PrerenderHandle> remote_handle(context); prerender_processor->Start(std::move(attributes),
prerender_processor->AddPrerender( std::move(prerender_handle_client));
std::move(attributes), std::move(prerender_handle_client),
remote_handle.BindNewPipeAndPassReceiver(
context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
return MakeGarbageCollected<PrerenderHandle>(PassKey(), context, client, url, return MakeGarbageCollected<PrerenderHandle>(PassKey(), context, client, url,
std::move(remote_handle), std::move(prerender_processor),
std::move(receiver)); std::move(receiver));
} }
...@@ -90,12 +88,12 @@ PrerenderHandle::PrerenderHandle( ...@@ -90,12 +88,12 @@ PrerenderHandle::PrerenderHandle(
ExecutionContext* context, ExecutionContext* context,
PrerenderClient* client, PrerenderClient* client,
const KURL& url, const KURL& url,
HeapMojoRemote<mojom::blink::PrerenderHandle> remote_handle, HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor,
mojo::PendingReceiver<mojom::blink::PrerenderHandleClient> receiver) mojo::PendingReceiver<mojom::blink::PrerenderHandleClient> receiver)
: ExecutionContextLifecycleObserver(context), : ExecutionContextLifecycleObserver(context),
url_(url), url_(url),
client_(client), client_(client),
remote_handle_(std::move(remote_handle)), remote_processor_(std::move(remote_processor)),
receiver_(this, context) { receiver_(this, context) {
receiver_.Bind(std::move(receiver), receiver_.Bind(std::move(receiver),
context->GetTaskRunner(TaskType::kMiscPlatformAPI)); context->GetTaskRunner(TaskType::kMiscPlatformAPI));
...@@ -104,8 +102,11 @@ PrerenderHandle::PrerenderHandle( ...@@ -104,8 +102,11 @@ PrerenderHandle::PrerenderHandle(
PrerenderHandle::~PrerenderHandle() = default; PrerenderHandle::~PrerenderHandle() = default;
void PrerenderHandle::Dispose() { void PrerenderHandle::Dispose() {
if (remote_handle_.is_bound() && !GetExecutionContext()->IsContextDestroyed()) // TODO(https://crbug.com/1130360): This condition is never satisfied and
remote_handle_->Abandon(); // Abandon() is not called. See the issue for details. We should fix this.
if (remote_processor_.is_bound() &&
!GetExecutionContext()->IsContextDestroyed())
remote_processor_->Abandon();
Detach(); Detach();
} }
...@@ -114,8 +115,8 @@ void PrerenderHandle::Cancel() { ...@@ -114,8 +115,8 @@ void PrerenderHandle::Cancel() {
// case, the LinkLoader cancels the PrerenderHandle as the Document is // case, the LinkLoader cancels the PrerenderHandle as the Document is
// destroyed, even through the ExecutionContextLifecycleObserver has already // destroyed, even through the ExecutionContextLifecycleObserver has already
// abandoned it. // abandoned it.
if (remote_handle_.is_bound()) if (remote_processor_.is_bound())
remote_handle_->Cancel(); remote_processor_->Cancel();
Detach(); Detach();
} }
...@@ -153,13 +154,13 @@ void PrerenderHandle::OnPrerenderStop() { ...@@ -153,13 +154,13 @@ void PrerenderHandle::OnPrerenderStop() {
void PrerenderHandle::Trace(Visitor* visitor) const { void PrerenderHandle::Trace(Visitor* visitor) const {
visitor->Trace(client_); visitor->Trace(client_);
visitor->Trace(remote_handle_); visitor->Trace(remote_processor_);
visitor->Trace(receiver_); visitor->Trace(receiver_);
ExecutionContextLifecycleObserver::Trace(visitor); ExecutionContextLifecycleObserver::Trace(visitor);
} }
void PrerenderHandle::Detach() { void PrerenderHandle::Detach() {
remote_handle_.reset(); remote_processor_.reset();
receiver_.reset(); receiver_.reset();
} }
......
...@@ -64,7 +64,7 @@ class PrerenderHandle final : public GarbageCollected<PrerenderHandle>, ...@@ -64,7 +64,7 @@ class PrerenderHandle final : public GarbageCollected<PrerenderHandle>,
ExecutionContext*, ExecutionContext*,
PrerenderClient*, PrerenderClient*,
const KURL&, const KURL&,
HeapMojoRemote<mojom::blink::PrerenderHandle>, HeapMojoRemote<mojom::blink::PrerenderProcessor>,
mojo::PendingReceiver<mojom::blink::PrerenderHandleClient>); mojo::PendingReceiver<mojom::blink::PrerenderHandleClient>);
~PrerenderHandle() override; ~PrerenderHandle() override;
void Dispose(); void Dispose();
...@@ -88,7 +88,7 @@ class PrerenderHandle final : public GarbageCollected<PrerenderHandle>, ...@@ -88,7 +88,7 @@ class PrerenderHandle final : public GarbageCollected<PrerenderHandle>,
KURL url_; KURL url_;
WeakMember<PrerenderClient> client_; WeakMember<PrerenderClient> client_;
HeapMojoRemote<mojom::blink::PrerenderHandle> remote_handle_; HeapMojoRemote<mojom::blink::PrerenderProcessor> remote_processor_;
HeapMojoReceiver<mojom::blink::PrerenderHandleClient, PrerenderHandle> HeapMojoReceiver<mojom::blink::PrerenderHandleClient, PrerenderHandle>
receiver_; receiver_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment