[DevTools] Implement mojom::DevToolsAgent for workers

1) Use blink::DevToolsAgent in WorkerInspectorController.
This replaces the ad-hoc interface for communicating with worker's debugger with
a mojo interface used for frames and shared/service worker's shadow pages.

2) Create WorkerDevToolsAgentHost. This is similar to other
agent hosts, keeps itself alive while the corresponding worker is alive,
and reuses DevToolsSession machinery for inspection.

3) Report dedicated workers to the browser process when auto attach is on.
mojom::DevToolsAgentHost is now notified about child workers and gets
their DevToolsAgent interfaces to debug in the future.

4) Add TargetHandler to service/shared/dedicated worker sessions, to handle
communication with nested dedicated workers.

5) Retire WorkerInspectorProxy and ExecutionContextWorkerRegistry.
These are covered by DevToolsAgent now, which reports to it's host.

6) Retire InspectorWorkerAgent, which is replaced by WorkerDevToolsAgentHost
on the browser side.

The benefits are:
- unified interface for inspecting any entity including workers;
- workers now support flatten mode of operations;
- all inspection targets are now listed on the browser side and
  represented with DevToolsAgentHost, which allows for further
  simplification;
- less abstractions - we can even get rid of InspectorSession now.

Bug: 775132

Change-Id: Ib4f58677a81ce48d4c2382f05d1166f730a2e2c3
Reviewed-on: https://chromium-review.googlesource.com/c/1183589
Commit-Queue: Dmitry Gozman <[email protected]>
Reviewed-by: Kinuko Yasuda <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: Andrey Kosyakov <[email protected]>
Reviewed-by: Hiroki Nakagawa <[email protected]>
Reviewed-by: Aleksey Kozyatinskiy <[email protected]>
Reviewed-by: Pavel Feldman <[email protected]>
Cr-Commit-Position: refs/heads/master@{#603652}
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index 210ef3a..9d46d3e 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -79,7 +79,8 @@
   }
   session->SetBrowserOnly(true);
   session->AddHandler(std::make_unique<protocol::TargetHandler>(
-      protocol::TargetHandler::AccessMode::kBrowser, GetId(), registry));
+      protocol::TargetHandler::AccessMode::kBrowser, GetId(),
+      GetRendererChannel(), registry));
   if (only_discovery_)
     return true;
 
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 2c78d0f..2dc1f1d 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -40,6 +40,7 @@
 
 const char DevToolsAgentHost::kTypePage[] = "page";
 const char DevToolsAgentHost::kTypeFrame[] = "iframe";
+const char DevToolsAgentHost::kTypeDedicatedWorker[] = "worker";
 const char DevToolsAgentHost::kTypeSharedWorker[] = "shared_worker";
 const char DevToolsAgentHost::kTypeServiceWorker[] = "service_worker";
 const char DevToolsAgentHost::kTypeBrowser[] = "browser";
@@ -73,6 +74,8 @@
   for (const auto& host : service_list)
     result.push_back(host);
 
+  // TODO(dgozman): we should add dedicated workers here, but clients are not
+  // ready.
   RenderFrameDevToolsAgentHost::AddAllAgentHosts(&result);
 
 #if DCHECK_IS_ON()
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 46823e3a..ac21296 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -12,6 +12,7 @@
 #include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
+#include "base/macros.h"
 #include "base/process/kill.h"
 #include "content/browser/devtools/devtools_io_context.h"
 #include "content/browser/devtools/devtools_renderer_channel.h"
@@ -19,7 +20,6 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/devtools_agent_host.h"
-#include "third_party/blink/public/web/devtools_agent.mojom.h"
 
 namespace content {
 
@@ -114,6 +114,8 @@
   DevToolsIOContext io_context_;
   DevToolsRendererChannel renderer_channel_;
   static int s_force_creation_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsAgentHostImpl);
 };
 
 }  // namespace content
diff --git a/content/browser/devtools/devtools_renderer_channel.cc b/content/browser/devtools/devtools_renderer_channel.cc
index bd09fc1..23cd857 100644
--- a/content/browser/devtools/devtools_renderer_channel.cc
+++ b/content/browser/devtools/devtools_renderer_channel.cc
@@ -7,6 +7,9 @@
 #include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/protocol/devtools_domain_handler.h"
