Commit 237f8276 authored by Dmitry Gozman's avatar Dmitry Gozman Committed by Commit Bot

[DevTools] Support multiple sessions in Target domain

BUG=590878

Change-Id: Idcebf0336623322813b4cdfac66183d37c28f2bd
Reviewed-on: https://chromium-review.googlesource.com/573411
Commit-Queue: Dmitry Gozman <dgozman@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488395}
parent 17173492
...@@ -186,6 +186,10 @@ void DevToolsAgentHostImpl::ForceAttachClient(DevToolsAgentHostClient* client) { ...@@ -186,6 +186,10 @@ void DevToolsAgentHostImpl::ForceAttachClient(DevToolsAgentHostClient* client) {
InnerAttachClient(client); InnerAttachClient(client);
} }
void DevToolsAgentHostImpl::AttachMultiClient(DevToolsAgentHostClient* client) {
InnerAttachClient(client);
}
bool DevToolsAgentHostImpl::DetachClient(DevToolsAgentHostClient* client) { bool DevToolsAgentHostImpl::DetachClient(DevToolsAgentHostClient* client) {
if (!SessionByClient(client)) if (!SessionByClient(client))
return false; return false;
......
...@@ -44,6 +44,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost { ...@@ -44,6 +44,7 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
void DisconnectWebContents() override; void DisconnectWebContents() override;
void ConnectWebContents(WebContents* wc) override; void ConnectWebContents(WebContents* wc) override;
void AttachMultiClient(DevToolsAgentHostClient* client);
bool Inspect(); bool Inspect();
protected: protected:
......
...@@ -1657,6 +1657,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, TargetDiscovery) { ...@@ -1657,6 +1657,8 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, TargetDiscovery) {
EXPECT_TRUE(params->GetBoolean("targetInfo.attached", &is_attached)); EXPECT_TRUE(params->GetBoolean("targetInfo.attached", &is_attached));
EXPECT_TRUE(is_attached); EXPECT_TRUE(is_attached);
params = WaitForNotification("Target.attachedToTarget", true); params = WaitForNotification("Target.attachedToTarget", true);
std::string session_id;
EXPECT_TRUE(params->GetString("sessionId", &session_id));
EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp)); EXPECT_TRUE(params->GetString("targetInfo.targetId", &temp));
EXPECT_EQ(attached_id, temp); EXPECT_EQ(attached_id, temp);
EXPECT_TRUE(notifications_.empty()); EXPECT_TRUE(notifications_.empty());
...@@ -1667,9 +1669,11 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, TargetDiscovery) { ...@@ -1667,9 +1669,11 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, TargetDiscovery) {
EXPECT_TRUE(notifications_.empty()); EXPECT_TRUE(notifications_.empty());
command_params.reset(new base::DictionaryValue()); command_params.reset(new base::DictionaryValue());
command_params->SetString("targetId", attached_id); command_params->SetString("sessionId", session_id);
SendCommand("Target.detachFromTarget", std::move(command_params), true); SendCommand("Target.detachFromTarget", std::move(command_params), true);
params = WaitForNotification("Target.detachedFromTarget", true); params = WaitForNotification("Target.detachedFromTarget", true);
EXPECT_TRUE(params->GetString("sessionId", &temp));
EXPECT_EQ(session_id, temp);
EXPECT_TRUE(params->GetString("targetId", &temp)); EXPECT_TRUE(params->GetString("targetId", &temp));
EXPECT_EQ(attached_id, temp); EXPECT_EQ(attached_id, temp);
EXPECT_TRUE(notifications_.empty()); EXPECT_TRUE(notifications_.empty());
...@@ -1737,6 +1741,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) { ...@@ -1737,6 +1741,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) {
command_params->SetBoolean("value", true); command_params->SetBoolean("value", true);
SendCommand("Target.setAttachToFrames", std::move(command_params), false); SendCommand("Target.setAttachToFrames", std::move(command_params), false);
params = WaitForNotification("Target.attachedToTarget", true); params = WaitForNotification("Target.attachedToTarget", true);
std::string session_id;
EXPECT_TRUE(params->GetString("sessionId", &session_id));
EXPECT_TRUE(params->GetString("targetInfo.targetId", &target_id)); EXPECT_TRUE(params->GetString("targetInfo.targetId", &target_id));
EXPECT_TRUE(params->GetString("targetInfo.type", &temp)); EXPECT_TRUE(params->GetString("targetInfo.type", &temp));
EXPECT_EQ("iframe", temp); EXPECT_EQ("iframe", temp);
...@@ -1748,10 +1754,13 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) { ...@@ -1748,10 +1754,13 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) {
params = WaitForNotification("Target.detachedFromTarget", true); params = WaitForNotification("Target.detachedFromTarget", true);
EXPECT_TRUE(params->GetString("targetId", &temp)); EXPECT_TRUE(params->GetString("targetId", &temp));
EXPECT_EQ(target_id, temp); EXPECT_EQ(target_id, temp);
EXPECT_TRUE(params->GetString("sessionId", &temp));
EXPECT_EQ(session_id, temp);
// Navigate back to cross-site iframe. // Navigate back to cross-site iframe.
NavigateFrameToURL(root->child_at(0), cross_site_url); NavigateFrameToURL(root->child_at(0), cross_site_url);
params = WaitForNotification("Target.attachedToTarget", true); params = WaitForNotification("Target.attachedToTarget", true);
EXPECT_TRUE(params->GetString("sessionId", &session_id));
EXPECT_TRUE(params->GetString("targetInfo.targetId", &target_id)); EXPECT_TRUE(params->GetString("targetInfo.targetId", &target_id));
EXPECT_TRUE(params->GetString("targetInfo.type", &temp)); EXPECT_TRUE(params->GetString("targetInfo.type", &temp));
EXPECT_EQ("iframe", temp); EXPECT_EQ("iframe", temp);
...@@ -1764,6 +1773,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) { ...@@ -1764,6 +1773,8 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, TargetNoDiscovery) {
params = WaitForNotification("Target.detachedFromTarget", true); params = WaitForNotification("Target.detachedFromTarget", true);
EXPECT_TRUE(params->GetString("targetId", &temp)); EXPECT_TRUE(params->GetString("targetId", &temp));
EXPECT_EQ(target_id, temp); EXPECT_EQ(target_id, temp);
EXPECT_TRUE(params->GetString("sessionId", &temp));
EXPECT_EQ(session_id, temp);
} }
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SetAndGetCookies) { IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SetAndGetCookies) {
......
...@@ -176,8 +176,8 @@ void TargetAutoAttacher::ReattachTargetsOfType(const Hosts& new_hosts, ...@@ -176,8 +176,8 @@ void TargetAutoAttacher::ReattachTargetsOfType(const Hosts& new_hosts,
for (auto& it : new_hosts) { for (auto& it : new_hosts) {
DevToolsAgentHost* host = it.get(); DevToolsAgentHost* host = it.get();
if (old_hosts.find(host) == old_hosts.end()) { if (old_hosts.find(host) == old_hosts.end()) {
if (attach_callback_.Run(host, waiting_for_debugger)) attach_callback_.Run(host, waiting_for_debugger);
auto_attached_hosts_.insert(host); auto_attached_hosts_.insert(host);
} }
} }
} }
......
...@@ -18,7 +18,7 @@ namespace protocol { ...@@ -18,7 +18,7 @@ namespace protocol {
class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer { class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer {
public: public:
// Second parameter is |waiting_for_debugger|, returns whether it succeeded. // Second parameter is |waiting_for_debugger|, returns whether it succeeded.
using AttachCallback = base::Callback<bool(DevToolsAgentHost*, bool)>; using AttachCallback = base::Callback<void(DevToolsAgentHost*, bool)>;
using DetachCallback = base::Callback<void(DevToolsAgentHost*)>; using DetachCallback = base::Callback<void(DevToolsAgentHost*)>;
TargetAutoAttacher(AttachCallback attach_callback, TargetAutoAttacher(AttachCallback attach_callback,
......
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
#include "content/browser/devtools/protocol/target_handler.h" #include "content/browser/devtools/protocol/target_handler.h"
#include "base/strings/stringprintf.h"
#include "content/browser/devtools/devtools_manager.h" #include "content/browser/devtools/devtools_manager.h"
#include "content/browser/devtools/devtools_session.h" #include "content/browser/devtools/devtools_session.h"
#include "content/public/browser/devtools_agent_host_client.h"
namespace content { namespace content {
namespace protocol { namespace protocol {
...@@ -24,12 +26,77 @@ std::unique_ptr<Target::TargetInfo> CreateInfo(DevToolsAgentHost* host) { ...@@ -24,12 +26,77 @@ std::unique_ptr<Target::TargetInfo> CreateInfo(DevToolsAgentHost* host) {
} // namespace } // namespace
class TargetHandler::Session : public DevToolsAgentHostClient {
public:
static std::string Attach(TargetHandler* handler,
DevToolsAgentHost* agent_host,
bool waiting_for_debugger) {
std::string id = base::StringPrintf("%s:%d", agent_host->GetId().c_str(),
++handler->last_session_id_);
Session* session = new Session(handler, agent_host, id);
handler->attached_sessions_[id].reset(session);
static_cast<DevToolsAgentHostImpl*>(agent_host)->AttachMultiClient(session);
handler->frontend_->AttachedToTarget(id, CreateInfo(agent_host),
waiting_for_debugger);
return id;
}
~Session() override {
if (agent_host_)
agent_host_->DetachClient(this);
}
void Detach(bool host_closed) {
handler_->frontend_->DetachedFromTarget(id_, agent_host_->GetId());
if (host_closed)
handler_->auto_attacher_.AgentHostClosed(agent_host_.get());
else
agent_host_->DetachClient(this);
handler_->auto_attached_sessions_.erase(agent_host_.get());
agent_host_ = nullptr;
handler_->attached_sessions_.erase(id_);
}
void SendMessageToAgentHost(const std::string& message) {
agent_host_->DispatchProtocolMessage(this, message);
}
bool IsAttachedTo(const std::string& target_id) {
return agent_host_->GetId() == target_id;
}
private:
Session(TargetHandler* handler,
DevToolsAgentHost* agent_host,
const std::string& id)
: handler_(handler), agent_host_(agent_host), id_(id) {}
// DevToolsAgentHostClient implementation.
void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
const std::string& message) override {
DCHECK(agent_host == agent_host_.get());
handler_->frontend_->ReceivedMessageFromTarget(id_, message,
agent_host_->GetId());
}
void AgentHostClosed(DevToolsAgentHost* agent_host,
bool replaced_with_another_client) override {
DCHECK(agent_host == agent_host_.get());
Detach(true);
}
TargetHandler* handler_;
scoped_refptr<DevToolsAgentHost> agent_host_;
std::string id_;
DISALLOW_COPY_AND_ASSIGN(Session);
};
TargetHandler::TargetHandler() TargetHandler::TargetHandler()
: DevToolsDomainHandler(Target::Metainfo::domainName), : DevToolsDomainHandler(Target::Metainfo::domainName),
auto_attacher_(base::Bind(&TargetHandler::AttachToTargetInternal, auto_attacher_(
base::Unretained(this)), base::Bind(&TargetHandler::AutoAttach, base::Unretained(this)),
base::Bind(&TargetHandler::DetachFromTargetInternal, base::Bind(&TargetHandler::AutoDetach, base::Unretained(this))),
base::Unretained(this))),
discover_(false) {} discover_(false) {}
TargetHandler::~TargetHandler() { TargetHandler::~TargetHandler() {
...@@ -54,9 +121,8 @@ void TargetHandler::SetRenderFrameHost(RenderFrameHostImpl* render_frame_host) { ...@@ -54,9 +121,8 @@ void TargetHandler::SetRenderFrameHost(RenderFrameHostImpl* render_frame_host) {
Response TargetHandler::Disable() { Response TargetHandler::Disable() {
SetAutoAttach(false, false); SetAutoAttach(false, false);
SetDiscoverTargets(false); SetDiscoverTargets(false);
for (const auto& id_host : attached_hosts_) auto_attached_sessions_.clear();
id_host.second->DetachClient(this); attached_sessions_.clear();
attached_hosts_.clear();
return Response::OK(); return Response::OK();
} }
...@@ -68,46 +134,52 @@ void TargetHandler::RenderFrameHostChanged() { ...@@ -68,46 +134,52 @@ void TargetHandler::RenderFrameHostChanged() {
auto_attacher_.UpdateFrames(); auto_attacher_.UpdateFrames();
} }
void TargetHandler::TargetCreatedInternal(DevToolsAgentHost* host) { void TargetHandler::AutoAttach(DevToolsAgentHost* host,
if (reported_hosts_.find(host->GetId()) != reported_hosts_.end()) bool waiting_for_debugger) {
return; std::string session_id = Session::Attach(this, host, waiting_for_debugger);
frontend_->TargetCreated(CreateInfo(host)); auto_attached_sessions_[host] = attached_sessions_[session_id].get();
reported_hosts_[host->GetId()] = host;
}
void TargetHandler::TargetInfoChangedInternal(DevToolsAgentHost* host) {
if (reported_hosts_.find(host->GetId()) == reported_hosts_.end())
return;
frontend_->TargetInfoChanged(CreateInfo(host));
} }
void TargetHandler::TargetDestroyedInternal(DevToolsAgentHost* host) { void TargetHandler::AutoDetach(DevToolsAgentHost* host) {
auto it = reported_hosts_.find(host->GetId()); auto it = auto_attached_sessions_.find(host);
if (it == reported_hosts_.end()) if (it == auto_attached_sessions_.end())
return; return;
if (discover_) it->second->Detach(false);
frontend_->TargetDestroyed(host->GetId()); }
reported_hosts_.erase(it);
} Response TargetHandler::FindSession(Maybe<std::string> session_id,
Maybe<std::string> target_id,
bool TargetHandler::AttachToTargetInternal( Session** session,
DevToolsAgentHost* host, bool waiting_for_debugger) { bool fall_through) {
attached_hosts_[host->GetId()] = host; *session = nullptr;
if (!host->AttachClient(this)) { if (session_id.isJust()) {
attached_hosts_.erase(host->GetId()); auto it = attached_sessions_.find(session_id.fromJust());
return false; if (it == attached_sessions_.end()) {
if (fall_through)
return Response::FallThrough();
return Response::InvalidParams("No session with given id");
}
*session = it->second.get();
return Response::OK();
} }
frontend_->AttachedToTarget(CreateInfo(host), waiting_for_debugger); if (target_id.isJust()) {
return true; for (auto& it : attached_sessions_) {
} if (it.second->IsAttachedTo(target_id.fromJust())) {
if (*session)
void TargetHandler::DetachFromTargetInternal(DevToolsAgentHost* host) { return Response::Error("Multiple sessions attached, specify id.");
auto it = attached_hosts_.find(host->GetId()); *session = it.second.get();
if (it == attached_hosts_.end()) }
return; }
host->DetachClient(this); if (!*session) {
frontend_->DetachedFromTarget(host->GetId()); if (fall_through)
attached_hosts_.erase(it); return Response::FallThrough();
return Response::InvalidParams("No session for given target id");
}
return Response::OK();
}
if (fall_through)
return Response::FallThrough();
return Response::InvalidParams("Session id must be specified");
} }
// ----------------- Protocol ---------------------- // ----------------- Protocol ----------------------
...@@ -120,9 +192,7 @@ Response TargetHandler::SetDiscoverTargets(bool discover) { ...@@ -120,9 +192,7 @@ Response TargetHandler::SetDiscoverTargets(bool discover) {
DevToolsAgentHost::AddObserver(this); DevToolsAgentHost::AddObserver(this);
} else { } else {
DevToolsAgentHost::RemoveObserver(this); DevToolsAgentHost::RemoveObserver(this);
RawHostsMap copy = reported_hosts_; reported_hosts_.clear();
for (const auto& id_host : copy)
TargetDestroyedInternal(id_host.second);
} }
return Response::OK(); return Response::OK();
} }
...@@ -144,32 +214,36 @@ Response TargetHandler::SetRemoteLocations( ...@@ -144,32 +214,36 @@ Response TargetHandler::SetRemoteLocations(
} }
Response TargetHandler::AttachToTarget(const std::string& target_id, Response TargetHandler::AttachToTarget(const std::string& target_id,
bool* out_success) { std::string* out_session_id) {
// TODO(dgozman): only allow reported hosts. // TODO(dgozman): only allow reported hosts.
scoped_refptr<DevToolsAgentHost> agent_host = scoped_refptr<DevToolsAgentHost> agent_host =
DevToolsAgentHost::GetForId(target_id); DevToolsAgentHost::GetForId(target_id);
if (!agent_host) if (!agent_host)
return Response::InvalidParams("No target with given id found"); return Response::InvalidParams("No target with given id found");
*out_success = AttachToTargetInternal(agent_host.get(), false); *out_session_id = Session::Attach(this, agent_host.get(), false);
return Response::OK(); return Response::OK();
} }
Response TargetHandler::DetachFromTarget(const std::string& target_id) { Response TargetHandler::DetachFromTarget(Maybe<std::string> session_id,
auto it = attached_hosts_.find(target_id); Maybe<std::string> target_id) {
if (it == attached_hosts_.end()) Session* session = nullptr;
return Response::Error("Not attached to the target"); Response response =
DevToolsAgentHost* agent_host = it->second.get(); FindSession(std::move(session_id), std::move(target_id), &session, false);
DetachFromTargetInternal(agent_host); if (!response.isSuccess())
return response;
session->Detach(false);
return Response::OK(); return Response::OK();
} }
Response TargetHandler::SendMessageToTarget( Response TargetHandler::SendMessageToTarget(const std::string& message,
const std::string& target_id, Maybe<std::string> session_id,
const std::string& message) { Maybe<std::string> target_id) {
auto it = attached_hosts_.find(target_id); Session* session = nullptr;
if (it == attached_hosts_.end()) Response response =
return Response::FallThrough(); FindSession(std::move(session_id), std::move(target_id), &session, true);
it->second->DispatchProtocolMessage(this, message); if (!response.isSuccess())
return response;
session->SendMessageToAgentHost(message);
return Response::OK(); return Response::OK();
} }
...@@ -239,49 +313,38 @@ Response TargetHandler::GetTargets( ...@@ -239,49 +313,38 @@ Response TargetHandler::GetTargets(
return Response::OK(); return Response::OK();
} }
// ---------------- DevToolsAgentHostClient ----------------
void TargetHandler::DispatchProtocolMessage(
DevToolsAgentHost* host,
const std::string& message) {
auto it = attached_hosts_.find(host->GetId());
if (it == attached_hosts_.end())
return; // Already disconnected.
frontend_->ReceivedMessageFromTarget(host->GetId(), message);
}
void TargetHandler::AgentHostClosed(
DevToolsAgentHost* host,
bool replaced_with_another_client) {
frontend_->DetachedFromTarget(host->GetId());
attached_hosts_.erase(host->GetId());
auto_attacher_.AgentHostClosed(host);
}
// -------------- DevToolsAgentHostObserver ----------------- // -------------- DevToolsAgentHostObserver -----------------
bool TargetHandler::ShouldForceDevToolsAgentHostCreation() { bool TargetHandler::ShouldForceDevToolsAgentHostCreation() {
return true; return true;
} }
void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* agent_host) { void TargetHandler::DevToolsAgentHostCreated(DevToolsAgentHost* host) {
// 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.
TargetCreatedInternal(agent_host); if (reported_hosts_.find(host) != reported_hosts_.end())
return;
frontend_->TargetCreated(CreateInfo(host));
reported_hosts_.insert(host);
} }
void TargetHandler::DevToolsAgentHostDestroyed(DevToolsAgentHost* agent_host) { void TargetHandler::DevToolsAgentHostDestroyed(DevToolsAgentHost* host) {
DCHECK(attached_hosts_.find(agent_host->GetId()) == attached_hosts_.end()); if (reported_hosts_.find(host) == reported_hosts_.end())
TargetDestroyedInternal(agent_host); return;
frontend_->TargetDestroyed(host->GetId());
reported_hosts_.erase(host);
} }
void TargetHandler::DevToolsAgentHostAttached(DevToolsAgentHost* host) { void TargetHandler::DevToolsAgentHostAttached(DevToolsAgentHost* host) {
TargetInfoChangedInternal(host); if (reported_hosts_.find(host) == reported_hosts_.end())
return;
frontend_->TargetInfoChanged(CreateInfo(host));
} }
void TargetHandler::DevToolsAgentHostDetached(DevToolsAgentHost* host) { void TargetHandler::DevToolsAgentHostDetached(DevToolsAgentHost* host) {
TargetInfoChangedInternal(host); if (reported_hosts_.find(host) == reported_hosts_.end())
return;
frontend_->TargetInfoChanged(CreateInfo(host));
} }
} // namespace protocol } // namespace protocol
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "content/browser/devtools/protocol/devtools_domain_handler.h" #include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/target.h" #include "content/browser/devtools/protocol/target.h"
#include "content/browser/devtools/protocol/target_auto_attacher.h" #include "content/browser/devtools/protocol/target_auto_attacher.h"
#include "content/public/browser/devtools_agent_host_client.h"
#include "content/public/browser/devtools_agent_host_observer.h" #include "content/public/browser/devtools_agent_host_observer.h"
namespace content { namespace content {
...@@ -23,7 +22,6 @@ namespace protocol { ...@@ -23,7 +22,6 @@ namespace protocol {
class TargetHandler : public DevToolsDomainHandler, class TargetHandler : public DevToolsDomainHandler,
public Target::Backend, public Target::Backend,
public DevToolsAgentHostClient,
public DevToolsAgentHostObserver { public DevToolsAgentHostObserver {
public: public:
TargetHandler(); TargetHandler();
...@@ -46,10 +44,12 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -46,10 +44,12 @@ class TargetHandler : public DevToolsDomainHandler,
Response SetRemoteLocations( Response SetRemoteLocations(
std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override; std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override;
Response AttachToTarget(const std::string& target_id, Response AttachToTarget(const std::string& target_id,
bool* out_success) override; std::string* out_session_id) override;
Response DetachFromTarget(const std::string& target_id) override; Response DetachFromTarget(Maybe<std::string> session_id,
Response SendMessageToTarget(const std::string& target_id, Maybe<std::string> target_id) override;
const std::string& message) override; Response SendMessageToTarget(const std::string& message,
Maybe<std::string> session_id,
Maybe<std::string> target_id) override;
Response GetTargetInfo( Response GetTargetInfo(
const std::string& target_id, const std::string& target_id,
std::unique_ptr<Target::TargetInfo>* target_info) override; std::unique_ptr<Target::TargetInfo>* target_info) override;
...@@ -69,14 +69,14 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -69,14 +69,14 @@ class TargetHandler : public DevToolsDomainHandler,
override; override;
private: private:
using RawHostsMap = std::map<std::string, DevToolsAgentHost*>; class Session;
void TargetCreatedInternal(DevToolsAgentHost* host); void AutoAttach(DevToolsAgentHost* host, bool waiting_for_debugger);
void TargetInfoChangedInternal(DevToolsAgentHost* host); void AutoDetach(DevToolsAgentHost* host);
void TargetDestroyedInternal(DevToolsAgentHost* host); Response FindSession(Maybe<std::string> session_id,
bool AttachToTargetInternal(DevToolsAgentHost* host, Maybe<std::string> target_id,
bool waiting_for_debugger); Session** session,
void DetachFromTargetInternal(DevToolsAgentHost* host); bool fall_through);
// DevToolsAgentHostObserver implementation. // DevToolsAgentHostObserver implementation.
bool ShouldForceDevToolsAgentHostCreation() override; bool ShouldForceDevToolsAgentHostCreation() override;
...@@ -85,17 +85,13 @@ class TargetHandler : public DevToolsDomainHandler, ...@@ -85,17 +85,13 @@ class TargetHandler : public DevToolsDomainHandler,
void DevToolsAgentHostAttached(DevToolsAgentHost* agent_host) override; void DevToolsAgentHostAttached(DevToolsAgentHost* agent_host) override;
void DevToolsAgentHostDetached(DevToolsAgentHost* agent_host) override; void DevToolsAgentHostDetached(DevToolsAgentHost* agent_host) override;
// DevToolsAgentHostClient implementation.
void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
const std::string& message) override;
void AgentHostClosed(DevToolsAgentHost* agent_host,
bool replaced_with_another_client) override;
std::unique_ptr<Target::Frontend> frontend_; std::unique_ptr<Target::Frontend> frontend_;
TargetAutoAttacher auto_attacher_; TargetAutoAttacher auto_attacher_;
bool discover_; bool discover_;
std::map<std::string, scoped_refptr<DevToolsAgentHost>> attached_hosts_; std::map<std::string, std::unique_ptr<Session>> attached_sessions_;
RawHostsMap reported_hosts_; std::map<DevToolsAgentHost*, Session*> auto_attached_sessions_;
std::set<DevToolsAgentHost*> reported_hosts_;
int last_session_id_ = 0;
DISALLOW_COPY_AND_ASSIGN(TargetHandler); DISALLOW_COPY_AND_ASSIGN(TargetHandler);
}; };
......
...@@ -184,9 +184,9 @@ TestRunner.Page = class { ...@@ -184,9 +184,9 @@ TestRunner.Page = class {
} }
async createSession() { async createSession() {
await DevToolsAPI._sendCommandOrDie('Target.attachToTarget', {targetId: this._targetId}); var sessionId = (await DevToolsAPI._sendCommandOrDie('Target.attachToTarget', {targetId: this._targetId})).sessionId;
var session = new TestRunner.Session(this); var session = new TestRunner.Session(this, sessionId);
DevToolsAPI._sessions.set(this._targetId, session); DevToolsAPI._sessions.set(sessionId, session);
return session; return session;
} }
...@@ -195,18 +195,12 @@ TestRunner.Page = class { ...@@ -195,18 +195,12 @@ TestRunner.Page = class {
} }
async _navigate(url) { async _navigate(url) {
if (DevToolsAPI._sessions.get(this._targetId))
this._testRunner.die(`Cannot navigate to ${url} with active session`, new Error());
var session = await this.createSession(); var session = await this.createSession();
await session._navigate(url); await session._navigate(url);
await session.disconnect(); await session.disconnect();
} }
async loadHTML(html) { async loadHTML(html) {
if (DevToolsAPI._sessions.get(this._targetId))
this._testRunner.die('Cannot loadHTML with active session', new Error());
html = html.replace(/'/g, "\\'").replace(/\n/g, '\\n'); html = html.replace(/'/g, "\\'").replace(/\n/g, '\\n');
var session = await this.createSession(); var session = await this.createSession();
await session.protocol.Runtime.evaluate({expression: `document.write('${html}');document.close();`}); await session.protocol.Runtime.evaluate({expression: `document.write('${html}');document.close();`});
...@@ -215,9 +209,10 @@ TestRunner.Page = class { ...@@ -215,9 +209,10 @@ TestRunner.Page = class {
}; };
TestRunner.Session = class { TestRunner.Session = class {
constructor(page) { constructor(page, sessionId) {
this._testRunner = page._testRunner; this._testRunner = page._testRunner;
this._page = page; this._page = page;
this._sessionId = sessionId;
this._requestId = 0; this._requestId = 0;
this._dispatchTable = new Map(); this._dispatchTable = new Map();
this._eventHandlers = new Map(); this._eventHandlers = new Map();
...@@ -225,12 +220,12 @@ TestRunner.Session = class { ...@@ -225,12 +220,12 @@ TestRunner.Session = class {
} }
async disconnect() { async disconnect() {
await DevToolsAPI._sendCommandOrDie('Target.detachFromTarget', {targetId: this._page._targetId}); await DevToolsAPI._sendCommandOrDie('Target.detachFromTarget', {sessionId: this._sessionId});
DevToolsAPI._sessions.delete(this._page._targetId); DevToolsAPI._sessions.delete(this._page._targetId);
} }
sendRawCommand(requestId, message) { sendRawCommand(requestId, message) {
DevToolsAPI._sendCommandOrDie('Target.sendMessageToTarget', {targetId: this._page._targetId, message: message}); DevToolsAPI._sendCommandOrDie('Target.sendMessageToTarget', {sessionId: this._sessionId, message: message});
return new Promise(f => this._dispatchTable.set(requestId, f)); return new Promise(f => this._dispatchTable.set(requestId, f));
} }
...@@ -394,9 +389,9 @@ DevToolsAPI.dispatchMessage = function(messageOrObject) { ...@@ -394,9 +389,9 @@ DevToolsAPI.dispatchMessage = function(messageOrObject) {
} else { } else {
var eventName = messageObject.method; var eventName = messageObject.method;
if (eventName === 'Target.receivedMessageFromTarget') { if (eventName === 'Target.receivedMessageFromTarget') {
var targetId = messageObject.params.targetId; var sessionId = messageObject.params.sessionId;
var message = messageObject.params.message; var message = messageObject.params.message;
var session = DevToolsAPI._sessions.get(targetId); var session = DevToolsAPI._sessions.get(sessionId);
if (session) if (session)
session._dispatchMessage(JSON.parse(message)); session._dispatchMessage(JSON.parse(message));
} }
......
...@@ -4,18 +4,18 @@ Debugger-related command should be issued: { ...@@ -4,18 +4,18 @@ Debugger-related command should be issued: {
"id": "<id>", "id": "<id>",
"method": "Target.sendMessageToTarget", "method": "Target.sendMessageToTarget",
"params": { "params": {
"targetId": "<id>",
"message": { "message": {
"id": "<id>", "id": "<id>",
"method": "Target.sendMessageToTarget", "method": "Target.sendMessageToTarget",
"params": { "params": {
"targetId": "<id>",
"message": { "message": {
"id": "<id>", "id": "<id>",
"method": "Debugger.enable" "method": "Debugger.enable"
} },
"sessionId": "<id>"
} }
} },
"sessionId": "<id>"
} }
} }
Suspending targets. Suspending targets.
...@@ -24,18 +24,18 @@ Debugger-related command should be issued: { ...@@ -24,18 +24,18 @@ Debugger-related command should be issued: {
"id": "<id>", "id": "<id>",
"method": "Target.sendMessageToTarget", "method": "Target.sendMessageToTarget",
"params": { "params": {
"targetId": "<id>",
"message": { "message": {
"id": "<id>", "id": "<id>",
"method": "Target.sendMessageToTarget", "method": "Target.sendMessageToTarget",
"params": { "params": {
"targetId": "<id>",
"message": { "message": {
"id": "<id>", "id": "<id>",
"method": "Debugger.enable" "method": "Debugger.enable"
} },
"sessionId": "<id>"
} }
} },
"sessionId": "<id>"
} }
} }
...@@ -38,18 +38,16 @@ ...@@ -38,18 +38,16 @@
namespace blink { namespace blink {
using protocol::Maybe;
using protocol::Response; using protocol::Response;
namespace WorkerAgentState { namespace WorkerAgentState {
static const char kAutoAttach[] = "autoAttach"; static const char kAutoAttach[] = "autoAttach";
static const char kWaitForDebuggerOnStart[] = "waitForDebuggerOnStart"; static const char kWaitForDebuggerOnStart[] = "waitForDebuggerOnStart";
static const char kAttachedWorkerIds[] = "attachedWorkerIds"; static const char kAttachedSessionIds[] = "attachedSessionIds";
}; };
namespace { int InspectorWorkerAgent::s_last_connection_ = 0;
// TODO(dgozman): support multiple sessions in protocol.
static const int kSessionId = 1;
} // namespace
InspectorWorkerAgent::InspectorWorkerAgent(InspectedFrames* inspected_frames) InspectorWorkerAgent::InspectorWorkerAgent(InspectedFrames* inspected_frames)
: inspected_frames_(inspected_frames) {} : inspected_frames_(inspected_frames) {}
...@@ -60,10 +58,10 @@ void InspectorWorkerAgent::Restore() { ...@@ -60,10 +58,10 @@ void InspectorWorkerAgent::Restore() {
if (!AutoAttachEnabled()) if (!AutoAttachEnabled())
return; return;
instrumenting_agents_->addInspectorWorkerAgent(this); instrumenting_agents_->addInspectorWorkerAgent(this);
protocol::DictionaryValue* attached = AttachedWorkerIds(); protocol::DictionaryValue* attached = AttachedSessionIds();
for (size_t i = 0; i < attached->size(); ++i) for (size_t i = 0; i < attached->size(); ++i)
GetFrontend()->detachedFromTarget(attached->at(i).first); GetFrontend()->detachedFromTarget(attached->at(i).first);
state_->remove(WorkerAgentState::kAttachedWorkerIds); state_->remove(WorkerAgentState::kAttachedSessionIds);
ConnectToAllProxies(); ConnectToAllProxies();
} }
...@@ -74,7 +72,7 @@ Response InspectorWorkerAgent::disable() { ...@@ -74,7 +72,7 @@ Response InspectorWorkerAgent::disable() {
} }
state_->setBoolean(WorkerAgentState::kAutoAttach, false); state_->setBoolean(WorkerAgentState::kAutoAttach, false);
state_->setBoolean(WorkerAgentState::kWaitForDebuggerOnStart, false); state_->setBoolean(WorkerAgentState::kWaitForDebuggerOnStart, false);
state_->remove(WorkerAgentState::kAttachedWorkerIds); state_->remove(WorkerAgentState::kAttachedSessionIds);
return Response::OK(); return Response::OK();
} }
...@@ -104,13 +102,33 @@ bool InspectorWorkerAgent::AutoAttachEnabled() { ...@@ -104,13 +102,33 @@ bool InspectorWorkerAgent::AutoAttachEnabled() {
return state_->booleanProperty(WorkerAgentState::kAutoAttach, false); return state_->booleanProperty(WorkerAgentState::kAutoAttach, false);
} }
Response InspectorWorkerAgent::sendMessageToTarget(const String& target_id, Response InspectorWorkerAgent::sendMessageToTarget(const String& message,
const String& message) { Maybe<String> session_id,
WorkerInspectorProxy* proxy = connected_proxies_.at(target_id); Maybe<String> target_id) {
if (!proxy) if (session_id.isJust()) {
return Response::Error("Not attached to a target with given id"); auto it = session_id_to_connection_.find(session_id.fromJust());
proxy->SendMessageToInspector(kSessionId, message); if (it == session_id_to_connection_.end())
return Response::OK(); return Response::Error("No session with given id");
WorkerInspectorProxy* proxy = connected_proxies_.at(it->value);
proxy->SendMessageToInspector(it->value, message);
return Response::OK();
}
if (target_id.isJust()) {
int connection = 0;
for (auto& it : connected_proxies_) {
if (it.value->InspectorId() == target_id.fromJust()) {
if (connection)
return Response::Error("Multiple sessions attached, specify id");
connection = it.key;
}
}
if (!connection)
return Response::Error("No target with given id");
WorkerInspectorProxy* proxy = connected_proxies_.at(connection);
proxy->SendMessageToInspector(connection, message);
return Response::OK();
}
return Response::Error("Session id must be specified");
} }
void InspectorWorkerAgent::SetTracingSessionId( void InspectorWorkerAgent::SetTracingSessionId(
...@@ -138,12 +156,20 @@ void InspectorWorkerAgent::DidStartWorker(WorkerInspectorProxy* proxy, ...@@ -138,12 +156,20 @@ void InspectorWorkerAgent::DidStartWorker(WorkerInspectorProxy* proxy,
void InspectorWorkerAgent::WorkerTerminated(WorkerInspectorProxy* proxy) { void InspectorWorkerAgent::WorkerTerminated(WorkerInspectorProxy* proxy) {
DCHECK(GetFrontend() && AutoAttachEnabled()); DCHECK(GetFrontend() && AutoAttachEnabled());
if (connected_proxies_.find(proxy->InspectorId()) == connected_proxies_.end()) Vector<String> session_ids;
return; for (auto& it : session_id_to_connection_) {
AttachedWorkerIds()->remove(proxy->InspectorId()); if (connected_proxies_.at(it.value) == proxy)
GetFrontend()->detachedFromTarget(proxy->InspectorId()); session_ids.push_back(it.key);
proxy->DisconnectFromInspector(kSessionId, this); }
connected_proxies_.erase(proxy->InspectorId()); for (const String& session_id : session_ids) {
AttachedSessionIds()->remove(session_id);
GetFrontend()->detachedFromTarget(session_id, proxy->InspectorId());
int connection = session_id_to_connection_.at(session_id);
proxy->DisconnectFromInspector(connection, this);
connected_proxies_.erase(connection);
connection_to_session_id_.erase(connection);
session_id_to_connection_.erase(session_id);
}
} }
void InspectorWorkerAgent::ConnectToAllProxies() { void InspectorWorkerAgent::ConnectToAllProxies() {
...@@ -152,19 +178,23 @@ void InspectorWorkerAgent::ConnectToAllProxies() { ...@@ -152,19 +178,23 @@ void InspectorWorkerAgent::ConnectToAllProxies() {
DCHECK(proxy->GetExecutionContext()->IsDocument()); DCHECK(proxy->GetExecutionContext()->IsDocument());
Document* document = ToDocument(proxy->GetExecutionContext()); Document* document = ToDocument(proxy->GetExecutionContext());
if (document->GetFrame() && if (document->GetFrame() &&
inspected_frames_->Contains(document->GetFrame())) inspected_frames_->Contains(document->GetFrame())) {
ConnectToProxy(proxy, false); ConnectToProxy(proxy, false);
}
} }
} }
void InspectorWorkerAgent::DisconnectFromAllProxies(bool report_to_frontend) { void InspectorWorkerAgent::DisconnectFromAllProxies(bool report_to_frontend) {
for (auto& id_proxy : connected_proxies_) { for (auto& it : session_id_to_connection_) {
WorkerInspectorProxy* proxy = connected_proxies_.at(it.value);
if (report_to_frontend) { if (report_to_frontend) {
AttachedWorkerIds()->remove(id_proxy.key); AttachedSessionIds()->remove(it.key);
GetFrontend()->detachedFromTarget(id_proxy.key); GetFrontend()->detachedFromTarget(it.key, proxy->InspectorId());
} }
id_proxy.value->DisconnectFromInspector(kSessionId, this); proxy->DisconnectFromInspector(it.value, this);
} }
connection_to_session_id_.clear();
session_id_to_connection_.clear();
connected_proxies_.clear(); connected_proxies_.clear();
} }
...@@ -175,33 +205,36 @@ void InspectorWorkerAgent::DidCommitLoadForLocalFrame(LocalFrame* frame) { ...@@ -175,33 +205,36 @@ void InspectorWorkerAgent::DidCommitLoadForLocalFrame(LocalFrame* frame) {
// During navigation workers from old page may die after a while. // During navigation workers from old page may die after a while.
// Usually, it's fine to report them terminated later, but some tests // Usually, it's fine to report them terminated later, but some tests
// expect strict set of workers, and we reuse renderer between tests. // expect strict set of workers, and we reuse renderer between tests.
for (auto& id_proxy : connected_proxies_) { DisconnectFromAllProxies(true);
AttachedWorkerIds()->remove(id_proxy.key);
GetFrontend()->detachedFromTarget(id_proxy.key);
id_proxy.value->DisconnectFromInspector(kSessionId, this);
}
connected_proxies_.clear();
} }
protocol::DictionaryValue* InspectorWorkerAgent::AttachedWorkerIds() { protocol::DictionaryValue* InspectorWorkerAgent::AttachedSessionIds() {
protocol::DictionaryValue* ids = protocol::DictionaryValue* ids =
state_->getObject(WorkerAgentState::kAttachedWorkerIds); state_->getObject(WorkerAgentState::kAttachedSessionIds);
if (!ids) { if (!ids) {
std::unique_ptr<protocol::DictionaryValue> new_ids = std::unique_ptr<protocol::DictionaryValue> new_ids =
protocol::DictionaryValue::create(); protocol::DictionaryValue::create();
ids = new_ids.get(); ids = new_ids.get();
state_->setObject(WorkerAgentState::kAttachedWorkerIds, std::move(new_ids)); state_->setObject(WorkerAgentState::kAttachedSessionIds,
std::move(new_ids));
} }
return ids; return ids;
} }
void InspectorWorkerAgent::ConnectToProxy(WorkerInspectorProxy* proxy, void InspectorWorkerAgent::ConnectToProxy(WorkerInspectorProxy* proxy,
bool waiting_for_debugger) { bool waiting_for_debugger) {
connected_proxies_.Set(proxy->InspectorId(), proxy); int connection = ++s_last_connection_;
proxy->ConnectToInspector(kSessionId, this); connected_proxies_.Set(connection, proxy);
String session_id = proxy->InspectorId() + "-" + String::Number(connection);
session_id_to_connection_.Set(session_id, connection);
connection_to_session_id_.Set(connection, session_id);
proxy->ConnectToInspector(connection, this);
DCHECK(GetFrontend()); DCHECK(GetFrontend());
AttachedWorkerIds()->setBoolean(proxy->InspectorId(), true); AttachedSessionIds()->setBoolean(session_id, true);
GetFrontend()->attachedToTarget(protocol::Target::TargetInfo::create() GetFrontend()->attachedToTarget(session_id,
protocol::Target::TargetInfo::create()
.setTargetId(proxy->InspectorId()) .setTargetId(proxy->InspectorId())
.setType("worker") .setType("worker")
.setTitle(proxy->Url()) .setTitle(proxy->Url())
...@@ -213,10 +246,13 @@ void InspectorWorkerAgent::ConnectToProxy(WorkerInspectorProxy* proxy, ...@@ -213,10 +246,13 @@ void InspectorWorkerAgent::ConnectToProxy(WorkerInspectorProxy* proxy,
void InspectorWorkerAgent::DispatchMessageFromWorker( void InspectorWorkerAgent::DispatchMessageFromWorker(
WorkerInspectorProxy* proxy, WorkerInspectorProxy* proxy,
int session_id, int connection,
const String& message) { const String& message) {
DCHECK(session_id == kSessionId); auto it = connection_to_session_id_.find(connection);
GetFrontend()->receivedMessageFromTarget(proxy->InspectorId(), message); if (it == connection_to_session_id_.end())
return;
GetFrontend()->receivedMessageFromTarget(it->value, message,
proxy->InspectorId());
} }
DEFINE_TRACE(InspectorWorkerAgent) { DEFINE_TRACE(InspectorWorkerAgent) {
......
...@@ -65,8 +65,10 @@ class CORE_EXPORT InspectorWorkerAgent final ...@@ -65,8 +65,10 @@ class CORE_EXPORT InspectorWorkerAgent final
protocol::Response setAutoAttach(bool auto_attach, protocol::Response setAutoAttach(bool auto_attach,
bool wait_for_debugger_on_start) override; bool wait_for_debugger_on_start) override;
protocol::Response setAttachToFrames(bool attach) override; protocol::Response setAttachToFrames(bool attach) override;
protocol::Response sendMessageToTarget(const String& target_id, protocol::Response sendMessageToTarget(
const String& message) override; const String& message,
protocol::Maybe<String> session_id,
protocol::Maybe<String> target_id) override;
void SetTracingSessionId(const String&); void SetTracingSessionId(const String&);
...@@ -75,16 +77,19 @@ class CORE_EXPORT InspectorWorkerAgent final ...@@ -75,16 +77,19 @@ class CORE_EXPORT InspectorWorkerAgent final
void ConnectToAllProxies(); void ConnectToAllProxies();
void DisconnectFromAllProxies(bool report_to_frontend); void DisconnectFromAllProxies(bool report_to_frontend);
void ConnectToProxy(WorkerInspectorProxy*, bool waiting_for_debugger); void ConnectToProxy(WorkerInspectorProxy*, bool waiting_for_debugger);
protocol::DictionaryValue* AttachedWorkerIds(); protocol::DictionaryValue* AttachedSessionIds();
// WorkerInspectorProxy::PageInspector implementation. // WorkerInspectorProxy::PageInspector implementation.
void DispatchMessageFromWorker(WorkerInspectorProxy*, void DispatchMessageFromWorker(WorkerInspectorProxy*,
int session_id, int connection,
const String& message) override; const String& message) override;
Member<InspectedFrames> inspected_frames_; Member<InspectedFrames> inspected_frames_;
HeapHashMap<String, Member<WorkerInspectorProxy>> connected_proxies_; HeapHashMap<int, Member<WorkerInspectorProxy>> connected_proxies_;
HashMap<int, String> connection_to_session_id_;
HashMap<String, int> session_id_to_connection_;
String tracing_session_id_; String tracing_session_id_;
static int s_last_connection_;
}; };
} // namespace blink } // namespace blink
......
...@@ -3601,6 +3601,11 @@ ...@@ -3601,6 +3601,11 @@
"id": "TargetID", "id": "TargetID",
"type": "string" "type": "string"
}, },
{
"id": "SessionID",
"type": "string",
"description": "Unique identifier of attached debugging session."
},
{ {
"id": "BrowserContextID", "id": "BrowserContextID",
"type": "string" "type": "string"
...@@ -3656,10 +3661,11 @@ ...@@ -3656,10 +3661,11 @@
}, },
{ {
"name": "sendMessageToTarget", "name": "sendMessageToTarget",
"description": "Sends protocol message to the target with given id.", "description": "Sends protocol message over session with given id.",
"parameters": [ "parameters": [
{ "name": "targetId", "$ref": "TargetID" }, { "name": "message", "type": "string" },
{ "name": "message", "type": "string" } { "name": "sessionId", "$ref": "SessionID", "optional": true, "description": "Identifier of the session." },
{ "name": "targetId", "$ref": "TargetID", "optional": true, "deprecated": true, "description": "Deprecated." }
] ]
}, },
{ {
...@@ -3696,14 +3702,15 @@ ...@@ -3696,14 +3702,15 @@
{ "name": "targetId", "$ref": "TargetID" } { "name": "targetId", "$ref": "TargetID" }
], ],
"returns": [ "returns": [
{ "name": "success", "type": "boolean", "description": "Whether attach succeeded." } { "name": "sessionId", "$ref": "SessionID", "description": "Id assigned to the session." }
] ]
}, },
{ {
"name": "detachFromTarget", "name": "detachFromTarget",
"description": "Detaches from the target with given id.", "description": "Detaches session with given id.",
"parameters": [ "parameters": [
{ "name": "targetId", "$ref": "TargetID" } { "name": "sessionId", "$ref": "SessionID", "optional": true, "description": "Session to detach." },
{ "name": "targetId", "$ref": "TargetID", "optional": true, "deprecated": true, "description": "Deprecated." }
] ]
}, },
{ {
...@@ -3770,23 +3777,26 @@ ...@@ -3770,23 +3777,26 @@
"name": "attachedToTarget", "name": "attachedToTarget",
"description": "Issued when attached to target because of auto-attach or <code>attachToTarget</code> command.", "description": "Issued when attached to target because of auto-attach or <code>attachToTarget</code> command.",
"parameters": [ "parameters": [
{ "name": "sessionId", "$ref": "SessionID", "description": "Identifier assigned to the session used to send/receive messages." },
{ "name": "targetInfo", "$ref": "TargetInfo" }, { "name": "targetInfo", "$ref": "TargetInfo" },
{ "name": "waitingForDebugger", "type": "boolean" } { "name": "waitingForDebugger", "type": "boolean" }
] ]
}, },
{ {
"name": "detachedFromTarget", "name": "detachedFromTarget",
"description": "Issued when detached from target for any reason (including <code>detachFromTarget</code> command).", "description": "Issued when detached from target for any reason (including <code>detachFromTarget</code> command). Can be issued multiple times per target if multiple sessions have been attached to it.",
"parameters": [ "parameters": [
{ "name": "targetId", "$ref": "TargetID" } { "name": "sessionId", "$ref": "SessionID", "description": "Detached session identifier." },
{ "name": "targetId", "$ref": "TargetID", "optional": true, "deprecated": true, "description": "Deprecated." }
] ]
}, },
{ {
"name": "receivedMessageFromTarget", "name": "receivedMessageFromTarget",
"description": "Notifies about new protocol message from attached target.", "description": "Notifies about a new protocol message received from the session (as reported in <code>attachedToTarget</code> event).",
"parameters": [ "parameters": [
{ "name": "targetId", "$ref": "TargetID" }, { "name": "sessionId", "$ref": "SessionID", "description": "Identifier of a session which sends a message." },
{ "name": "message", "type": "string" } { "name": "message", "type": "string" },
{ "name": "targetId", "$ref": "TargetID", "optional": true, "deprecated": true, "description": "Deprecated." }
] ]
} }
] ]
......
...@@ -457,10 +457,8 @@ SDK.ChildTargetManager = class { ...@@ -457,10 +457,8 @@ SDK.ChildTargetManager = class {
InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this); InspectorFrontendHostAPI.Events.DevicesDiscoveryConfigChanged, this._devicesDiscoveryConfigChanged, this);
} }
// TODO(dgozman): this is O(n^2) when removing main target. for (var sessionId of this._childConnections.keys())
var childTargets = this._targetManager._targets.filter(child => child.parentTarget() === this._parentTarget); this.detachedFromTarget(sessionId, undefined);
for (var child of childTargets)
this.detachedFromTarget(child.id());
} }
/** /**
...@@ -534,10 +532,11 @@ SDK.ChildTargetManager = class { ...@@ -534,10 +532,11 @@ SDK.ChildTargetManager = class {
/** /**
* @override * @override
* @param {string} sessionId
* @param {!Protocol.Target.TargetInfo} targetInfo * @param {!Protocol.Target.TargetInfo} targetInfo
* @param {boolean} waitingForDebugger * @param {boolean} waitingForDebugger
*/ */
attachedToTarget(targetInfo, waitingForDebugger) { attachedToTarget(sessionId, targetInfo, waitingForDebugger) {
var targetName = ''; var targetName = '';
if (targetInfo.type === 'node') { if (targetInfo.type === 'node') {
targetName = Common.UIString('Node.js: %s', targetInfo.url); targetName = Common.UIString('Node.js: %s', targetInfo.url);
...@@ -548,7 +547,7 @@ SDK.ChildTargetManager = class { ...@@ -548,7 +547,7 @@ SDK.ChildTargetManager = class {
} }
var target = this._targetManager.createTarget( var target = this._targetManager.createTarget(
targetInfo.targetId, targetName, this._capabilitiesForType(targetInfo.type), targetInfo.targetId, targetName, this._capabilitiesForType(targetInfo.type),
this._createChildConnection.bind(this, this._targetAgent, targetInfo.targetId), this._parentTarget); this._createChildConnection.bind(this, this._targetAgent, sessionId), this._parentTarget);
// Only pause the new worker if debugging SW - we are going through the pause on start checkbox. // Only pause the new worker if debugging SW - we are going through the pause on start checkbox.
if (!this._parentTarget.parentTarget() && Runtime.queryParam('isSharedWorker') && waitingForDebugger) { if (!this._parentTarget.parentTarget() && Runtime.queryParam('isSharedWorker') && waitingForDebugger) {
...@@ -564,33 +563,35 @@ SDK.ChildTargetManager = class { ...@@ -564,33 +563,35 @@ SDK.ChildTargetManager = class {
/** /**
* @override * @override
* @param {string} childTargetId * @param {string} sessionId
* @param {string=} childTargetId
*/ */
detachedFromTarget(childTargetId) { detachedFromTarget(sessionId, childTargetId) {
this._childConnections.get(childTargetId)._onDisconnect.call(null, 'target terminated'); this._childConnections.get(sessionId)._onDisconnect.call(null, 'target terminated');
this._childConnections.delete(childTargetId); this._childConnections.delete(sessionId);
} }
/** /**
* @override * @override
* @param {string} childTargetId * @param {string} sessionId
* @param {string} message * @param {string} message
* @param {string=} childTargetId
*/ */
receivedMessageFromTarget(childTargetId, message) { receivedMessageFromTarget(sessionId, message, childTargetId) {
var connection = this._childConnections.get(childTargetId); var connection = this._childConnections.get(sessionId);
if (connection) if (connection)
connection._onMessage.call(null, message); connection._onMessage.call(null, message);
} }
/** /**
* @param {!Protocol.TargetAgent} agent * @param {!Protocol.TargetAgent} agent
* @param {string} childTargetId * @param {string} sessionId
* @param {!Protocol.InspectorBackend.Connection.Params} params * @param {!Protocol.InspectorBackend.Connection.Params} params
* @return {!Protocol.InspectorBackend.Connection} * @return {!Protocol.InspectorBackend.Connection}
*/ */
_createChildConnection(agent, childTargetId, params) { _createChildConnection(agent, sessionId, params) {
var connection = new SDK.ChildConnection(agent, childTargetId, params); var connection = new SDK.ChildConnection(agent, sessionId, params);
this._childConnections.set(childTargetId, connection); this._childConnections.set(sessionId, connection);
return connection; return connection;
} }
}; };
...@@ -601,12 +602,12 @@ SDK.ChildTargetManager = class { ...@@ -601,12 +602,12 @@ SDK.ChildTargetManager = class {
SDK.ChildConnection = class { SDK.ChildConnection = class {
/** /**
* @param {!Protocol.TargetAgent} agent * @param {!Protocol.TargetAgent} agent
* @param {string} targetId * @param {string} sessionId
* @param {!Protocol.InspectorBackend.Connection.Params} params * @param {!Protocol.InspectorBackend.Connection.Params} params
*/ */
constructor(agent, targetId, params) { constructor(agent, sessionId, params) {
this._agent = agent; this._agent = agent;
this._targetId = targetId; this._sessionId = sessionId;
this._onMessage = params.onMessage; this._onMessage = params.onMessage;
this._onDisconnect = params.onDisconnect; this._onDisconnect = params.onDisconnect;
} }
...@@ -616,7 +617,7 @@ SDK.ChildConnection = class { ...@@ -616,7 +617,7 @@ SDK.ChildConnection = class {
* @param {string} message * @param {string} message
*/ */
sendMessage(message) { sendMessage(message) {
this._agent.sendMessageToTarget(this._targetId, message); this._agent.sendMessageToTarget(message, this._sessionId);
} }
/** /**
......
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