Commit 2a47c1c9 authored by Yury Semikhatsky's avatar Yury Semikhatsky Committed by Commit Bot

DevTools: allow auto-attaching to page targets

Target.setAutoAttach on the top level Target handler now allows
attaching to all new pages. Top level TargetHandler will attach
to each main frame as soon as it is created (right after sending
targetCreated event). All subsequent navigations will be throttled
until Runtime.runIfWaitingForDebugger is received.

Experimental parameter 'windowOpen' is removed in favour of the
new more generic functionality.

Bug: 1051687
Change-Id: Ia9b58133b97999383cd44016f8d3041f71b5d3d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2042302
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Auto-Submit: Yury Semikhatsky <yurys@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741363}
parent bff00c7a
...@@ -190,14 +190,23 @@ void OnSignedExchangeCertificateRequestCompleted( ...@@ -190,14 +190,23 @@ void OnSignedExchangeCertificateRequestCompleted(
protocol::Network::ResourceTypeEnum::Other, status); protocol::Network::ResourceTypeEnum::Other, status);
} }
void CreateThrottlesForAgentHost(
DevToolsAgentHostImpl* agent_host,
NavigationHandle* navigation_handle,
std::vector<std::unique_ptr<NavigationThrottle>>* result) {
for (auto* target_handler :
protocol::TargetHandler::ForAgentHost(agent_host)) {
std::unique_ptr<NavigationThrottle> throttle =
target_handler->CreateThrottleForNavigation(navigation_handle);
if (throttle)
result->push_back(std::move(throttle));
}
}
std::vector<std::unique_ptr<NavigationThrottle>> CreateNavigationThrottles( std::vector<std::unique_ptr<NavigationThrottle>> CreateNavigationThrottles(
NavigationHandle* navigation_handle) { NavigationHandle* navigation_handle) {
std::vector<std::unique_ptr<NavigationThrottle>> result;
FrameTreeNode* frame_tree_node = FrameTreeNode* frame_tree_node =
NavigationRequest::From(navigation_handle)->frame_tree_node(); NavigationRequest::From(navigation_handle)->frame_tree_node();
DevToolsAgentHostImpl* agent_host =
RenderFrameDevToolsAgentHost::GetFor(frame_tree_node);
FrameTreeNode* parent = frame_tree_node->parent(); FrameTreeNode* parent = frame_tree_node->parent();
if (!parent) { if (!parent) {
if (WebContentsImpl::FromFrameTreeNode(frame_tree_node)->IsPortal() && if (WebContentsImpl::FromFrameTreeNode(frame_tree_node)->IsPortal() &&
...@@ -207,22 +216,19 @@ std::vector<std::unique_ptr<NavigationThrottle>> CreateNavigationThrottles( ...@@ -207,22 +216,19 @@ std::vector<std::unique_ptr<NavigationThrottle>> CreateNavigationThrottles(
->GetOuterWebContents() ->GetOuterWebContents()
->GetFrameTree() ->GetFrameTree()
->root(); ->root();
} else {
parent = frame_tree_node->original_opener();
} }
} }
if (!parent)
return result;
agent_host = RenderFrameDevToolsAgentHost::GetFor(parent); std::vector<std::unique_ptr<NavigationThrottle>> result;
if (agent_host) { if (parent) {
for (auto* target_handler : DevToolsAgentHostImpl* agent_host =
protocol::TargetHandler::ForAgentHost(agent_host)) { RenderFrameDevToolsAgentHost::GetFor(parent);
std::unique_ptr<NavigationThrottle> throttle = if (agent_host)
target_handler->CreateThrottleForNavigation(navigation_handle); CreateThrottlesForAgentHost(agent_host, navigation_handle, &result);
if (throttle) } else {
result.push_back(std::move(throttle)); for (auto* browser_agent_host : BrowserDevToolsAgentHost::Instances())
} CreateThrottlesForAgentHost(browser_agent_host, navigation_handle,
&result);
} }
return result; return result;
......
...@@ -92,6 +92,10 @@ void DevToolsSession::SetRuntimeResumeCallback( ...@@ -92,6 +92,10 @@ void DevToolsSession::SetRuntimeResumeCallback(
runtime_resume_ = std::move(runtime_resume); runtime_resume_ = std::move(runtime_resume);
} }
bool DevToolsSession::IsWaitingForDebuggerOnStart() const {
return !runtime_resume_.is_null();
}
void DevToolsSession::Dispose() { void DevToolsSession::Dispose() {
dispatcher_.reset(); dispatcher_.reset();
for (auto& pair : handlers_) for (auto& pair : handlers_)
......
...@@ -44,6 +44,7 @@ class DevToolsSession : public protocol::FrontendChannel, ...@@ -44,6 +44,7 @@ class DevToolsSession : public protocol::FrontendChannel,
void SetAgentHost(DevToolsAgentHostImpl* agent_host); void SetAgentHost(DevToolsAgentHostImpl* agent_host);
void SetRuntimeResumeCallback(base::OnceClosure runtime_resume); void SetRuntimeResumeCallback(base::OnceClosure runtime_resume);
bool IsWaitingForDebuggerOnStart() const;
void Dispose(); void Dispose();
// content::DevToolsAgentHostClientChannel implementation. // content::DevToolsAgentHostClientChannel implementation.
......
...@@ -119,11 +119,9 @@ base::flat_set<GURL> GetFrameUrls(RenderFrameHostImpl* render_frame_host) { ...@@ -119,11 +119,9 @@ base::flat_set<GURL> GetFrameUrls(RenderFrameHostImpl* render_frame_host) {
} // namespace } // namespace
TargetAutoAttacher::TargetAutoAttacher( TargetAutoAttacher::TargetAutoAttacher(
AttachCallback attach_callback, Delegate* delegate,
DetachCallback detach_callback,
DevToolsRendererChannel* renderer_channel) DevToolsRendererChannel* renderer_channel)
: attach_callback_(attach_callback), : delegate_(delegate),
detach_callback_(detach_callback),
renderer_channel_(renderer_channel), renderer_channel_(renderer_channel),
render_frame_host_(nullptr), render_frame_host_(nullptr),
auto_attach_(false), auto_attach_(false),
...@@ -206,6 +204,13 @@ bool TargetAutoAttacher::ShouldThrottleFramesNavigation() { ...@@ -206,6 +204,13 @@ bool TargetAutoAttacher::ShouldThrottleFramesNavigation() {
return auto_attach_; return auto_attach_;
} }
void TargetAutoAttacher::AttachToAgentHost(DevToolsAgentHost* host) {
scoped_refptr<DevToolsAgentHost> agent_host(host);
DCHECK(auto_attached_hosts_.find(agent_host) == auto_attached_hosts_.end());
delegate_->AutoAttach(agent_host.get(), wait_for_debugger_on_start_);
auto_attached_hosts_.insert(agent_host);
}
DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame( DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame(
NavigationRequest* navigation_request) { NavigationRequest* navigation_request) {
if (!ShouldThrottleFramesNavigation()) if (!ShouldThrottleFramesNavigation())
...@@ -223,20 +228,6 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame( ...@@ -223,20 +228,6 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame(
scoped_refptr<DevToolsAgentHost> agent_host = scoped_refptr<DevToolsAgentHost> agent_host =
RenderFrameDevToolsAgentHost::FindForDangling(frame_tree_node); RenderFrameDevToolsAgentHost::FindForDangling(frame_tree_node);
// Process the window.open auto-attaches for new targets.
if (frame_tree_node->original_opener()) {
if (!agent_host) {
agent_host =
RenderFrameDevToolsAgentHost::CreateForCrossProcessNavigation(
navigation_request);
}
if (auto_attached_hosts_.find(agent_host) != auto_attached_hosts_.end())
return nullptr;
attach_callback_.Run(agent_host.get(), wait_for_debugger_on_start_);
auto_attached_hosts_.insert(agent_host);
return wait_for_debugger_on_start_ ? agent_host.get() : nullptr;
}
bool old_cross_process = !!agent_host; bool old_cross_process = !!agent_host;
bool is_portal_main_frame = bool is_portal_main_frame =
frame_tree_node->IsMainFrame() && frame_tree_node->IsMainFrame() &&
...@@ -251,8 +242,7 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame( ...@@ -251,8 +242,7 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame(
if (new_cross_process) { if (new_cross_process) {
agent_host = RenderFrameDevToolsAgentHost::CreateForCrossProcessNavigation( agent_host = RenderFrameDevToolsAgentHost::CreateForCrossProcessNavigation(
navigation_request); navigation_request);
attach_callback_.Run(agent_host.get(), wait_for_debugger_on_start_); AttachToAgentHost(agent_host.get());
auto_attached_hosts_.insert(agent_host);
return wait_for_debugger_on_start_ ? agent_host.get() : nullptr; return wait_for_debugger_on_start_ ? agent_host.get() : nullptr;
} }
...@@ -263,7 +253,7 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame( ...@@ -263,7 +253,7 @@ DevToolsAgentHost* TargetAutoAttacher::AutoAttachToFrame(
if (it == auto_attached_hosts_.end()) if (it == auto_attached_hosts_.end())
return nullptr; return nullptr;
auto_attached_hosts_.erase(it); auto_attached_hosts_.erase(it);
detach_callback_.Run(agent_host.get()); delegate_->AutoDetach(agent_host.get());
return nullptr; return nullptr;
} }
...@@ -291,12 +281,12 @@ void TargetAutoAttacher::ReattachTargetsOfType(const Hosts& new_hosts, ...@@ -291,12 +281,12 @@ void TargetAutoAttacher::ReattachTargetsOfType(const Hosts& new_hosts,
for (auto& host : old_hosts) { for (auto& host : old_hosts) {
if (host->GetType() == type && new_hosts.find(host) == new_hosts.end()) { if (host->GetType() == type && new_hosts.find(host) == new_hosts.end()) {
auto_attached_hosts_.erase(host); auto_attached_hosts_.erase(host);
detach_callback_.Run(host.get()); delegate_->AutoDetach(host.get());
} }
} }
for (auto& host : new_hosts) { for (auto& host : new_hosts) {
if (old_hosts.find(host) == old_hosts.end()) { if (old_hosts.find(host) == old_hosts.end()) {
attach_callback_.Run(host.get(), waiting_for_debugger); delegate_->AutoAttach(host.get(), waiting_for_debugger);
auto_attached_hosts_.insert(host); auto_attached_hosts_.insert(host);
} }
} }
...@@ -371,7 +361,7 @@ void TargetAutoAttacher::WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) { ...@@ -371,7 +361,7 @@ void TargetAutoAttacher::WorkerDestroyed(ServiceWorkerDevToolsAgentHost* host) {
void TargetAutoAttacher::ChildWorkerCreated(DevToolsAgentHostImpl* agent_host, void TargetAutoAttacher::ChildWorkerCreated(DevToolsAgentHostImpl* agent_host,
bool waiting_for_debugger) { bool waiting_for_debugger) {
attach_callback_.Run(agent_host, waiting_for_debugger); delegate_->AutoAttach(agent_host, waiting_for_debugger);
auto_attached_hosts_.insert(scoped_refptr<DevToolsAgentHost>(agent_host)); auto_attached_hosts_.insert(scoped_refptr<DevToolsAgentHost>(agent_host));
} }
......
...@@ -20,13 +20,17 @@ namespace protocol { ...@@ -20,13 +20,17 @@ namespace protocol {
class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer { class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer {
public: public:
// Second parameter is |waiting_for_debugger|, returns whether it succeeded. class Delegate {
using AttachCallback = public:
base::RepeatingCallback<void(DevToolsAgentHost*, bool)>; virtual void AutoAttach(DevToolsAgentHost* host,
using DetachCallback = base::RepeatingCallback<void(DevToolsAgentHost*)>; bool waiting_for_debugger) = 0;
virtual void AutoDetach(DevToolsAgentHost* host) = 0;
protected:
virtual ~Delegate() = default;
};
TargetAutoAttacher(AttachCallback attach_callback, TargetAutoAttacher(Delegate* delegate,
DetachCallback detach_callback,
DevToolsRendererChannel* renderer_channel); DevToolsRendererChannel* renderer_channel);
~TargetAutoAttacher() override; ~TargetAutoAttacher() override;
...@@ -40,6 +44,7 @@ class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer { ...@@ -40,6 +44,7 @@ class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer {
void AgentHostClosed(DevToolsAgentHost* host); void AgentHostClosed(DevToolsAgentHost* host);
bool ShouldThrottleFramesNavigation(); bool ShouldThrottleFramesNavigation();
void AttachToAgentHost(DevToolsAgentHost* host);
DevToolsAgentHost* AutoAttachToFrame(NavigationRequest* navigation_request); DevToolsAgentHost* AutoAttachToFrame(NavigationRequest* navigation_request);
void ChildWorkerCreated(DevToolsAgentHostImpl* agent_host, void ChildWorkerCreated(DevToolsAgentHostImpl* agent_host,
bool waiting_for_debugger); bool waiting_for_debugger);
...@@ -61,8 +66,7 @@ class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer { ...@@ -61,8 +66,7 @@ class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer {
void UpdateFrames(); void UpdateFrames();
AttachCallback attach_callback_; Delegate* delegate_;
DetachCallback detach_callback_;
DevToolsRendererChannel* renderer_channel_; DevToolsRendererChannel* renderer_channel_;
RenderFrameHostImpl* render_frame_host_; RenderFrameHostImpl* render_frame_host_;
......
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
#include "content/browser/devtools/browser_devtools_agent_host.h" #include "content/browser/devtools/browser_devtools_agent_host.h"
#include "content/browser/devtools/devtools_agent_host_impl.h" #include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/devtools_manager.h" #include "content/browser/devtools/devtools_manager.h"
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/frame_host/navigation_request.h" #include "content/browser/frame_host/navigation_request.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/devtools_agent_host_client.h" #include "content/public/browser/devtools_agent_host_client.h"
#include "content/public/browser/navigation_throttle.h" #include "content/public/browser/navigation_throttle.h"
...@@ -258,16 +260,35 @@ class TargetHandler::Throttle : public content::NavigationThrottle { ...@@ -258,16 +260,35 @@ class TargetHandler::Throttle : public content::NavigationThrottle {
NavigationThrottle::ThrottleCheckResult WillFailRequest() override; NavigationThrottle::ThrottleCheckResult WillFailRequest() override;
const char* GetNameForLogging() override; const char* GetNameForLogging() override;
protected:
void SetThrottledAgentHost(DevToolsAgentHost* agent_host);
private: private:
NavigationThrottle::ThrottleCheckResult MaybeAttach(); virtual void ComputeThrottledAgentHost();
void CleanupPointers(); void CleanupPointers();
base::WeakPtr<protocol::TargetHandler> target_handler_; base::WeakPtr<protocol::TargetHandler> target_handler_;
scoped_refptr<DevToolsAgentHost> agent_host_; scoped_refptr<DevToolsAgentHost> agent_host_;
bool is_deferring_ = false;
DISALLOW_COPY_AND_ASSIGN(Throttle); DISALLOW_COPY_AND_ASSIGN(Throttle);
}; };
class TargetHandler::MainFrameThrottle : public TargetHandler::Throttle {
public:
MainFrameThrottle(base::WeakPtr<protocol::TargetHandler> target_handler,
content::NavigationHandle* navigation_handle,
DevToolsAgentHost* throttled_agent_host)
: Throttle(target_handler, navigation_handle) {
SetThrottledAgentHost(throttled_agent_host);
}
~MainFrameThrottle() override = default;
private:
// For top frames agent host is always set in the constructor.
void ComputeThrottledAgentHost() override {}
};
class TargetHandler::Session : public DevToolsAgentHostClient { class TargetHandler::Session : public DevToolsAgentHostClient {
public: public:
static std::string Attach(TargetHandler* handler, static std::string Attach(TargetHandler* handler,
...@@ -288,9 +309,10 @@ class TargetHandler::Session : public DevToolsAgentHostClient { ...@@ -288,9 +309,10 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
DevToolsSession* devtools_session = DevToolsSession* devtools_session =
handler->root_session_->AttachChildSession(id, agent_host_impl, handler->root_session_->AttachChildSession(id, agent_host_impl,
session); session);
if (devtools_session) { if (waiting_for_debugger && devtools_session) {
devtools_session->SetRuntimeResumeCallback(base::BindOnce( devtools_session->SetRuntimeResumeCallback(base::BindOnce(
&Session::ResumeIfThrottled, base::Unretained(session))); &Session::ResumeIfThrottled, base::Unretained(session)));
session->devtools_session_ = devtools_session;
} }
} else { } else {
agent_host_impl->AttachClient(session); agent_host_impl->AttachClient(session);
...@@ -317,10 +339,16 @@ class TargetHandler::Session : public DevToolsAgentHostClient { ...@@ -317,10 +339,16 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
else else
agent_host_->DetachClient(this); agent_host_->DetachClient(this);
handler_->auto_attached_sessions_.erase(agent_host_.get()); handler_->auto_attached_sessions_.erase(agent_host_.get());
devtools_session_ = nullptr;
agent_host_ = nullptr; agent_host_ = nullptr;
handler_->attached_sessions_.erase(id_); handler_->attached_sessions_.erase(id_);
} }
bool IsWaitingForDebuggerOnStart() const {
return devtools_session_ &&
devtools_session_->IsWaitingForDebuggerOnStart();
}
void SetThrottle(Throttle* throttle) { throttle_ = throttle; } void SetThrottle(Throttle* throttle) { throttle_ = throttle; }
void ResumeIfThrottled() { void ResumeIfThrottled() {
...@@ -401,6 +429,7 @@ class TargetHandler::Session : public DevToolsAgentHostClient { ...@@ -401,6 +429,7 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
scoped_refptr<DevToolsAgentHost> agent_host_; scoped_refptr<DevToolsAgentHost> agent_host_;
std::string id_; std::string id_;
bool flatten_protocol_; bool flatten_protocol_;
DevToolsSession* devtools_session_ = nullptr;
Throttle* throttle_ = nullptr; Throttle* throttle_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(Session); DISALLOW_COPY_AND_ASSIGN(Session);
...@@ -432,24 +461,33 @@ void TargetHandler::Throttle::CleanupPointers() { ...@@ -432,24 +461,33 @@ void TargetHandler::Throttle::CleanupPointers() {
NavigationThrottle::ThrottleCheckResult NavigationThrottle::ThrottleCheckResult
TargetHandler::Throttle::WillProcessResponse() { TargetHandler::Throttle::WillProcessResponse() {
return MaybeAttach(); ComputeThrottledAgentHost();
is_deferring_ = !!agent_host_;
return is_deferring_ ? DEFER : PROCEED;
} }
NavigationThrottle::ThrottleCheckResult NavigationThrottle::ThrottleCheckResult
TargetHandler::Throttle::WillFailRequest() { TargetHandler::Throttle::WillFailRequest() {
return MaybeAttach(); ComputeThrottledAgentHost();
is_deferring_ = !!agent_host_;
return is_deferring_ ? DEFER : PROCEED;
} }
NavigationThrottle::ThrottleCheckResult TargetHandler::Throttle::MaybeAttach() { void TargetHandler::Throttle::SetThrottledAgentHost(
if (!target_handler_) DevToolsAgentHost* agent_host) {
return PROCEED; agent_host_ = agent_host;
agent_host_ = target_handler_->auto_attacher_.AutoAttachToFrame( if (agent_host_) {
NavigationRequest::From(navigation_handle()));
if (!agent_host_.get())
return PROCEED;
target_handler_->auto_attached_sessions_[agent_host_.get()]->SetThrottle( target_handler_->auto_attached_sessions_[agent_host_.get()]->SetThrottle(
this); this);
return DEFER; }
}
void TargetHandler::Throttle::ComputeThrottledAgentHost() {
if (!target_handler_)
return;
NavigationRequest* request = NavigationRequest::From(navigation_handle());
SetThrottledAgentHost(
target_handler_->auto_attacher_.AutoAttachToFrame(request));
} }
const char* TargetHandler::Throttle::GetNameForLogging() { const char* TargetHandler::Throttle::GetNameForLogging() {
...@@ -458,10 +496,10 @@ const char* TargetHandler::Throttle::GetNameForLogging() { ...@@ -458,10 +496,10 @@ const char* TargetHandler::Throttle::GetNameForLogging() {
void TargetHandler::Throttle::Clear() { void TargetHandler::Throttle::Clear() {
CleanupPointers(); CleanupPointers();
if (agent_host_) {
agent_host_ = nullptr; agent_host_ = nullptr;
if (is_deferring_)
Resume(); Resume();
} is_deferring_ = false;
} }
TargetHandler::TargetHandler(AccessMode access_mode, TargetHandler::TargetHandler(AccessMode access_mode,
...@@ -469,11 +507,7 @@ TargetHandler::TargetHandler(AccessMode access_mode, ...@@ -469,11 +507,7 @@ TargetHandler::TargetHandler(AccessMode access_mode,
DevToolsRendererChannel* renderer_channel, DevToolsRendererChannel* renderer_channel,
DevToolsSession* root_session) DevToolsSession* root_session)
: DevToolsDomainHandler(Target::Metainfo::domainName), : DevToolsDomainHandler(Target::Metainfo::domainName),
auto_attacher_(base::BindRepeating(&TargetHandler::AutoAttach, auto_attacher_(this, renderer_channel),
base::Unretained(this)),
base::BindRepeating(&TargetHandler::AutoDetach,
base::Unretained(this)),
renderer_channel),
discover_(false), discover_(false),
access_mode_(access_mode), access_mode_(access_mode),
owner_target_id_(owner_target_id), owner_target_id_(owner_target_id),
...@@ -499,7 +533,7 @@ void TargetHandler::SetRenderer(int process_host_id, ...@@ -499,7 +533,7 @@ void TargetHandler::SetRenderer(int process_host_id,
} }
Response TargetHandler::Disable() { Response TargetHandler::Disable() {
SetAutoAttachInternal(false, false, false, false, base::DoNothing()); SetAutoAttachInternal(false, false, false, base::DoNothing());
SetDiscoverTargets(false); SetDiscoverTargets(false);
auto_attached_sessions_.clear(); auto_attached_sessions_.clear();
attached_sessions_.clear(); attached_sessions_.clear();
...@@ -530,11 +564,25 @@ std::unique_ptr<NavigationThrottle> TargetHandler::CreateThrottleForNavigation( ...@@ -530,11 +564,25 @@ std::unique_ptr<NavigationThrottle> TargetHandler::CreateThrottleForNavigation(
NavigationHandle* navigation_handle) { NavigationHandle* navigation_handle) {
if (!auto_attacher_.ShouldThrottleFramesNavigation()) if (!auto_attacher_.ShouldThrottleFramesNavigation())
return nullptr; return nullptr;
if (access_mode_ == AccessMode::kBrowser) {
FrameTreeNode* frame_tree_node = FrameTreeNode* frame_tree_node =
NavigationRequest::From(navigation_handle)->frame_tree_node(); NavigationRequest::From(navigation_handle)->frame_tree_node();
bool is_window_open = frame_tree_node->original_opener(); // Top-level target handler is expected to create throttles only for new
if (is_window_open && !attach_to_window_open_) // pages.
DCHECK(!frame_tree_node->parent());
DevToolsAgentHost* host =
RenderFrameDevToolsAgentHost::GetFor(frame_tree_node);
// For new pages create Throttle only if the session is still paused.
if (!host)
return nullptr;
auto it = auto_attached_sessions_.find(host);
if (it == auto_attached_sessions_.end())
return nullptr;
if (!it->second->IsWaitingForDebuggerOnStart())
return nullptr; return nullptr;
return std::make_unique<MainFrameThrottle>(weak_factory_.GetWeakPtr(),
navigation_handle, host);
}
return std::make_unique<Throttle>(weak_factory_.GetWeakPtr(), return std::make_unique<Throttle>(weak_factory_.GetWeakPtr(),
navigation_handle); navigation_handle);
} }
...@@ -553,14 +601,27 @@ void TargetHandler::ClearThrottles() { ...@@ -553,14 +601,27 @@ void TargetHandler::ClearThrottles() {
void TargetHandler::SetAutoAttachInternal(bool auto_attach, void TargetHandler::SetAutoAttachInternal(bool auto_attach,
bool wait_for_debugger_on_start, bool wait_for_debugger_on_start,
bool flatten, bool flatten,
bool window_open,
base::OnceClosure callback) { base::OnceClosure callback) {
flatten_auto_attach_ = flatten; flatten_auto_attach_ = flatten;
attach_to_window_open_ = window_open;
auto_attacher_.SetAutoAttach(auto_attach, wait_for_debugger_on_start, auto_attacher_.SetAutoAttach(auto_attach, wait_for_debugger_on_start,
std::move(callback)); std::move(callback));
if (!auto_attacher_.ShouldThrottleFramesNavigation()) if (!auto_attacher_.ShouldThrottleFramesNavigation())
ClearThrottles(); ClearThrottles();
UpdateAgentHostObserver();
}
void TargetHandler::UpdateAgentHostObserver() {
bool should_observe =
discover_ || (access_mode_ == AccessMode::kBrowser &&
auto_attacher_.ShouldThrottleFramesNavigation());
if (should_observe == observing_agent_hosts_)
return;
observing_agent_hosts_ = should_observe;
if (should_observe)
DevToolsAgentHost::AddObserver(this);
else
DevToolsAgentHost::RemoveObserver(this);
} }
void TargetHandler::AutoAttach(DevToolsAgentHost* host, void TargetHandler::AutoAttach(DevToolsAgentHost* host,
...@@ -611,12 +672,9 @@ Response TargetHandler::SetDiscoverTargets(bool discover) { ...@@ -611,12 +672,9 @@ Response TargetHandler::SetDiscoverTargets(bool discover) {
if (discover_ == discover) if (discover_ == discover)
return Response::OK(); return Response::OK();
discover_ = discover; discover_ = discover;
if (discover_) { UpdateAgentHostObserver();
DevToolsAgentHost::AddObserver(this); if (!discover_)
} else {
DevToolsAgentHost::RemoveObserver(this);
reported_hosts_.clear(); reported_hosts_.clear();
}
return Response::OK(); return Response::OK();
} }
...@@ -624,11 +682,14 @@ void TargetHandler::SetAutoAttach( ...@@ -624,11 +682,14 @@ void TargetHandler::SetAutoAttach(
bool auto_attach, bool auto_attach,
bool wait_for_debugger_on_start, bool wait_for_debugger_on_start,
Maybe<bool> flatten, Maybe<bool> flatten,
Maybe<bool> window_open,
std::unique_ptr<SetAutoAttachCallback> callback) { std::unique_ptr<SetAutoAttachCallback> callback) {
if (access_mode_ == AccessMode::kBrowser && !flatten.fromMaybe(false)) {
callback->sendFailure(Response::InvalidParams(
"Only flatten protocol is supported with browser level auto-attach"));
return;
}
SetAutoAttachInternal( SetAutoAttachInternal(
auto_attach, wait_for_debugger_on_start, flatten.fromMaybe(false), auto_attach, wait_for_debugger_on_start, flatten.fromMaybe(false),
window_open.fromMaybe(false),
base::BindOnce(&SetAutoAttachCallback::sendSuccess, std::move(callback))); base::BindOnce(&SetAutoAttachCallback::sendSuccess, std::move(callback)));
} }
...@@ -794,13 +855,34 @@ bool TargetHandler::ShouldForceDevToolsAgentHostCreation() { ...@@ -794,13 +855,34 @@ bool TargetHandler::ShouldForceDevToolsAgentHostCreation() {
return true; return true;
} }
static bool IsMainFrameHost(DevToolsAgentHost* host) {
WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(host->GetWebContents());
if (!web_contents)
return false;
FrameTreeNode* frame_tree_node = web_contents->GetFrameTree()->root();
if (!frame_tree_node)
return false;
return host == RenderFrameDevToolsAgentHost::GetFor(frame_tree_node);
}
void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* host) { void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* host) {
if (discover_) {
// If we start discovering late, all existing agent hosts will be reported, // If we start discovering late, all existing agent hosts will be reported,
// but we could have already attached to some. // but we could have already attached to some.
if (reported_hosts_.find(host) != reported_hosts_.end()) if (reported_hosts_.find(host) == reported_hosts_.end()) {
return;
frontend_->TargetCreated(CreateInfo(host)); frontend_->TargetCreated(CreateInfo(host));
reported_hosts_.insert(host); reported_hosts_.insert(host);
}
}
// In the top level target handler auto-attach to pages as soon as they
// are created, otherwise if they don't incur any network activity we'll
// never get a chance to throttle them (and auto-attach there).
if (access_mode_ == AccessMode::kBrowser &&
auto_attacher_.ShouldThrottleFramesNavigation() &&
IsMainFrameHost(host)) {
auto_attacher_.AttachToAgentHost(host);
}
} }
void TargetHandler::DevToolsAgentHostNavigated(DevToolsAgentHost* host) { void TargetHandler::DevToolsAgentHostNavigated(DevToolsAgentHost* host) {
......
...@@ -28,7 +28,8 @@ namespace protocol { ...@@ -28,7 +28,8 @@ namespace protocol {
class TargetHandler : public DevToolsDomainHandler, class TargetHandler : public DevToolsDomainHandler,
public Target::Backend, public Target::Backend,
public DevToolsAgentHostObserver { public DevToolsAgentHostObserver,
public TargetAutoAttacher::Delegate {
public: public:
enum class AccessMode { enum class AccessMode {
// Only setAutoAttach is supported. Any non-related target are not // Only setAutoAttach is supported. Any non-related target are not
...@@ -63,7 +64,6 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -63,7 +64,6 @@ class TargetHandler : public DevToolsDomainHandler,
void SetAutoAttach(bool auto_attach, void SetAutoAttach(bool auto_attach,
bool wait_for_debugger_on_start, bool wait_for_debugger_on_start,
Maybe<bool> flatten, Maybe<bool> flatten,
Maybe<bool> window_open,
std::unique_ptr<SetAutoAttachCallback> callback) override; std::unique_ptr<SetAutoAttachCallback> callback) override;
Response SetRemoteLocations( Response SetRemoteLocations(
std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override; std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override;
...@@ -106,9 +106,12 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -106,9 +106,12 @@ class TargetHandler : public DevToolsDomainHandler,
private: private:
class Session; class Session;
class Throttle; class Throttle;
class MainFrameThrottle;
// TargetAutoAttacher::Delegate implementation.
void AutoAttach(DevToolsAgentHost* host, bool waiting_for_debugger) override;
void AutoDetach(DevToolsAgentHost* host) override;
void AutoAttach(DevToolsAgentHost* host, bool waiting_for_debugger);
void AutoDetach(DevToolsAgentHost* host);
Response FindSession(Maybe<std::string> session_id, Response FindSession(Maybe<std::string> session_id,
Maybe<std::string> target_id, Maybe<std::string> target_id,
Session** session); Session** session);
...@@ -116,8 +119,8 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -116,8 +119,8 @@ class TargetHandler : public DevToolsDomainHandler,
void SetAutoAttachInternal(bool auto_attach, void SetAutoAttachInternal(bool auto_attach,
bool wait_for_debugger_on_start, bool wait_for_debugger_on_start,
bool flatten, bool flatten,
bool window_open,
base::OnceClosure callback); base::OnceClosure callback);
void UpdateAgentHostObserver();
// DevToolsAgentHostObserver implementation. // DevToolsAgentHostObserver implementation.
bool ShouldForceDevToolsAgentHostCreation() override; bool ShouldForceDevToolsAgentHostCreation() override;
...@@ -132,8 +135,8 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -132,8 +135,8 @@ class TargetHandler : public DevToolsDomainHandler,
std::unique_ptr<Target::Frontend> frontend_; std::unique_ptr<Target::Frontend> frontend_;
TargetAutoAttacher auto_attacher_; TargetAutoAttacher auto_attacher_;
bool flatten_auto_attach_ = false; bool flatten_auto_attach_ = false;
bool attach_to_window_open_ = false;
bool discover_; bool discover_;
bool observing_agent_hosts_ = false;
std::map<std::string, std::unique_ptr<Session>> attached_sessions_; std::map<std::string, std::unique_ptr<Session>> attached_sessions_;
std::map<DevToolsAgentHost*, Session*> auto_attached_sessions_; std::map<DevToolsAgentHost*, Session*> auto_attached_sessions_;
std::set<DevToolsAgentHost*> reported_hosts_; std::set<DevToolsAgentHost*> reported_hosts_;
......
...@@ -245,6 +245,12 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost( ...@@ -245,6 +245,12 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
SetFrameTreeNode(frame_tree_node); SetFrameTreeNode(frame_tree_node);
ChangeFrameHostAndObservedProcess(frame_host); ChangeFrameHostAndObservedProcess(frame_host);
render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive(); render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive();
if (frame_tree_node->parent()) {
render_frame_crashed_ = !render_frame_alive_;
} else {
WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host);
render_frame_crashed_ = web_contents && web_contents->IsCrashed();
}
AddRef(); // Balanced in DestroyOnRenderFrameGone. AddRef(); // Balanced in DestroyOnRenderFrameGone.
NotifyCreated(); NotifyCreated();
} }
...@@ -441,12 +447,8 @@ void RenderFrameDevToolsAgentHost::DidFinishNavigation( ...@@ -441,12 +447,8 @@ void RenderFrameDevToolsAgentHost::DidFinishNavigation(
void RenderFrameDevToolsAgentHost::UpdateFrameHost( void RenderFrameDevToolsAgentHost::UpdateFrameHost(
RenderFrameHostImpl* frame_host) { RenderFrameHostImpl* frame_host) {
if (frame_host == frame_host_) { if (frame_host == frame_host_) {
if (frame_host && !render_frame_alive_) { if (frame_host && !render_frame_alive_)
render_frame_alive_ = true; UpdateFrameAlive();
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetReloadedAfterCrash();
UpdateRendererChannel(IsAttached());
}
return; return;
} }
...@@ -469,13 +471,7 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost( ...@@ -469,13 +471,7 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost(
if (!restricted_sessions.empty()) if (!restricted_sessions.empty())
ForceDetachRestrictedSessions(restricted_sessions); ForceDetachRestrictedSessions(restricted_sessions);
if (!render_frame_alive_) { UpdateFrameAlive();
render_frame_alive_ = true;
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetReloadedAfterCrash();
}
UpdateRendererChannel(IsAttached());
} }
void RenderFrameDevToolsAgentHost::DidStartNavigation( void RenderFrameDevToolsAgentHost::DidStartNavigation(
...@@ -558,6 +554,16 @@ void RenderFrameDevToolsAgentHost::ChangeFrameHostAndObservedProcess( ...@@ -558,6 +554,16 @@ void RenderFrameDevToolsAgentHost::ChangeFrameHostAndObservedProcess(
frame_host_->GetProcess()->AddObserver(this); frame_host_->GetProcess()->AddObserver(this);
} }
void RenderFrameDevToolsAgentHost::UpdateFrameAlive() {
render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive();
if (render_frame_alive_ && render_frame_crashed_) {
render_frame_crashed_ = false;
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetReloadedAfterCrash();
}
UpdateRendererChannel(IsAttached());
}
void RenderFrameDevToolsAgentHost::RenderProcessExited( void RenderFrameDevToolsAgentHost::RenderProcessExited(
RenderProcessHost* host, RenderProcessHost* host,
const ChildProcessTerminationInfo& info) { const ChildProcessTerminationInfo& info) {
...@@ -575,6 +581,7 @@ void RenderFrameDevToolsAgentHost::RenderProcessExited( ...@@ -575,6 +581,7 @@ void RenderFrameDevToolsAgentHost::RenderProcessExited(
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetCrashed(); inspector->TargetCrashed();
NotifyCrashed(info.status); NotifyCrashed(info.status);
render_frame_crashed_ = true;
break; break;
default: default:
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
......
...@@ -139,6 +139,7 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost ...@@ -139,6 +139,7 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
void UpdateFrameHost(RenderFrameHostImpl* frame_host); void UpdateFrameHost(RenderFrameHostImpl* frame_host);
void SetFrameTreeNode(FrameTreeNode* frame_tree_node); void SetFrameTreeNode(FrameTreeNode* frame_tree_node);
void ChangeFrameHostAndObservedProcess(RenderFrameHostImpl* frame_host); void ChangeFrameHostAndObservedProcess(RenderFrameHostImpl* frame_host);
void UpdateFrameAlive();
bool ShouldAllowSession(DevToolsSession* session); bool ShouldAllowSession(DevToolsSession* session);
...@@ -159,6 +160,7 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost ...@@ -159,6 +160,7 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
RenderFrameHostImpl* frame_host_ = nullptr; RenderFrameHostImpl* frame_host_ = nullptr;
base::flat_set<NavigationRequest*> navigation_requests_; base::flat_set<NavigationRequest*> navigation_requests_;
bool render_frame_alive_ = false; bool render_frame_alive_ = false;
bool render_frame_crashed_ = false;
// The FrameTreeNode associated with this agent. // The FrameTreeNode associated with this agent.
FrameTreeNode* frame_tree_node_; FrameTreeNode* frame_tree_node_;
......
...@@ -6833,8 +6833,6 @@ domain Target ...@@ -6833,8 +6833,6 @@ domain Target
# We plan to make this the default, deprecate non-flattened mode, # We plan to make this the default, deprecate non-flattened mode,
# and eventually retire it. See crbug.com/991325. # and eventually retire it. See crbug.com/991325.
optional boolean flatten optional boolean flatten
# Auto-attach to the targets created via window.open from current target.
experimental optional boolean windowOpen
# Controls whether to discover available targets and notify via # Controls whether to discover available targets and notify via
# `targetCreated/targetInfoChanged/targetDestroyed` events. # `targetCreated/targetInfoChanged/targetDestroyed` events.
......
Tests that browser.Target.setAutoAttach() attaches to new about:blank page.
Created new page from another session
Auto-attached to the new page: {
method : Target.attachedToTarget
params : {
sessionId : <string>
targetInfo : {
attached : true
browserContextId : <string>
targetId : <string>
title :
type : page
url :
}
waitingForDebugger : true
}
}
Resumed
Received new target info: {
method : Target.targetInfoChanged
params : {
targetInfo : {
attached : true
browserContextId : <string>
targetId : <string>
title : about:blank#newpage
type : page
url : about:blank#newpage
}
}
}
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Tests that browser.Target.setAutoAttach() attaches to new about:blank page.`);
const target = testRunner.browserP().Target;
await target.setDiscoverTargets({discover: true});
await target.setAutoAttach(
{autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
const response = await target.attachToBrowserTarget();
const newBrowserSession = new TestRunner.Session(testRunner, response.result.sessionId);
newBrowserSession.protocol.Target.createTarget({url: 'about:blank#newpage'});
testRunner.log('Created new page from another session');
const attachedEvent = await target.onceAttachedToTarget();
testRunner.log(attachedEvent, 'Auto-attached to the new page: ');
// Navigate elsewhere and test that the request will be paused.
const newSession = new TestRunner.Session(testRunner, attachedEvent.params.sessionId);
const logSpuriousEvent = event => testRunner.log(event, 'FAIL: received spurious event while paused ');
target.onTargetInfoChanged(logSpuriousEvent);
newSession.navigate(testRunner.url('../resources/test-page.html?newpage'));
// Do a roundtrip to the browser to wait for some time when
// TargetInfoChanged could come.
await target.getTargets();
target.offTargetInfoChanged(logSpuriousEvent);
const [infoChangedEvent] = await Promise.all([
target.onceTargetInfoChanged(),
newSession.protocol.Runtime.runIfWaitingForDebugger()
]);
testRunner.log('Resumed');
testRunner.log(infoChangedEvent, 'Received new target info: ');
await newBrowserSession.disconnect();
testRunner.completeTest();
})
Tests that browser.Target.setAutoAttach() supports only flatten protocol.
Tried to auto-attach with not fatten protocol{
error : {
code : -32602
message : Only flatten protocol is supported with browser level auto-attach
}
id : <number>
}
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Tests that browser.Target.setAutoAttach() supports only flatten protocol.`);
const target = testRunner.browserP().Target;
const response = await target.setAutoAttach(
{autoAttach: true, waitForDebuggerOnStart: true, flatten: false});
testRunner.log(response, 'Tried to auto-attach with not fatten protocol');
testRunner.completeTest();
})
Tests that browser.Target.setAutoAttach() attaches to new page targets.
Attached to the new page: {
method : Target.attachedToTarget
params : {
sessionId : <string>
targetInfo : {
attached : true
browserContextId : <string>
targetId : <string>
title :
type : page
url :
}
waitingForDebugger : true
}
}
Resumed
New page location: {
id : <number>
result : {
result : {
type : string
value : http://127.0.0.1:8000/inspector-protocol/resources/test-page.html?newpage
}
}
sessionId : <string>
}
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Tests that browser.Target.setAutoAttach() attaches to new page targets.`);
const target = testRunner.browserP().Target;
await target.setDiscoverTargets({discover: true});
await target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
const response = await target.attachToBrowserTarget();
const newBrowserSession =
new TestRunner.Session(testRunner, response.result.sessionId);
const newUrl = testRunner.url('../resources/test-page.html?newpage');
newBrowserSession.protocol.Target.createTarget({url: newUrl});
const attachedEvent = await target.onceAttachedToTarget();
testRunner.log(attachedEvent, 'Attached to the new page: ');
const newSession = new TestRunner.Session(testRunner, attachedEvent.params.sessionId);
newSession.protocol.Inspector.onTargetReloadedAfterCrash(
event => testRunner.log(event, 'FAIL: received spurious event '));
await newSession.protocol.Runtime.runIfWaitingForDebugger();
testRunner.log('Resumed\n\n');
const path = await newSession.protocol.Runtime.evaluate({expression: 'location.href'});
testRunner.log(path, 'New page location: ');
await newBrowserSession.disconnect();
testRunner.completeTest();
})
Tests that Target.setAutoAttach(windowOpen=true) attaches to window.open targets. Tests that browser.Target.setAutoAttach() attaches to window.open targets.
Opened the window Opened the window
Attached to window Attached to window, waitingForDebugger=true
Resumed popup window
Popup window URL changed to http://127.0.0.1:8000/inspector-protocol/resources/inspector-protocol-page.html
Navigated the window Navigated the window
Target info changed Target info changed, new URL is http://127.0.0.1:8000/inspector-protocol/resources/test-page.html
Closed the window Closed the window
Detached from window Detached from window
(async function(testRunner) { (async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank( var {page, session, dp} = await testRunner.startBlank(
`Tests that Target.setAutoAttach(windowOpen=true) attaches to window.open targets.`); `Tests that browser.Target.setAutoAttach() attaches to window.open targets.`);
await dp.Target.setDiscoverTargets({discover: true}); const target = testRunner.browserP().Target;
await target.setDiscoverTargets({discover: true});
await target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true, windowOpen: true});
const attachedPromise = dp.Target.onceAttachedToTarget();
session.evaluate(` session.evaluate(`
window.myWindow = window.open('../resources/inspector-protocol-page.html'); undefined; window.myWindow = window.open('../resources/inspector-protocol-page.html'); undefined;
`); `);
testRunner.log('Opened the window'); testRunner.log('Opened the window');
await attachedPromise; const attachedEvent = await target.onceAttachedToTarget();
testRunner.log('Attached to window'); testRunner.log('Attached to window, waitingForDebugger=' + attachedEvent.params.waitingForDebugger);
const popupSession = new TestRunner.Session(testRunner, attachedEvent.params.sessionId);
const changedPromise = target.onceTargetInfoChanged();
await popupSession.protocol.Runtime.runIfWaitingForDebugger();
testRunner.log('Resumed popup window');
const changeEvent = await changedPromise;
testRunner.log('Popup window URL changed to ' + changeEvent.params.targetInfo.url);
const changedPromise = dp.Target.onceTargetInfoChanged(); const secondChangedPromise = target.onceTargetInfoChanged();
session.evaluate(` session.evaluate(`
window.myWindow.location.assign('../resources/inspector-protocol-page.html?foo'); undefined; window.myWindow.location.assign('../resources/test-page.html'); undefined;
`); `);
testRunner.log('Navigated the window'); testRunner.log('Navigated the window');
await changedPromise; const secondChangeEvent = await secondChangedPromise;
testRunner.log('Target info changed'); testRunner.log('Target info changed, new URL is ' + secondChangeEvent.params.targetInfo.url);
const detachedPromise = dp.Target.onceDetachedFromTarget(); const detachedPromise = target.onceDetachedFromTarget();
session.evaluate(` session.evaluate(`
window.myWindow.close(); undefined; window.myWindow.close(); undefined;
`); `);
......
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