+#include "content/browser/devtools/protocol/target_auto_attacher.h"
+#include "content/browser/devtools/worker_devtools_agent_host.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/common/child_process_host.h"
 #include "ui/gfx/geometry/point.h"
 
@@ -15,43 +18,136 @@
 DevToolsRendererChannel::DevToolsRendererChannel(DevToolsAgentHostImpl* owner)
     : owner_(owner),
       binding_(this),
-      process_id_(ChildProcessHost::kInvalidUniqueID) {}
+      associated_binding_(this),
+      process_id_(ChildProcessHost::kInvalidUniqueID),
+      weak_factory_(this) {}
 
 DevToolsRendererChannel::~DevToolsRendererChannel() = default;
 
 void DevToolsRendererChannel::SetRenderer(
+    blink::mojom::DevToolsAgentPtr agent_ptr,
+    blink::mojom::DevToolsAgentHostRequest host_request,
+    int process_id,
+    RenderFrameHostImpl* frame_host) {
+  CleanupConnection();
+  agent_ptr_ = std::move(agent_ptr);
+  if (host_request)
+    binding_.Bind(std::move(host_request));
+  SetRendererInternal(agent_ptr_.get(), process_id, frame_host);
+}
+
+void DevToolsRendererChannel::SetRendererAssociated(
     blink::mojom::DevToolsAgentAssociatedPtr agent_ptr,
     blink::mojom::DevToolsAgentHostAssociatedRequest host_request,
     int process_id,
     RenderFrameHostImpl* frame_host) {
-  binding_.Close();
+  CleanupConnection();
+  associated_agent_ptr_ = std::move(agent_ptr);
   if (host_request)
-    binding_.Bind(std::move(host_request));
-  agent_ptr_ = std::move(agent_ptr);
+    associated_binding_.Bind(std::move(host_request));
+  SetRendererInternal(associated_agent_ptr_.get(), process_id, frame_host);
+}
+
+void DevToolsRendererChannel::CleanupConnection() {
+  binding_.Close();
+  associated_binding_.Close();
+  associated_agent_ptr_ = nullptr;
+  agent_ptr_ = nullptr;
+}
+
+void DevToolsRendererChannel::SetRendererInternal(
+    blink::mojom::DevToolsAgent* agent,
+    int process_id,
+    RenderFrameHostImpl* frame_host) {
   process_id_ = process_id;
   frame_host_ = frame_host;
+  if (agent && !report_attachers_.empty()) {
+    agent->ReportChildWorkers(true /* report */,
+                              !wait_for_debugger_attachers_.empty());
+  }
   for (DevToolsSession* session : owner_->sessions()) {
     for (auto& pair : session->handlers())
       pair.second->SetRenderer(process_id_, frame_host_);
-    session->AttachToAgent(agent_ptr_.get());
+    session->AttachToAgent(agent);
   }
 }
 
 void DevToolsRendererChannel::AttachSession(DevToolsSession* session) {
-  if (!agent_ptr_)
+  if (!agent_ptr_ && !associated_agent_ptr_)
     owner_->UpdateRendererChannel(true /* force */);
   for (auto& pair : session->handlers())
     pair.second->SetRenderer(process_id_, frame_host_);
-  session->AttachToAgent(agent_ptr_.get());
+  if (agent_ptr_)
+    session->AttachToAgent(agent_ptr_.get());
+  else if (associated_agent_ptr_)
+    session->AttachToAgent(associated_agent_ptr_.get());
 }
 
 void DevToolsRendererChannel::InspectElement(const gfx::Point& point) {
-  if (!agent_ptr_)
+  if (!agent_ptr_ && !associated_agent_ptr_)
     owner_->UpdateRendererChannel(true /* force */);
-  // Previous call might update |agent_ptr_|
-  // via SetRenderer(), so we should check it again.
+  // Previous call might update |agent_ptr_| or |associated_agent_ptr_|
+  // via SetRenderer(), so we should check them again.
   if (agent_ptr_)
     agent_ptr_->InspectElement(point);
+  else if (associated_agent_ptr_)
+    associated_agent_ptr_->InspectElement(point);
+}
+
+void DevToolsRendererChannel::SetReportChildWorkers(
+    protocol::TargetAutoAttacher* attacher,
+    bool report,
+    bool wait_for_debugger) {
+  if (report) {
+    if (report_attachers_.find(attacher) == report_attachers_.end()) {
+      report_attachers_.insert(attacher);
+      for (DevToolsAgentHostImpl* host : child_workers_)
+        attacher->ChildWorkerCreated(host, false /* waiting_for_debugger */);
+    }
+  } else {
+    report_attachers_.erase(attacher);
+  }
+  if (wait_for_debugger)
+    wait_for_debugger_attachers_.insert(attacher);
+  else
+    wait_for_debugger_attachers_.erase(attacher);
+  if (agent_ptr_) {
+    agent_ptr_->ReportChildWorkers(!report_attachers_.empty(),
+                                   !wait_for_debugger_attachers_.empty());
+  } else if (associated_agent_ptr_) {
+    associated_agent_ptr_->ReportChildWorkers(
+        !report_attachers_.empty(), !wait_for_debugger_attachers_.empty());
+  }
+}
+
+void DevToolsRendererChannel::ChildWorkerCreated(
+    blink::mojom::DevToolsAgentPtr worker_devtools_agent,
+    blink::mojom::DevToolsAgentHostRequest host_request,
+    const GURL& url,
+    const base::UnguessableToken& devtools_worker_token,
+    bool waiting_for_debugger) {
+  if (content::DevToolsAgentHost::GetForId(devtools_worker_token.ToString())) {
+    mojo::ReportBadMessage("Workers should have unique tokens.");
+    return;
+  }
+  RenderProcessHost* process = RenderProcessHost::FromID(process_id_);
+  if (!process)
+    return;
+  GURL filtered_url = url;
+  process->FilterURL(true /* empty_allowed */, &filtered_url);
+  auto agent_host = base::MakeRefCounted<WorkerDevToolsAgentHost>(
+      process_id_, std::move(worker_devtools_agent), std::move(host_request),
+      filtered_url, devtools_worker_token, owner_->GetId(),
+      base::BindOnce(&DevToolsRendererChannel::ChildWorkerDestroyed,
+                     weak_factory_.GetWeakPtr()));
+  child_workers_.insert(agent_host.get());
+  for (protocol::TargetAutoAttacher* attacher : report_attachers_)
+    attacher->ChildWorkerCreated(agent_host.get(), waiting_for_debugger);
+}
+
+void DevToolsRendererChannel::ChildWorkerDestroyed(
+    DevToolsAgentHostImpl* host) {
+  child_workers_.erase(host);
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/devtools_renderer_channel.h b/content/browser/devtools/devtools_renderer_channel.h
index 1e39045..10ec64a 100644
--- a/content/browser/devtools/devtools_renderer_channel.h
+++ b/content/browser/devtools/devtools_renderer_channel.h
@@ -5,7 +5,9 @@
 #ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_RENDERER_CHANNEL_H_
 #define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_RENDERER_CHANNEL_H_
 
+#include "base/containers/flat_set.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -21,9 +23,14 @@
 class DevToolsSession;
 class RenderFrameHostImpl;
 
+namespace protocol {
+class TargetAutoAttacher;
+}
+
 // This class encapsulates a connection to blink::mojom::DevToolsAgent
-// in the renderer.
-// When the renderer changes, different DevToolsAgentHostImpl subclasses
+// in the renderer (either RenderFrame or some kind of worker).
+// When the renderer changes (e.g. worker restarts or a new RenderFrame
+// is used for the frame), different DevToolsAgentHostImpl subclasses
 // retrieve a new blink::mojom::DevToolsAgent pointer, and this channel
 // starts using it for all existing and future sessions.
 class CONTENT_EXPORT DevToolsRendererChannel
@@ -32,7 +39,14 @@
   explicit DevToolsRendererChannel(DevToolsAgentHostImpl* owner);
   ~DevToolsRendererChannel() override;
 
-  void SetRenderer(
+  // Dedicated workers use non-associated version,
+  // while frames and other workers use DevToolsAgent associated
+  // with respective control interfraces. See mojom for details.
+  void SetRenderer(blink::mojom::DevToolsAgentPtr agent_ptr,
+                   blink::mojom::DevToolsAgentHostRequest host_request,
+                   int process_id,
+                   RenderFrameHostImpl* frame_host);
+  void SetRendererAssociated(
       blink::mojom::DevToolsAgentAssociatedPtr agent_ptr,
       blink::mojom::DevToolsAgentHostAssociatedRequest host_request,
       int process_id,
@@ -40,12 +54,35 @@
   void AttachSession(DevToolsSession* session);
   void InspectElement(const gfx::Point& point);
 
+  void SetReportChildWorkers(protocol::TargetAutoAttacher* attacher,
+                             bool report,
+                             bool wait_for_debugger);
+
  private:
+  // blink::mojom::DevToolsAgentHost implementation.
+  void ChildWorkerCreated(blink::mojom::DevToolsAgentPtr worker_devtools_agent,
+                          blink::mojom::DevToolsAgentHostRequest host_request,
+                          const GURL& url,
+                          const base::UnguessableToken& devtools_worker_token,
+                          bool waiting_for_debugger) override;
+  void ChildWorkerDestroyed(DevToolsAgentHostImpl*);
+
+  void CleanupConnection();
+  void SetRendererInternal(blink::mojom::DevToolsAgent* agent,
+                           int process_id,
+                           RenderFrameHostImpl* frame_host);
+
   DevToolsAgentHostImpl* owner_;
-  mojo::AssociatedBinding<blink::mojom::DevToolsAgentHost> binding_;
-  blink::mojom::DevToolsAgentAssociatedPtr agent_ptr_;
+  mojo::Binding<blink::mojom::DevToolsAgentHost> binding_;
+  mojo::AssociatedBinding<blink::mojom::DevToolsAgentHost> associated_binding_;
+  blink::mojom::DevToolsAgentPtr agent_ptr_;
+  blink::mojom::DevToolsAgentAssociatedPtr associated_agent_ptr_;
   int process_id_;
   RenderFrameHostImpl* frame_host_ = nullptr;
+  base::flat_set<protocol::TargetAutoAttacher*> report_attachers_;
+  base::flat_set<protocol::TargetAutoAttacher*> wait_for_debugger_attachers_;
+  base::flat_set<DevToolsAgentHostImpl*> child_workers_;
+  base::WeakPtrFactory<DevToolsRendererChannel> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsRendererChannel);
 };
diff --git a/content/browser/devtools/protocol/target_auto_attacher.cc b/content/browser/devtools/protocol/target_auto_attacher.cc
index c194d82..21104799 100644
--- a/content/browser/devtools/protocol/target_auto_attacher.cc
+++ b/content/browser/devtools/protocol/target_auto_attacher.cc
@@ -5,6 +5,7 @@
 #include "content/browser/devtools/protocol/target_auto_attacher.h"
 
 #include "base/containers/queue.h"
+#include "content/browser/devtools/devtools_renderer_channel.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
 #include "content/browser/devtools/service_worker_devtools_agent_host.h"
 #include "content/browser/frame_host/frame_tree.h"
@@ -86,10 +87,13 @@
 
 }  // namespace
 
