HeadlessWebContents Observers for devtools clients attaching/detatching

BUG=546953

Review-Url: https://codereview.chromium.org/2843773002
Cr-Commit-Position: refs/heads/master@{#467268}
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index aea5aef..0749208 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -192,9 +192,11 @@
 #endif
   web_contents_->SetDelegate(web_contents_delegate_.get());
   render_process_host_->AddObserver(this);
+  agent_host_->AddObserver(this);
 }
 
 HeadlessWebContentsImpl::~HeadlessWebContentsImpl() {
+  agent_host_->RemoveObserver(this);
   if (render_process_host_)
     render_process_host_->RemoveObserver(this);
 }
@@ -277,6 +279,20 @@
   observer_map_.erase(it);
 }
 
+void HeadlessWebContentsImpl::DevToolsAgentHostAttached(
+    content::DevToolsAgentHost* agent_host) {
+  for (const auto& pair : observer_map_) {
+    pair.second->observer()->DevToolsClientAttached();
+  }
+}
+
+void HeadlessWebContentsImpl::DevToolsAgentHostDetached(
+    content::DevToolsAgentHost* agent_host) {
+  for (const auto& pair : observer_map_) {
+    pair.second->observer()->DevToolsClientDetached();
+  }
+}
+
 void HeadlessWebContentsImpl::RenderProcessExited(
     content::RenderProcessHost* host,
     base::TerminationStatus status,
diff --git a/headless/lib/browser/headless_web_contents_impl.h b/headless/lib/browser/headless_web_contents_impl.h
index 1dd6c6d6..e578e8a 100644
--- a/headless/lib/browser/headless_web_contents_impl.h
+++ b/headless/lib/browser/headless_web_contents_impl.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <unordered_map>
 
+#include "content/public/browser/devtools_agent_host_observer.h"
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "headless/lib/browser/headless_window_tree_host.h"
@@ -35,6 +36,7 @@
 class HEADLESS_EXPORT HeadlessWebContentsImpl
     : public HeadlessWebContents,
       public HeadlessDevToolsTarget,
+      public content::DevToolsAgentHostObserver,
       public content::RenderProcessHostObserver,
       public content::WebContentsObserver {
  public:
@@ -65,7 +67,13 @@
   void DetachClient(HeadlessDevToolsClient* client) override;
   bool IsAttached() override;
 
-  // RenderProcessHostObserver implementation:
+  // content::DevToolsAgentHostObserver implementation:
+  void DevToolsAgentHostAttached(
+      content::DevToolsAgentHost* agent_host) override;
+  void DevToolsAgentHostDetached(
+      content::DevToolsAgentHost* agent_host) override;
+
+  // content::RenderProcessHostObserver implementation:
   void RenderProcessExited(content::RenderProcessHost* host,
                            base::TerminationStatus status,
                            int exit_code) override;
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index dd4474b..79c5495 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -1022,4 +1022,27 @@
 
 HEADLESS_ASYNC_DEVTOOLED_TEST_F(RawDevtoolsProtocolTest);
 
+class DevToolsAttachAndDetachNotifications
+    : public HeadlessAsyncDevTooledBrowserTest {
+ public:
+  void DevToolsClientAttached() override { dev_tools_client_attached_ = true; }
+
+  void RunDevTooledTest() override {
+    EXPECT_TRUE(dev_tools_client_attached_);
+    FinishAsynchronousTest();
+  }
+
+  void DevToolsClientDetached() override { dev_tools_client_detached_ = true; }
+
+  void TearDownOnMainThread() override {
+    EXPECT_TRUE(dev_tools_client_detached_);
+  }
+
+ private:
+  bool dev_tools_client_attached_ = false;
+  bool dev_tools_client_detached_ = false;
+};
+
+HEADLESS_ASYNC_DEVTOOLED_TEST_F(DevToolsAttachAndDetachNotifications);
+
 }  // namespace headless
diff --git a/headless/public/headless_web_contents.h b/headless/public/headless_web_contents.h
index 031045f0..93f6262 100644
--- a/headless/public/headless_web_contents.h
+++ b/headless/public/headless_web_contents.h
@@ -41,6 +41,14 @@
     // TODO(altimin): Support this event for pages that aren't created by us.
     virtual void DevToolsTargetReady() {}
 
+    // Indicates that a DevTools client attached to this HeadlessWebContents
+    // instance.
+    virtual void DevToolsClientAttached() {}
+
+    // Indicates that a DevTools client detached from this HeadlessWebContents
+    // instance.
+    virtual void DevToolsClientDetached() {}
+
     // This method is invoked when the process of the observed RenderProcessHost
     // exits (either normally or with a crash). To determine if the process
     // closed normally or crashed, examine the |status| parameter.