Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(722)

Unified Diff: chrome/browser/devtools/devtools_adb_bridge.cc

Issue 12586010: DevTools: extract ADB command classes, change objects' lifetimes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Win build fixed. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/devtools/devtools_adb_bridge.h ('k') | chrome/browser/resources/inspect/inspect.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/devtools/devtools_adb_bridge.cc
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 0efd62b92ab911a85da4cb72d37b2152b1bc535e..145e5e55d7cd50ba7604c9f18ec25b4e3c8ab7b7 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -17,10 +17,16 @@
#include "base/threading/thread.h"
#include "base/values.h"
#include "chrome/browser/devtools/adb_client_socket.h"
+#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_client_host.h"
+#include "content/public/browser/devtools_manager.h"
#include "net/base/net_errors.h"
+#include "net/server/web_socket.h"
using content::BrowserThread;
+using net::WebSocket;
namespace {
@@ -29,237 +35,298 @@ static const char kDevToolsChannelName[] = "chrome_devtools_remote";
static const char kHostDevicesCommand[] = "host:devices";
static const char kDeviceModelCommand[] =
"host:transport:%s|shell:getprop ro.product.model";
-static const char kPageListQuery[] = "/json";
+
+static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
+static const char kWebSocketUpgradeRequest[] = "GET %s HTTP/1.1\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n";
const int kAdbPort = 5037;
+const int kBufferSize = 16 * 1024;
+
+typedef DevToolsAdbBridge::Callback Callback;
+typedef DevToolsAdbBridge::PagesCallback PagesCallback;
+
+class AdbQueryCommand : public base::RefCounted<AdbQueryCommand> {
+ public:
+ AdbQueryCommand(const std::string& query,
+ const Callback& callback)
+ : query_(query),
+ callback_(callback) {
+ }
+
+ void Run() {
+ AdbClientSocket::AdbQuery(kAdbPort, query_,
+ base::Bind(&AdbQueryCommand::Handle, this));
+ }
+
+ private:
+ friend class base::RefCounted<AdbQueryCommand>;
+ virtual ~AdbQueryCommand() {}
+
+ void Handle(int result, const std::string& response) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&AdbQueryCommand::Respond, this, result, response));
+ }
+
+ void Respond(int result, const std::string& response) {
+ callback_.Run(result, response);
+ }
+
+ std::string query_;
+ Callback callback_;
+};
+
+class AdbPagesCommand : public base::RefCounted<AdbPagesCommand> {
+ public:
+ explicit AdbPagesCommand(const PagesCallback& callback)
+ : callback_(callback) {
+ pages_.reset(new DevToolsAdbBridge::RemotePages());
+ }
+
+ void Run() {
+ AdbClientSocket::AdbQuery(
+ kAdbPort, kHostDevicesCommand,
+ base::Bind(&AdbPagesCommand::ReceivedDevices, this));
+ }
+
+ private:
+ friend class base::RefCounted<AdbPagesCommand>;
+ virtual ~AdbPagesCommand() {}
+
+ void ReceivedDevices(int result, const std::string& response) {
+ if (result != net::OK) {
+ ProcessSerials();
+ return;
+ }
+
+ std::vector<std::string> devices;
+ Tokenize(response, "\n", &devices);
+ for (size_t i = 0; i < devices.size(); ++i) {
+ std::vector<std::string> tokens;
+ Tokenize(devices[i], "\t ", &tokens);
+ std::string serial = tokens[0];
+ serials_.push_back(serial);
+ }
+
+ ProcessSerials();
+ }
+
+ void ProcessSerials() {
+ if (serials_.size() == 0) {
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&AdbPagesCommand::Respond, this));
+ return;
+ }
+
+ AdbClientSocket::AdbQuery(
+ kAdbPort,
+ base::StringPrintf(kDeviceModelCommand, serials_.back().c_str()),
+ base::Bind(&AdbPagesCommand::ReceivedModel, this));
+ }
+
+ void ReceivedModel(int result, const std::string& response) {
+ if (result != net::OK) {
+ serials_.pop_back();
+ ProcessSerials();
+ return;
+ }
+
+ AdbClientSocket::HttpQuery(
+ kAdbPort, serials_.back(), kDevToolsChannelName, kPageListRequest,
+ base::Bind(&AdbPagesCommand::ReceivedPages, this, response));
+ }
+
+ void ReceivedPages(const std::string& model,
+ int result,
+ const std::string& response) {
+ std::string serial = serials_.back();
+ serials_.pop_back();
+ if (result < 0) {
+ ProcessSerials();
+ return;
+ }
+
+ std::string body = response.substr(result);
+ scoped_ptr<base::Value> value(base::JSONReader::Read(body));
+ base::ListValue* list_value;
+ if (!value || !value->GetAsList(&list_value)) {
+ ProcessSerials();
+ return;
+ }
+
+ base::Value* item;
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ list_value->Get(i, &item);
+ base::DictionaryValue* dict;
+ if (!item || !item->GetAsDictionary(&dict))
+ continue;
+ pages_->push_back(
+ new DevToolsAdbBridge::RemotePage(serial, model, *dict));
+ }
+ ProcessSerials();
+ }
+
+ void Respond() {
+ callback_.Run(net::OK, pages_.release());
+ }
+
+ PagesCallback callback_;
+ std::vector<std::string> serials_;
+ scoped_ptr<DevToolsAdbBridge::RemotePages> pages_;
+};
+
+class AdbAttachCommand : public base::RefCounted<AdbAttachCommand> {
+ public:
+ explicit AdbAttachCommand(scoped_refptr<DevToolsAdbBridge::RemotePage> page)
+ : page_(page) {
+ }
+
+ void Run() {
+ AdbClientSocket::HttpQuery(
+ kAdbPort, page_->serial(), kDevToolsChannelName,
+ base::StringPrintf(kWebSocketUpgradeRequest,
+ page_->debug_url().c_str()),
+ base::Bind(&AdbAttachCommand::Handle, this));
+ }
+
+ private:
+ friend class base::RefCounted<AdbAttachCommand>;
+ virtual ~AdbAttachCommand() {}
+
+ void Handle(int result, net::TCPClientSocket* socket) {
+ if (result != net::OK || socket == NULL)
+ return;
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&AdbAttachCommand::OpenDevToolsWindow, this, socket));
+ }
+
+ void OpenDevToolsWindow(net::TCPClientSocket* socket) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ scoped_ptr<net::TCPClientSocket> tcp_socket(socket);
+ // TODO(pfeldman): Show DevToolsWindow here.
+ }
+
+ scoped_refptr<DevToolsAdbBridge::RemotePage> page_;
+};
} // namespace
-DevToolsAdbBridge::AgentHost::AgentHost(const std::string& serial,
- const std::string& model,
- const base::DictionaryValue& value)
+DevToolsAdbBridge::RemotePage::RemotePage(const std::string& serial,
+ const std::string& model,
+ const base::DictionaryValue& value)
: serial_(serial),
model_(model) {
value.GetString("id", &id_);
+ value.GetString("url", &url_);
value.GetString("title", &title_);
value.GetString("descirption", &description_);
value.GetString("faviconUrl", &favicon_url_);
value.GetString("webSocketDebuggerUrl", &debug_url_);
+ value.GetString("devtoolsFrontendUrl", &frontend_url_);
+
+ if (debug_url_.find("ws://") == 0)
+ debug_url_ = debug_url_.substr(5);
+ else
+ debug_url_ = "";
+
+ size_t ws_param = frontend_url_.find("?ws");
+ if (ws_param != std::string::npos)
+ frontend_url_ = frontend_url_.substr(0, ws_param);
}
-DevToolsAdbBridge::AgentHost::~AgentHost() {
+DevToolsAdbBridge::RemotePage::~RemotePage() {
}
+DevToolsAdbBridge::RefCountedAdbThread*
+DevToolsAdbBridge::RefCountedAdbThread::instance_ = NULL;
+
// static
-DevToolsAdbBridge* DevToolsAdbBridge::Start() {
+scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread>
+DevToolsAdbBridge::RefCountedAdbThread::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- return new DevToolsAdbBridge();
+ if (!instance_)
+ new RefCountedAdbThread();
+ return instance_;
}
-void DevToolsAdbBridge::Stop() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!thread_.get()) {
- ResetHandlerAndReleaseOnUIThread();
- return;
+DevToolsAdbBridge::RefCountedAdbThread::RefCountedAdbThread() {
+ instance_ = this;
+ thread_ = new base::Thread(kDevToolsAdbBridgeThreadName);
+ base::Thread::Options options;
+ options.message_loop_type = MessageLoop::TYPE_IO;
+ if (!thread_->StartWithOptions(options)) {
+ delete thread_;
+ thread_ = NULL;
}
- BrowserThread::PostTaskAndReply(
- BrowserThread::FILE, FROM_HERE,
- base::Bind(&DevToolsAdbBridge::StopHandlerOnFileThread,
- base::Unretained(this)),
- base::Bind(&DevToolsAdbBridge::ResetHandlerAndReleaseOnUIThread,
- base::Unretained(this)));
}
-void DevToolsAdbBridge::Query(
- const std::string query,
- const Callback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+MessageLoop* DevToolsAdbBridge::RefCountedAdbThread::message_loop() {
+ return thread_ ? thread_->message_loop() : NULL;
+}
- // There is a race condition in case Query immediately follows start. We
- // consider it Ok since query is polling anyways.
- if (!thread_.get()) {
- callback.Run(net::ERR_FAILED, "ADB is not yet connected");
- return;
- }
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&DevToolsAdbBridge::QueryOnHandlerThread,
- base::Unretained(this), query, callback));
+// static
+void DevToolsAdbBridge::RefCountedAdbThread::StopThread(base::Thread* thread) {
+ thread->Stop();
}
-void DevToolsAdbBridge::Devices() {
+DevToolsAdbBridge::RefCountedAdbThread::~RefCountedAdbThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (!thread_.get())
+ instance_ = NULL;
+ if (!thread_)
return;
-
- thread_->message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&DevToolsAdbBridge::DevicesOnHandlerThread,
- base::Unretained(this),
- base::Bind(&DevToolsAdbBridge::PrintHosts,
- base::Unretained(this))));
+ // Shut down thread on FILE thread to join into IO.
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&RefCountedAdbThread::StopThread, thread_));
}
-DevToolsAdbBridge::DevToolsAdbBridge() {
- thread_.reset(new base::Thread(kDevToolsAdbBridgeThreadName));
-
- base::Thread::Options options;
- options.message_loop_type = MessageLoop::TYPE_IO;
- if (!thread_->StartWithOptions(options))
- thread_.reset();
+DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile)
+ : profile_(profile),
+ adb_thread_(RefCountedAdbThread::GetInstance()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
+ has_message_loop_(adb_thread_->message_loop() != NULL) {
}
DevToolsAdbBridge::~DevToolsAdbBridge() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- // Stop() must be called prior to destruction.
- DCHECK(thread_.get() == NULL);
-}
-
-// Runs on FILE thread to make sure that it is serialized against
-// {Start|Stop}HandlerThread and to allow calling pthread_join.
-void DevToolsAdbBridge::StopHandlerOnFileThread() {
- if (!thread_->message_loop())
- return;
- // Thread::Stop joins the thread.
- thread_->Stop();
-}
-
-void DevToolsAdbBridge::ResetHandlerAndReleaseOnUIThread() {
- ResetHandlerOnUIThread();
- delete this;
}
-void DevToolsAdbBridge::ResetHandlerOnUIThread() {
- thread_.reset();
-}
-
-void DevToolsAdbBridge::QueryOnHandlerThread(
+void DevToolsAdbBridge::Query(
const std::string query,
const Callback& callback) {
- AdbClientSocket::AdbQuery(kAdbPort, query,
- base::Bind(&DevToolsAdbBridge::QueryResponseOnHandlerThread,
- base::Unretained(this), callback));
-}
-
-void DevToolsAdbBridge::QueryResponseOnHandlerThread(
- const Callback& callback,
- int result,
- const std::string& response) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&DevToolsAdbBridge::RespondOnUIThread, base::Unretained(this),
- callback, result, response));
-}
-
-void DevToolsAdbBridge::DevicesOnHandlerThread(
- const HostsCallback& callback) {
- AdbClientSocket::AdbQuery(
- kAdbPort, kHostDevicesCommand,
- base::Bind(&DevToolsAdbBridge::ReceivedDevices,
- base::Unretained(this), callback));
-}
-
-void DevToolsAdbBridge::ReceivedDevices(
- const HostsCallback& callback,
- int result,
- const std::string& response) {
- AgentHosts* hosts = new AgentHosts();
- if (result != net::OK) {
- callback.Run(result, hosts);
- return;
- }
-
- std::vector<std::string> devices;
- Tokenize(response, "\n", &devices);
- std::vector<std::string>* serials = new std::vector<std::string>();
- for (size_t i = 0; i < devices.size(); ++i) {
- std::vector<std::string> tokens;
- Tokenize(devices[i], "\t ", &tokens);
- std::string serial = tokens[0];
- serials->push_back(serial);
- }
-
- ProcessSerials(callback, hosts, serials);
-}
-
-void DevToolsAdbBridge::ProcessSerials(
- const HostsCallback& callback,
- AgentHosts* hosts,
- std::vector<std::string>* serials) {
- if (serials->size() == 0) {
- delete serials;
- callback.Run(net::OK, hosts);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!has_message_loop_) {
+ callback.Run(net::ERR_FAILED, "Could not start ADB thread");
return;
}
-
- AdbClientSocket::AdbQuery(
- kAdbPort,
- base::StringPrintf(kDeviceModelCommand, serials->back().c_str()),
- base::Bind(&DevToolsAdbBridge::ReceivedModel, base::Unretained(this),
- callback, hosts, serials));
+ scoped_refptr<AdbQueryCommand> command(new AdbQueryCommand(query, callback));
+ adb_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&AdbQueryCommand::Run, command));
}
-void DevToolsAdbBridge::ReceivedModel(const HostsCallback& callback,
- AgentHosts* hosts,
- std::vector<std::string>* serials,
- int result,
- const std::string& response) {
- if (result != net::OK) {
- serials->pop_back();
- ProcessSerials(callback, hosts, serials);
+void DevToolsAdbBridge::Pages(const PagesCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!has_message_loop_)
return;
- }
-
- AdbClientSocket::HttpQuery(
- kAdbPort, serials->back(), kDevToolsChannelName, kPageListQuery,
- base::Bind(&DevToolsAdbBridge::ReceivedPages, base::Unretained(this),
- callback, hosts, serials, response));
+ scoped_refptr<AdbPagesCommand> command(new AdbPagesCommand(callback));
+ adb_thread_->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&AdbPagesCommand::Run, command));
}
-void DevToolsAdbBridge::ReceivedPages(const HostsCallback& callback,
- AgentHosts* hosts,
- std::vector<std::string>* serials,
- const std::string& model,
- int result,
- const std::string& response) {
- std::string serial = serials->back();
- serials->pop_back();
- if (result != net::OK) {
- ProcessSerials(callback, hosts, serials);
- return;
- }
-
- scoped_ptr<base::Value> value(base::JSONReader::Read(response));
- base::ListValue* list_value;
- if (!value || !value->GetAsList(&list_value)) {
- ProcessSerials(callback, hosts, serials);
+void DevToolsAdbBridge::Attach(scoped_refptr<RemotePage> page) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!has_message_loop_)
return;
- }
-
- base::Value* item;
- for (size_t i = 0; i < list_value->GetSize(); ++i) {
- list_value->Get(i, &item);
- base::DictionaryValue* dict;
- if (!item || !item->GetAsDictionary(&dict))
- continue;
- scoped_refptr<AgentHost> host = new AgentHost(serial, model, *dict);
- hosts->push_back(host);
- }
- ProcessSerials(callback, hosts, serials);
-}
-
-void DevToolsAdbBridge::RespondOnUIThread(const Callback& callback,
- int result,
- const std::string& response) {
- callback.Run(result, response);
-}
-void DevToolsAdbBridge::PrintHosts(int result, AgentHosts* hosts) {
- for (AgentHosts::iterator it = hosts->begin(); it != hosts->end(); ++it) {
- AgentHost* host = it->get();
- fprintf(stderr, "HOST %s %s %s %s %s %s %s\n", host->serial().c_str(),
- host->model().c_str(), host->id().c_str(), host->title().c_str(),
- host->description().c_str(), host->favicon_url().c_str(),
- host->debug_url().c_str());
- }
+ scoped_refptr<AdbAttachCommand> command(new AdbAttachCommand(page));
+ adb_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&AdbAttachCommand::Run, command));
}
« no previous file with comments | « chrome/browser/devtools/devtools_adb_bridge.h ('k') | chrome/browser/resources/inspect/inspect.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698