-TargetAutoAttacher::TargetAutoAttacher(AttachCallback attach_callback,
-                                       DetachCallback detach_callback)
+TargetAutoAttacher::TargetAutoAttacher(
+    AttachCallback attach_callback,
+    DetachCallback detach_callback,
+    DevToolsRendererChannel* renderer_channel)
     : attach_callback_(attach_callback),
       detach_callback_(detach_callback),
+      renderer_channel_(renderer_channel),
       render_frame_host_(nullptr),
       auto_attach_(false),
       wait_for_debugger_on_start_(false) {}
@@ -222,10 +226,8 @@
 void TargetAutoAttacher::SetAutoAttach(bool auto_attach,
                                        bool wait_for_debugger_on_start) {
   wait_for_debugger_on_start_ = wait_for_debugger_on_start;
-  if (auto_attach_ == auto_attach)
-    return;
-  auto_attach_ = auto_attach;
-  if (auto_attach_) {
+  if (auto_attach && !auto_attach_) {
+    auto_attach_ = true;
     auto_attaching_service_workers_ =
         render_frame_host_ && !render_frame_host_->GetParent();
     if (auto_attaching_service_workers_) {
@@ -233,7 +235,8 @@
       ReattachServiceWorkers(false);
     }
     UpdateFrames();
-  } else {
+  } else if (!auto_attach && auto_attach_) {
+    auto_attach_ = false;
     Hosts empty;
     ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeFrame, false);
     if (auto_attaching_service_workers_) {
@@ -242,8 +245,12 @@
                             false);
       auto_attaching_service_workers_ = false;
     }
+    ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeDedicatedWorker,
+                          false);
     DCHECK(auto_attached_hosts_.empty());
   }
