普通文本  |  192行  |  6.23 KB

// Copyright (c) 2012 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/devtools_manager_impl.h"

#include <vector>

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "content/browser/devtools/devtools_netlog_observer.h"
#include "content/browser/devtools/render_view_devtools_agent_host.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_client_host.h"

namespace content {

// static
DevToolsManager* DevToolsManager::GetInstance() {
  return DevToolsManagerImpl::GetInstance();
}

// static
DevToolsManagerImpl* DevToolsManagerImpl::GetInstance() {
  return Singleton<DevToolsManagerImpl>::get();
}

DevToolsManagerImpl::DevToolsManagerImpl() {
}

DevToolsManagerImpl::~DevToolsManagerImpl() {
  DCHECK(agent_to_client_host_.empty());
  DCHECK(client_to_agent_host_.empty());
}

DevToolsClientHost* DevToolsManagerImpl::GetDevToolsClientHostFor(
    DevToolsAgentHostImpl* agent_host_impl) {
  AgentToClientHostMap::iterator it =
      agent_to_client_host_.find(agent_host_impl);
  if (it != agent_to_client_host_.end())
    return it->second;
  return NULL;
}

DevToolsAgentHost* DevToolsManagerImpl::GetDevToolsAgentHostFor(
    DevToolsClientHost* client_host) {
  ClientToAgentHostMap::iterator it = client_to_agent_host_.find(client_host);
  if (it != client_to_agent_host_.end())
    return it->second.get();
  return NULL;
}

void DevToolsManagerImpl::RegisterDevToolsClientHostFor(
    DevToolsAgentHost* agent_host,
    DevToolsClientHost* client_host) {
  DevToolsAgentHostImpl* agent_host_impl =
      static_cast<DevToolsAgentHostImpl*>(agent_host);
  DevToolsClientHost* old_client_host =
      GetDevToolsClientHostFor(agent_host_impl);
  if (old_client_host) {
    old_client_host->ReplacedWithAnotherClient();
    UnregisterDevToolsClientHostFor(agent_host_impl);
  }
  BindClientHost(agent_host_impl, client_host);
  agent_host_impl->Attach();
}

bool DevToolsManagerImpl::DispatchOnInspectorBackend(
    DevToolsClientHost* from,
    const std::string& message) {
  DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(from);
  if (!agent_host)
    return false;
  DevToolsAgentHostImpl* agent_host_impl =
      static_cast<DevToolsAgentHostImpl*>(agent_host);
  agent_host_impl->DispatchOnInspectorBackend(message);
  return true;
}

void DevToolsManagerImpl::DispatchOnInspectorFrontend(
    DevToolsAgentHost* agent_host,
    const std::string& message) {
  DevToolsAgentHostImpl* agent_host_impl =
      static_cast<DevToolsAgentHostImpl*>(agent_host);
  DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl);
  if (!client_host) {
    // Client window was closed while there were messages
    // being sent to it.
    return;
  }
  client_host->DispatchOnInspectorFrontend(message);
}

void DevToolsManagerImpl::ClientHostClosing(DevToolsClientHost* client_host) {
  DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(client_host);
  if (!agent_host)
    return;
  DevToolsAgentHostImpl* agent_host_impl =
      static_cast<DevToolsAgentHostImpl*>(agent_host);
  UnbindClientHost(agent_host_impl, client_host);
}

void DevToolsManagerImpl::AgentHostClosing(DevToolsAgentHostImpl* agent_host) {
  UnregisterDevToolsClientHostFor(agent_host);
}

void DevToolsManagerImpl::UnregisterDevToolsClientHostFor(
    DevToolsAgentHostImpl* agent_host_impl) {
  DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl);
  if (!client_host)
    return;
  UnbindClientHost(agent_host_impl, client_host);
  client_host->InspectedContentsClosing();
}

void DevToolsManagerImpl::BindClientHost(
    DevToolsAgentHostImpl* agent_host,
    DevToolsClientHost* client_host) {
  DCHECK(agent_to_client_host_.find(agent_host) ==
      agent_to_client_host_.end());
  DCHECK(client_to_agent_host_.find(client_host) ==
      client_to_agent_host_.end());

  if (client_to_agent_host_.empty()) {
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&DevToolsNetLogObserver::Attach));
  }
  agent_to_client_host_[agent_host] = client_host;
  client_to_agent_host_[client_host] = agent_host;
  agent_host->set_close_listener(this);
}

void DevToolsManagerImpl::UnbindClientHost(DevToolsAgentHostImpl* agent_host,
                                           DevToolsClientHost* client_host) {
  DCHECK(agent_host);
  scoped_refptr<DevToolsAgentHostImpl> protect(agent_host);
  DCHECK(agent_to_client_host_.find(agent_host)->second ==
      client_host);
  DCHECK(client_to_agent_host_.find(client_host)->second.get() == agent_host);
  agent_host->set_close_listener(NULL);

  agent_to_client_host_.erase(agent_host);
  client_to_agent_host_.erase(client_host);

  if (client_to_agent_host_.empty()) {
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&DevToolsNetLogObserver::Detach));
  }
  // Lazy agent hosts can be deleted from within detach.
  // Do not access agent_host below this line.
  agent_host->Detach();
}

void DevToolsManagerImpl::CloseAllClientHosts() {
  std::vector<DevToolsAgentHostImpl*> agents;
  for (AgentToClientHostMap::iterator it =
           agent_to_client_host_.begin();
       it != agent_to_client_host_.end(); ++it) {
    agents.push_back(it->first);
  }
  for (std::vector<DevToolsAgentHostImpl*>::iterator it = agents.begin();
       it != agents.end(); ++it) {
    UnregisterDevToolsClientHostFor(*it);
  }
}

void DevToolsManagerImpl::AddAgentStateCallback(const Callback& callback) {
  callbacks_.push_back(&callback);
}

void DevToolsManagerImpl::RemoveAgentStateCallback(const Callback& callback) {
  CallbackContainer::iterator it =
      std::find(callbacks_.begin(), callbacks_.end(), &callback);
  DCHECK(it != callbacks_.end());
  callbacks_.erase(it);
}

void DevToolsManagerImpl::NotifyObservers(DevToolsAgentHost* agent_host,
                                          bool attached) {
  CallbackContainer copy(callbacks_);
  for (CallbackContainer::iterator it = copy.begin(); it != copy.end(); ++it)
     (*it)->Run(agent_host, attached);
}

}  // namespace content