+  renderer_channel_->SetReportChildWorkers(this, auto_attach,
+                                           wait_for_debugger_on_start);
 }
 
 // -------- ServiceWorkerDevToolsManager::Observer ----------
@@ -278,5 +285,11 @@
   ReattachServiceWorkers(false);
 }
 
+void TargetAutoAttacher::ChildWorkerCreated(DevToolsAgentHostImpl* agent_host,
+                                            bool waiting_for_debugger) {
+  attach_callback_.Run(agent_host, waiting_for_debugger);
+  auto_attached_hosts_.insert(scoped_refptr<DevToolsAgentHost>(agent_host));
+}
+
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol/target_auto_attacher.h b/content/browser/devtools/protocol/target_auto_attacher.h
index aa8d657f..32adaf3 100644
--- a/content/browser/devtools/protocol/target_auto_attacher.h
+++ b/content/browser/devtools/protocol/target_auto_attacher.h
@@ -11,6 +11,8 @@
 
 namespace content {
 
+class DevToolsAgentHostImpl;
+class DevToolsRendererChannel;
 class NavigationHandleImpl;
 class RenderFrameHostImpl;
 
@@ -19,11 +21,13 @@
 class TargetAutoAttacher : public ServiceWorkerDevToolsManager::Observer {
  public:
   // Second parameter is |waiting_for_debugger|, returns whether it succeeded.
-  using AttachCallback = base::Callback<void(DevToolsAgentHost*, bool)>;
-  using DetachCallback = base::Callback<void(DevToolsAgentHost*)>;
+  using AttachCallback =
+      base::RepeatingCallback<void(DevToolsAgentHost*, bool)>;
+  using DetachCallback = base::RepeatingCallback<void(DevToolsAgentHost*)>;
 
   TargetAutoAttacher(AttachCallback attach_callback,
-                     DetachCallback detach_callback);
+                     DetachCallback detach_callback,
+                     DevToolsRendererChannel* renderer_channel);
   ~TargetAutoAttacher() override;
 
   void SetRenderFrameHost(RenderFrameHostImpl* host);
@@ -34,6 +38,8 @@
 
   bool ShouldThrottleFramesNavigation();
   DevToolsAgentHost* AutoAttachToFrame(NavigationHandleImpl* navigation_handle);
+  void ChildWorkerCreated(DevToolsAgentHostImpl* agent_host,
+                          bool waiting_for_debugger);
 
  private:
   using Hosts = base::flat_set<scoped_refptr<DevToolsAgentHost>>;
@@ -54,6 +60,7 @@
 
   AttachCallback attach_callback_;
   DetachCallback detach_callback_;
+  DevToolsRendererChannel* renderer_channel_;
   RenderFrameHostImpl* render_frame_host_;
   base::flat_set<GURL> frame_urls_;
 
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 3e03ef91..39a632d 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -421,11 +421,14 @@
 
 TargetHandler::TargetHandler(AccessMode access_mode,
                              const std::string& owner_target_id,
+                             DevToolsRendererChannel* renderer_channel,
                              TargetRegistry* target_registry)
     : DevToolsDomainHandler(Target::Metainfo::domainName),
-      auto_attacher_(
-          base::Bind(&TargetHandler::AutoAttach, base::Unretained(this)),
-          base::Bind(&TargetHandler::AutoDetach, base::Unretained(this))),
+      auto_attacher_(base::BindRepeating(&TargetHandler::AutoAttach,
+                                         base::Unretained(this)),
+                     base::BindRepeating(&TargetHandler::AutoDetach,
+                                         base::Unretained(this)),
+                     renderer_channel),
       discover_(false),
       access_mode_(access_mode),
       owner_target_id_(owner_target_id),
@@ -494,17 +497,12 @@
 
 Response TargetHandler::FindSession(Maybe<std::string> session_id,
                                     Maybe<std::string> target_id,
-                                    Session** session,
-                                    bool fall_through) {
+                                    Session** session) {
   *session = nullptr;
-  fall_through &= access_mode_ != AccessMode::kBrowser;
   if (session_id.isJust()) {
     auto it = attached_sessions_.find(session_id.fromJust());
-    if (it == attached_sessions_.end()) {
-      if (fall_through)
-        return Response::FallThrough();
+    if (it == attached_sessions_.end())
       return Response::InvalidParams("No session with given id");
-    }
     *session = it->second.get();
     return Response::OK();
   }
@@ -516,15 +514,10 @@
         *session = it.second.get();
       }
     }
-    if (!*session) {
-      if (fall_through)
-        return Response::FallThrough();
+    if (!*session)
       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");
 }
 
@@ -556,8 +549,7 @@
   auto_attacher_.SetAutoAttach(auto_attach, wait_for_debugger_on_start);
   if (!auto_attacher_.ShouldThrottleFramesNavigation())
     ClearThrottles();
-  return access_mode_ == AccessMode::kBrowser ? Response::OK()
-                                              : Response::FallThrough();
+  return Response::OK();
 }
 
 Response TargetHandler::SetRemoteLocations(
@@ -600,7 +592,7 @@
     return Response::Error(kNotAllowedError);
   Session* session = nullptr;
   Response response =
-      FindSession(std::move(session_id), std::move(target_id), &session, false);
+      FindSession(std::move(session_id), std::move(target_id), &session);
   if (!response.isSuccess())
     return response;
   session->Detach(false);
@@ -612,7 +604,7 @@
                                             Maybe<std::string> target_id) {
   Session* session = nullptr;
   Response response =
-      FindSession(std::move(session_id), std::move(target_id), &session, true);
+      FindSession(std::move(session_id), std::move(target_id), &session);
   if (!response.isSuccess())
     return response;
   if (session->flatten_protocol_) {
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index d7e4494..c07c604 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -18,6 +18,7 @@
 namespace content {
 
 class DevToolsAgentHostImpl;
+class DevToolsRendererChannel;
 class NavigationHandle;
 class NavigationThrottle;
 class RenderFrameHostImpl;
@@ -41,6 +42,7 @@
   };
   TargetHandler(AccessMode access_mode,
                 const std::string& owner_target_id,
+                DevToolsRendererChannel* renderer_channel,
                 TargetRegistry* target_registry);
   ~TargetHandler() override;
 
@@ -52,7 +54,6 @@
   Response Disable() override;
 
   void DidCommitNavigation();
-  void RenderFrameHostChanged();
   std::unique_ptr<NavigationThrottle> CreateThrottleForNavigation(
       NavigationHandle* navigation_handle);
 
@@ -104,8 +105,7 @@
   void AutoDetach(DevToolsAgentHost* host);
   Response FindSession(Maybe<std::string> session_id,
                        Maybe<std::string> target_id,
-                       Session** session,
-                       bool fall_through);
+                       Session** session);
   void ClearThrottles();
 
   // DevToolsAgentHostObserver implementation.
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 96188ba..fce65eef 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -247,7 +247,7 @@
       session->client()->MayDiscoverTargets()
           ? protocol::TargetHandler::AccessMode::kRegular
           : protocol::TargetHandler::AccessMode::kAutoAttachOnly,
-      GetId(), registry)));
+      GetId(), GetRendererChannel(), registry)));
   session->AddHandler(base::WrapUnique(new protocol::PageHandler(
       emulation_handler, session->client()->MayAffectLocalFiles())));
   session->AddHandler(base::WrapUnique(new protocol::SecurityHandler()));
@@ -721,7 +721,7 @@
   }
   int process_id = frame_host_ ? frame_host_->GetProcess()->GetID()
                                : ChildProcessHost::kInvalidUniqueID;
-  GetRendererChannel()->SetRenderer(
+  GetRendererChannel()->SetRendererAssociated(
       std::move(agent_ptr), std::move(host_request), process_id, frame_host_);
 }
 
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.cc b/content/browser/devtools/service_worker_devtools_agent_host.cc
index c610a37..64621fd2 100644
--- a/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -12,6 +12,7 @@
 #include "content/browser/devtools/protocol/network_handler.h"
 #include "content/browser/devtools/protocol/protocol.h"
 #include "content/browser/devtools/protocol/schema_handler.h"
+#include "content/browser/devtools/protocol/target_handler.h"
 #include "content/browser/devtools/service_worker_devtools_manager.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_version.h"
@@ -124,6 +125,9 @@
   session->AddHandler(base::WrapUnique(new protocol::NetworkHandler(
       GetId(), devtools_worker_token_, GetIOContext())));
   session->AddHandler(base::WrapUnique(new protocol::SchemaHandler()));
+  session->AddHandler(std::make_unique<protocol::TargetHandler>(
+      protocol::TargetHandler::AccessMode::kAutoAttachOnly, GetId(),
+      GetRendererChannel(), registry));
   if (state_ == WORKER_READY && sessions().empty())
     UpdateIsAttached(true);
   return true;
@@ -142,9 +146,9 @@
   state_ = WORKER_READY;
   blink::mojom::DevToolsAgentAssociatedPtr agent_ptr;
   agent_ptr.Bind(std::move(devtools_agent_ptr_info));
-  GetRendererChannel()->SetRenderer(std::move(agent_ptr),
-                                    std::move(host_request), worker_process_id_,
-                                    nullptr);
+  GetRendererChannel()->SetRendererAssociated(std::move(agent_ptr),
+                                              std::move(host_request),
+                                              worker_process_id_, nullptr);
   if (!sessions().empty())
     UpdateIsAttached(true);
 }
@@ -164,7 +168,7 @@
   state_ = WORKER_TERMINATED;
   for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
     inspector->TargetCrashed();
-  GetRendererChannel()->SetRenderer(
+  GetRendererChannel()->SetRendererAssociated(
       nullptr, nullptr, ChildProcessHost::kInvalidUniqueID, nullptr);
   if (!sessions().empty())
     UpdateIsAttached(false);
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.cc b/content/browser/devtools/shared_worker_devtools_agent_host.cc
index 9d4dd11..bd36f73 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.cc
@@ -10,6 +10,7 @@
 #include "content/browser/devtools/protocol/network_handler.h"
 #include "content/browser/devtools/protocol/protocol.h"
 #include "content/browser/devtools/protocol/schema_handler.h"
+#include "content/browser/devtools/protocol/target_handler.h"
 #include "content/browser/devtools/shared_worker_devtools_manager.h"
 #include "content/browser/shared_worker/shared_worker_host.h"
 #include "content/browser/shared_worker/shared_worker_instance.h"
@@ -74,6 +75,9 @@
   session->AddHandler(std::make_unique<protocol::NetworkHandler>(
       GetId(), devtools_worker_token_, GetIOContext()));
   session->AddHandler(std::make_unique<protocol::SchemaHandler>());
+  session->AddHandler(std::make_unique<protocol::TargetHandler>(
+      protocol::TargetHandler::AccessMode::kAutoAttachOnly, GetId(),
+      GetRendererChannel(), registry));
   return true;
 }
 
@@ -121,11 +125,11 @@
     blink::mojom::DevToolsAgentAssociatedPtr agent_ptr;
     worker_host_->BindDevToolsAgent(std::move(host_ptr_info),
                                     mojo::MakeRequest(&agent_ptr));
-    GetRendererChannel()->SetRenderer(std::move(agent_ptr),
-                                      std::move(host_request),
-                                      worker_host_->process_id(), nullptr);
+    GetRendererChannel()->SetRendererAssociated(
+        std::move(agent_ptr), std::move(host_request),
+        worker_host_->process_id(), nullptr);
   } else {
-    GetRendererChannel()->SetRenderer(
+    GetRendererChannel()->SetRendererAssociated(
         nullptr, nullptr, ChildProcessHost::kInvalidUniqueID, nullptr);
   }
 }
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
new file mode 100644
index 0000000..96d60dc
--- /dev/null
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -0,0 +1,90 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/worker_devtools_agent_host.h"
+
+#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/protocol/target_handler.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/public/common/child_process_host.h"
+
+namespace content {
+
+WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(
+    int process_id,
+    blink::mojom::DevToolsAgentPtr agent_ptr,
+    blink::mojom::DevToolsAgentHostRequest host_request,
+    const GURL& url,
+    const base::UnguessableToken& devtools_worker_token,
+    const std::string& parent_id,
+    base::OnceCallback<void(DevToolsAgentHostImpl*)> destroyed_callback)
+    : DevToolsAgentHostImpl(devtools_worker_token.ToString()),
+      process_id_(process_id),
+      url_(url),
+      parent_id_(parent_id),
+      destroyed_callback_(std::move(destroyed_callback)) {
+  DCHECK(agent_ptr);
+  DCHECK(!devtools_worker_token.is_empty());
+  AddRef();  // Self keep-alive while the worker agent is alive.
+  agent_ptr.set_connection_error_handler(base::BindOnce(
+      &WorkerDevToolsAgentHost::Disconnected, base::Unretained(this)));
+  NotifyCreated();
+  GetRendererChannel()->SetRenderer(
+      std::move(agent_ptr), std::move(host_request), process_id, nullptr);
+}
+
+WorkerDevToolsAgentHost::~WorkerDevToolsAgentHost() {}
+
+void WorkerDevToolsAgentHost::Disconnected() {
+  ForceDetachAllSessions();
+  GetRendererChannel()->SetRenderer(
+      nullptr, nullptr, ChildProcessHost::kInvalidUniqueID, nullptr);
+  std::move(destroyed_callback_).Run(this);
+  Release();  // Matches AddRef() in constructor.
+}
+
+BrowserContext* WorkerDevToolsAgentHost::GetBrowserContext() {
+  RenderProcessHost* process = RenderProcessHost::FromID(process_id_);
+  return process ? process->GetBrowserContext() : nullptr;
+}
+
+std::string WorkerDevToolsAgentHost::GetType() {
+  return kTypeDedicatedWorker;
+}
+
+std::string WorkerDevToolsAgentHost::GetTitle() {
+  return url_.spec();
+}
+
+std::string WorkerDevToolsAgentHost::GetParentId() {
+  return parent_id_;
+}
+
+GURL WorkerDevToolsAgentHost::GetURL() {
+  return url_;
+}
+
+bool WorkerDevToolsAgentHost::Activate() {
+  return false;
+}
+
+void WorkerDevToolsAgentHost::Reload() {}
+
+bool WorkerDevToolsAgentHost::Close() {
+  return false;
+}
+
+bool WorkerDevToolsAgentHost::AttachSession(DevToolsSession* session,
+                                            TargetRegistry* registry) {
+  session->AddHandler(std::make_unique<protocol::TargetHandler>(
+      protocol::TargetHandler::AccessMode::kAutoAttachOnly, GetId(),
+      GetRendererChannel(), registry));
+  return true;
+}
+
+void WorkerDevToolsAgentHost::DetachSession(DevToolsSession* session) {
+  // Destroying session automatically detaches in renderer.
+}
+
+}  // namespace content
diff --git a/content/browser/devtools/worker_devtools_agent_host.h b/content/browser/devtools/worker_devtools_agent_host.h
new file mode 100644
index 0000000..579c192
--- /dev/null
+++ b/content/browser/devtools/worker_devtools_agent_host.h
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_AGENT_HOST_H_
+#define CONTENT_BROWSER_DEVTOOLS_WORKER_DEVTOOLS_AGENT_HOST_H_
+
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "third_party/blink/public/web/devtools_agent.mojom.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class WorkerDevToolsAgentHost : public DevToolsAgentHostImpl {
+ public:
+  WorkerDevToolsAgentHost(
+      int process_id,
+      blink::mojom::DevToolsAgentPtr agent_ptr,
+      blink::mojom::DevToolsAgentHostRequest host_request,
+      const GURL& url,
+      const base::UnguessableToken& devtools_worker_token,
+      const std::string& parent_id,
+      base::OnceCallback<void(DevToolsAgentHostImpl*)> destroyed_callback);
+
+  // DevToolsAgentHost override.
+  BrowserContext* GetBrowserContext() override;
+  std::string GetType() override;
+  std::string GetTitle() override;
+  std::string GetParentId() override;
+  GURL GetURL() override;
+  bool Activate() override;
+  void Reload() override;
+  bool Close() override;
+
+ private:
+  ~WorkerDevToolsAgentHost() override;
+  void Disconnected();
+
+  // DevToolsAgentHostImpl overrides.
+  bool AttachSession(DevToolsSession* session,
+                     TargetRegistry* registry) override;
+  void DetachSession(DevToolsSession* session) override;
+
+  const int process_id_;
+  const GURL url_;
+  const std::string parent_id_;
+  base::OnceCallback<void(DevToolsAgentHostImpl*)> destroyed_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsAgentHost);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_DEDICATED_WORKER_DEVTOOLS_AGENT_HOST_H_