summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-26 06:18:41 +0000
committerpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-26 06:18:41 +0000
commit49d89206f6e43333cdf558adc261ceec1844541c (patch)
tree82d2c0d1684ad884202ce3fd49922111c863bbae
parentcb6ec5471fa7015852d1df5f03cb8b9a02d3fc2e (diff)
downloadchromium_src-49d89206f6e43333cdf558adc261ceec1844541c.zip
chromium_src-49d89206f6e43333cdf558adc261ceec1844541c.tar.gz
chromium_src-49d89206f6e43333cdf558adc261ceec1844541c.tar.bz2
DevTools: extract ADB command classes, change objects' lifetimes
TBR=jhawkins (for minor webui changes) Review URL: https://codereview.chromium.org/12586010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190564 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/devtools/adb_client_socket.cc257
-rw-r--r--chrome/browser/devtools/adb_client_socket.h29
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.cc439
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.h99
-rw-r--r--chrome/browser/resources/inspect/inspect.js21
-rw-r--r--chrome/browser/ui/webui/inspect_ui.cc54
-rw-r--r--chrome/browser/ui/webui/inspect_ui.h7
7 files changed, 503 insertions, 403 deletions
diff --git a/chrome/browser/devtools/adb_client_socket.cc b/chrome/browser/devtools/adb_client_socket.cc
index 342a098..a64171d 100644
--- a/chrome/browser/devtools/adb_client_socket.cc
+++ b/chrome/browser/devtools/adb_client_socket.cc
@@ -38,141 +38,14 @@ std::string EncodeMessage(const std::string& message) {
return result + message;
}
-class AdbSocket {
- public:
- AdbSocket(const std::string& host, int port) : host_(host), port_(port) {
- }
-
- ~AdbSocket() {
- }
-
- protected:
- void Connect(const net::CompletionCallback& callback) {
- net::IPAddressNumber ip_number;
- if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
- callback.Run(net::ERR_FAILED);
- return;
- }
-
- net::AddressList address_list =
- net::AddressList::CreateFromIPAddress(ip_number, port_);
- socket_.reset(new net::TCPClientSocket(address_list, NULL,
- net::NetLog::Source()));
- int result = socket_->Connect(callback);
- if (result != net::ERR_IO_PENDING)
- callback.Run(result);
- }
-
- void SendCommand(const std::string& command,
- bool is_void,
- const CommandCallback& callback) {
- scoped_refptr<net::StringIOBuffer> request_buffer =
- new net::StringIOBuffer(EncodeMessage(command));
- int result = socket_->Write(request_buffer, request_buffer->size(),
- base::Bind(&AdbSocket::ReadResponse, base::Unretained(this),
- callback, is_void));
- if (result != net::ERR_IO_PENDING)
- ReadResponse(callback, is_void, result);
- }
-
- scoped_ptr<net::TCPClientSocket> socket_;
-
- private:
- void ReadResponse(const CommandCallback& callback, bool is_void, int result) {
- if (result < 0) {
- callback.Run(result, "IO error");
- return;
- }
- scoped_refptr<net::IOBuffer> response_buffer =
- new net::IOBuffer(kBufferSize);
- result = socket_->Read(response_buffer, kBufferSize,
- base::Bind(&AdbSocket::OnResponseHeader, base::Unretained(this),
- callback, is_void, response_buffer));
- if (result != net::ERR_IO_PENDING)
- OnResponseHeader(callback, is_void, response_buffer, result);
- }
-
- void OnResponseHeader(const CommandCallback& callback,
- bool is_void,
- scoped_refptr<net::IOBuffer> response_buffer,
- int result) {
- if (result < 0) {
- callback.Run(result, "IO error");
- return;
- }
-
- std::string data = std::string(response_buffer->data(), result);
- if (result < 4) {
- callback.Run(net::ERR_FAILED, "Response is too short: " + data);
- return;
- }
-
- std::string status = data.substr(0, 4);
- if (status != kOkayResponse) {
- callback.Run(net::ERR_FAILED, data);
- return;
- }
-
- data = data.substr(4);
-
- if (!is_void) {
- int payload_length = 0;
- int bytes_left = -1;
- if (data.length() >= 4 &&
- base::HexStringToInt(data.substr(0, 4), &payload_length)) {
- data = data.substr(4);
- bytes_left = payload_length - result + 8;
- } else {
- bytes_left = -1;
- }
- OnResponseData(callback, data, response_buffer, bytes_left, 0);
- } else {
- callback.Run(net::OK, data);
- }
- }
-
- void OnResponseData(const CommandCallback& callback,
- const std::string& response,
- scoped_refptr<net::IOBuffer> response_buffer,
- int bytes_left,
- int result) {
- if (result < 0) {
- callback.Run(result, "IO error");
- return;
- }
-
- bytes_left -= result;
- std::string new_response =
- response + std::string(response_buffer->data(), result);
- if (bytes_left == 0) {
- callback.Run(net::OK, new_response);
- return;
- }
-
- // Read tail
- result = socket_->Read(response_buffer, kBufferSize,
- base::Bind(&AdbSocket::OnResponseData, base::Unretained(this),
- callback, new_response, response_buffer, bytes_left));
- if (result > 0) {
- OnResponseData(callback, new_response, response_buffer, bytes_left,
- result);
- } else if (result != net::ERR_IO_PENDING) {
- callback.Run(net::OK, new_response);
- }
- }
-
- std::string host_;
- int port_;
-};
-
-class AdbTransportSocket : public AdbSocket {
+class AdbTransportSocket : public AdbClientSocket {
public:
AdbTransportSocket(const std::string& host,
int port,
const std::string& serial,
const std::string& socket_name,
const SocketCallback& callback)
- : AdbSocket(host, port),
+ : AdbClientSocket(host, port),
serial_(serial),
socket_name_(socket_name),
callback_(callback) {
@@ -294,6 +167,10 @@ class HttpOverAdbSocket {
int result) {
if (!CheckNetResultOrDie(result))
return;
+ if (result == 0) {
+ CheckNetResultOrDie(net::ERR_CONNECTION_CLOSED);
+ return;
+ }
response_ += std::string(response_buffer->data(), result);
int expected_length = 0;
@@ -354,13 +231,13 @@ class HttpOverAdbSocket {
size_t body_pos_;
};
-class AdbQuerySocket : AdbSocket {
+class AdbQuerySocket : AdbClientSocket {
public:
AdbQuerySocket(const std::string& host,
int port,
const std::string& query,
const CommandCallback& callback)
- : AdbSocket(host, port),
+ : AdbClientSocket(host, port),
current_query_(0),
callback_(callback) {
if (Tokenize(query, "|", &queries_) == 0) {
@@ -373,7 +250,6 @@ class AdbQuerySocket : AdbSocket {
private:
~AdbQuerySocket() {
-
}
void SendNextQuery(int result) {
@@ -440,8 +316,123 @@ void AdbClientSocket::HttpQuery(int port,
callback);
}
-AdbClientSocket::AdbClientSocket() {
+AdbClientSocket::AdbClientSocket(const std::string& host, int port)
+ : host_(host), port_(port) {
}
AdbClientSocket::~AdbClientSocket() {
}
+
+void AdbClientSocket::Connect(const net::CompletionCallback& callback) {
+ net::IPAddressNumber ip_number;
+ if (!net::ParseIPLiteralToNumber(host_, &ip_number)) {
+ callback.Run(net::ERR_FAILED);
+ return;
+ }
+
+ net::AddressList address_list =
+ net::AddressList::CreateFromIPAddress(ip_number, port_);
+ socket_.reset(new net::TCPClientSocket(address_list, NULL,
+ net::NetLog::Source()));
+ int result = socket_->Connect(callback);
+ if (result != net::ERR_IO_PENDING)
+ callback.Run(result);
+}
+
+void AdbClientSocket::SendCommand(const std::string& command,
+ bool is_void,
+ const CommandCallback& callback) {
+ scoped_refptr<net::StringIOBuffer> request_buffer =
+ new net::StringIOBuffer(EncodeMessage(command));
+ int result = socket_->Write(request_buffer, request_buffer->size(),
+ base::Bind(&AdbClientSocket::ReadResponse, base::Unretained(this),
+ callback, is_void));
+ if (result != net::ERR_IO_PENDING)
+ ReadResponse(callback, is_void, result);
+}
+
+void AdbClientSocket::ReadResponse(const CommandCallback& callback,
+ bool is_void,
+ int result) {
+ if (result < 0) {
+ callback.Run(result, "IO error");
+ return;
+ }
+ scoped_refptr<net::IOBuffer> response_buffer =
+ new net::IOBuffer(kBufferSize);
+ result = socket_->Read(response_buffer, kBufferSize,
+ base::Bind(&AdbClientSocket::OnResponseHeader, base::Unretained(this),
+ callback, is_void, response_buffer));
+ if (result != net::ERR_IO_PENDING)
+ OnResponseHeader(callback, is_void, response_buffer, result);
+}
+
+void AdbClientSocket::OnResponseHeader(
+ const CommandCallback& callback,
+ bool is_void,
+ scoped_refptr<net::IOBuffer> response_buffer,
+ int result) {
+ if (result <= 0) {
+ callback.Run(result == 0 ? net::ERR_CONNECTION_CLOSED : result,
+ "IO error");
+ return;
+ }
+
+ std::string data = std::string(response_buffer->data(), result);
+ if (result < 4) {
+ callback.Run(net::ERR_FAILED, "Response is too short: " + data);
+ return;
+ }
+
+ std::string status = data.substr(0, 4);
+ if (status != kOkayResponse) {
+ callback.Run(net::ERR_FAILED, data);
+ return;
+ }
+
+ data = data.substr(4);
+
+ if (!is_void) {
+ int payload_length = 0;
+ int bytes_left = -1;
+ if (data.length() >= 4 &&
+ base::HexStringToInt(data.substr(0, 4), &payload_length)) {
+ data = data.substr(4);
+ bytes_left = payload_length - result + 8;
+ } else {
+ bytes_left = -1;
+ }
+ OnResponseData(callback, data, response_buffer, bytes_left, 0);
+ } else {
+ callback.Run(net::OK, data);
+ }
+}
+
+void AdbClientSocket::OnResponseData(
+ const CommandCallback& callback,
+ const std::string& response,
+ scoped_refptr<net::IOBuffer> response_buffer,
+ int bytes_left,
+ int result) {
+ if (result < 0) {
+ callback.Run(result, "IO error");
+ return;
+ }
+
+ bytes_left -= result;
+ std::string new_response =
+ response + std::string(response_buffer->data(), result);
+ if (bytes_left == 0) {
+ callback.Run(net::OK, new_response);
+ return;
+ }
+
+ // Read tail
+ result = socket_->Read(response_buffer, kBufferSize,
+ base::Bind(&AdbClientSocket::OnResponseData, base::Unretained(this),
+ callback, new_response, response_buffer, bytes_left));
+ if (result > 0)
+ OnResponseData(callback, new_response, response_buffer, bytes_left, result);
+ else if (result != net::ERR_IO_PENDING)
+ callback.Run(net::OK, new_response);
+}
diff --git a/chrome/browser/devtools/adb_client_socket.h b/chrome/browser/devtools/adb_client_socket.h
index f5e7872..f93a1af 100644
--- a/chrome/browser/devtools/adb_client_socket.h
+++ b/chrome/browser/devtools/adb_client_socket.h
@@ -31,10 +31,35 @@ class AdbClientSocket {
const std::string& request,
const SocketCallback& callback);
- private:
- AdbClientSocket();
+ AdbClientSocket(const std::string& host, int port);
~AdbClientSocket();
+ protected:
+ void Connect(const net::CompletionCallback& callback);
+
+ void SendCommand(const std::string& command,
+ bool is_void,
+ const CommandCallback& callback);
+
+ scoped_ptr<net::TCPClientSocket> socket_;
+
+ private:
+ void ReadResponse(const CommandCallback& callback, bool is_void, int result);
+
+ void OnResponseHeader(const CommandCallback& callback,
+ bool is_void,
+ scoped_refptr<net::IOBuffer> response_buffer,
+ int result);
+
+ void OnResponseData(const CommandCallback& callback,
+ const std::string& response,
+ scoped_refptr<net::IOBuffer> response_buffer,
+ int bytes_left,
+ int result);
+
+ std::string host_;
+ int port_;
+
DISALLOW_COPY_AND_ASSIGN(AdbClientSocket);
};
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 0efd62b..145e5e5 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));
}
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index 2043ffc..8c9141b 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -9,7 +9,9 @@
#include <vector>
#include "base/callback.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "net/socket/tcp_client_socket.h"
namespace base {
@@ -17,92 +19,77 @@ class Thread;
class DictionaryValue;
}
+class MessageLoop;
+class Profile;
+
class DevToolsAdbBridge {
public:
typedef base::Callback<void(int result,
const std::string& response)> Callback;
- class AgentHost : public base::RefCounted<AgentHost> {
+ class RemotePage : public base::RefCounted<RemotePage> {
public:
- AgentHost(const std::string& serial,
- const std::string& model,
- const base::DictionaryValue& value);
+ RemotePage(const std::string& serial,
+ const std::string& model,
+ const base::DictionaryValue& value);
std::string serial() { return serial_; }
std::string model() { return model_; }
std::string id() { return id_; }
+ std::string url() { return url_; }
std::string title() { return title_; }
std::string description() { return description_; }
std::string favicon_url() { return favicon_url_; }
std::string debug_url() { return debug_url_; }
+ std::string frontend_url() { return frontend_url_; }
private:
- friend class base::RefCounted<AgentHost>;
-
- virtual ~AgentHost();
+ friend class base::RefCounted<RemotePage>;
+ virtual ~RemotePage();
std::string serial_;
std::string model_;
std::string id_;
+ std::string url_;
std::string title_;
std::string description_;
std::string favicon_url_;
std::string debug_url_;
- DISALLOW_COPY_AND_ASSIGN(AgentHost);
+ std::string frontend_url_;
+ DISALLOW_COPY_AND_ASSIGN(RemotePage);
};
- typedef std::vector<scoped_refptr<AgentHost> > AgentHosts;
- typedef base::Callback<void(int, AgentHosts*)> HostsCallback;
+ typedef std::vector<scoped_refptr<RemotePage> > RemotePages;
+ typedef base::Callback<void(int, RemotePages*)> PagesCallback;
+
+ explicit DevToolsAdbBridge(Profile* profile);
+ ~DevToolsAdbBridge();
- static DevToolsAdbBridge* Start();
void Query(const std::string query, const Callback& callback);
- void Devices();
- void Stop();
+ void Pages(const PagesCallback& callback);
+ void Attach(scoped_refptr<RemotePage> page);
private:
- friend class base::RefCountedThreadSafe<DevToolsAdbBridge>;
-
-
- explicit DevToolsAdbBridge();
- virtual ~DevToolsAdbBridge();
-
- void StopHandlerOnFileThread();
-
- void ResetHandlerAndReleaseOnUIThread();
- void ResetHandlerOnUIThread();
-
- void QueryOnHandlerThread(const std::string query, const Callback& callback);
- void QueryResponseOnHandlerThread(const Callback& callback,
- int result,
- const std::string& response);
-
- void DevicesOnHandlerThread(const HostsCallback& callback);
- void ReceivedDevices(const HostsCallback& callback,
- int result,
- const std::string& response);
- void ProcessSerials(const HostsCallback& callback,
- AgentHosts* hosts,
- std::vector<std::string>* serials);
- void ReceivedModel(const HostsCallback& callback,
- AgentHosts* hosts,
- std::vector<std::string>* serials,
- int result,
- const std::string& response);
- void ReceivedPages(const HostsCallback& callback,
- AgentHosts* hosts,
- std::vector<std::string>* serials,
- const std::string& model,
- int result,
- const std::string& response);
-
- void RespondOnUIThread(const Callback& callback,
- int result,
- const std::string& response);
-
- void PrintHosts(int result, AgentHosts* hosts);
-
- // The thread used by the devtools to run client socket.
- scoped_ptr<base::Thread> thread_;
+ friend class AdbWebSocket;
+
+ class RefCountedAdbThread : public base::RefCounted<RefCountedAdbThread> {
+ public:
+ static scoped_refptr<RefCountedAdbThread> GetInstance();
+ RefCountedAdbThread();
+ MessageLoop* message_loop();
+
+ private:
+ friend class base::RefCounted<RefCountedAdbThread>;
+ static DevToolsAdbBridge::RefCountedAdbThread* instance_;
+ static void StopThread(base::Thread* thread);
+
+ virtual ~RefCountedAdbThread();
+ base::Thread* thread_;
+ };
+ Profile* profile_;
+ scoped_refptr<RefCountedAdbThread> adb_thread_;
+ base::WeakPtrFactory<DevToolsAdbBridge> weak_factory_;
+ bool has_message_loop_;
DISALLOW_COPY_AND_ASSIGN(DevToolsAdbBridge);
};
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 88094f7..bae8877 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -104,16 +104,15 @@ AdbDevice.adbQuery_ = function(query) {
* @return {?Object} ADB query result.
* @private
*/
-AdbDevice.adbDevices_ = function() {
+AdbDevice.adbPages_ = function() {
var xhr = new XMLHttpRequest();
- xhr.open('GET', 'adb-devices', false);
+ xhr.open('GET', 'adb-pages', false);
xhr.send(null);
if (xhr.status !== 200)
return null;
try {
- var result = JSON.parse(xhr.responseText);
- return result[0] ? null : result[1];
+ return JSON.parse(xhr.responseText);
} catch (e) {
}
return null;
@@ -164,8 +163,8 @@ AdbDevice.prototype.targets = function() {
target['name'] = json['title'];
target['url'] = json['url'];
target['attached'] = !json['webSocketDebuggerUrl'];
- target['favicon_url'] = json['faviconUrl'];
- target['inspect_url'] = json['devtoolsFrontendUrl'];
+ target['faviconUrl'] = json['faviconUrl'];
+ target['inspectUrl'] = json['devtoolsFrontendUrl'];
targets.push(target);
}
return targets;
@@ -205,8 +204,8 @@ function requestData() {
}
function inspect(data) {
- if (data['inspect_url']) {
- window.open(data['inspect_url'], undefined,
+ if (data['inspectUrl']) {
+ window.open(data['inspectUrl'], undefined,
'location=0,width=800,height=600');
return;
}
@@ -278,14 +277,14 @@ function populateDeviceLists() {
for (var j = 0; j < targets.length; j++) {
addTargetToList(targets[j], 'device-' + device.serial,
- ['favicon_url', 'name', 'url']);
+ ['faviconUrl', 'name', 'url']);
}
}
setTimeout(populateDeviceLists, 1000);
}
function addToPagesList(data) {
- addTargetToList(data, 'pages', ['favicon_url', 'name', 'url']);
+ addTargetToList(data, 'pages', ['faviconUrl', 'name', 'url']);
}
function addToExtensionsList(data) {
@@ -306,7 +305,7 @@ function addToOthersList(data) {
function formatValue(data, property) {
var value = data[property];
- if (property == 'favicon_url') {
+ if (property == 'faviconUrl') {
var faviconElement = document.createElement('img');
if (value)
faviconElement.src = value;
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index 0562d12..437f3aa 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -42,6 +42,7 @@
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
+#include "net/base/net_errors.h"
#include "ui/base/resource/resource_bundle.h"
using content::BrowserThread;
@@ -62,12 +63,13 @@ namespace {
static const char kDataFile[] = "targets-data.json";
static const char kAdbQuery[] = "adb-query/";
-static const char kAdbDevices[] = "adb-devices";
+static const char kAdbPages[] = "adb-pages";
static const char kLocalXhr[] = "local-xhr/";
static const char kExtensionTargetType[] = "extension";
static const char kPageTargetType[] = "page";
static const char kWorkerTargetType[] = "worker";
+static const char kAdbTargetType[] = "adb_page";
static const char kInspectCommand[] = "inspect";
static const char kTerminateCommand[] = "terminate";
@@ -78,8 +80,12 @@ static const char kProcessIdField[] = "processId";
static const char kRouteIdField[] = "routeId";
static const char kUrlField[] = "url";
static const char kNameField[] = "name";
-static const char kFaviconUrlField[] = "favicon_url";
+static const char kFaviconUrlField[] = "faviconUrl";
static const char kPidField[] = "pid";
+static const char kAdbSerialField[] = "adbSerial";
+static const char kAdbModelField[] = "adbModel";
+static const char kAdbPageIdField[] = "adbPageId";
+static const char kAdbDebugUrl[] = "adbDebugUrl";
DictionaryValue* BuildTargetDescriptor(
const std::string& target_type,
@@ -169,7 +175,6 @@ void SendDescriptors(
std::string json_string;
base::JSONWriter::Write(rvh_list, &json_string);
-
callback.Run(base::RefCountedString::TakeString(&json_string));
}
@@ -338,7 +343,7 @@ InspectUI::InspectUI(content::WebUI* web_ui)
web_ui->AddMessageHandler(new InspectMessageHandler());
Profile* profile = Profile::FromWebUI(web_ui);
- adb_bridge_ = DevToolsAdbBridge::Start();
+ adb_bridge_.reset(new DevToolsAdbBridge(profile));
content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource());
registrar_.Add(this,
@@ -383,10 +388,7 @@ void InspectUI::StopListeningNotifications()
{
if (!observer_)
return;
- if (adb_bridge_) {
- adb_bridge_->Stop();
- adb_bridge_ = NULL;
- }
+ adb_bridge_.reset();
observer_->InspectUIDestroyed();
observer_ = NULL;
registrar_.RemoveAll();
@@ -408,8 +410,8 @@ bool InspectUI::HandleRequestCallback(
const content::WebUIDataSource::GotDataCallback& callback) {
if (path == kDataFile)
return HandleDataRequestCallback(path, callback);
- if (path.find(kAdbDevices) == 0)
- return HandleAdbDevicesCallback(path, callback);
+ if (path.find(kAdbPages) == 0)
+ return HandleAdbPagesCallback(path, callback);
if (path.find(kAdbQuery) == 0)
return HandleAdbQueryCallback(path, callback);
if (path.find(kLocalXhr) == 0)
@@ -429,13 +431,39 @@ bool InspectUI::HandleAdbQueryCallback(
return true;
}
-bool InspectUI::HandleAdbDevicesCallback(
+bool InspectUI::HandleAdbPagesCallback(
const std::string& path,
const content::WebUIDataSource::GotDataCallback& callback) {
- adb_bridge_->Devices();
+ adb_bridge_->Pages(base::Bind(&InspectUI::OnAdbPages,
+ weak_factory_.GetWeakPtr(),
+ callback));
+ return true;
+}
+
+void InspectUI::OnAdbPages(
+ const content::WebUIDataSource::GotDataCallback& callback,
+ int result,
+ DevToolsAdbBridge::RemotePages* pages) {
+ if (result != net::OK)
+ return;
+ ListValue targets;
+ scoped_ptr<DevToolsAdbBridge::RemotePages> my_pages(pages);
+ for (DevToolsAdbBridge::RemotePages::iterator it = my_pages->begin();
+ it != my_pages->end(); ++it) {
+ DevToolsAdbBridge::RemotePage* page = it->get();
+ DictionaryValue* target_data = BuildTargetDescriptor(kAdbTargetType,
+ false, GURL(page->url()), page->title(), GURL(page->favicon_url()), 0,
+ 0);
+ target_data->SetString(kAdbSerialField, page->serial());
+ target_data->SetString(kAdbModelField, page->model());
+ target_data->SetString(kAdbPageIdField, page->id());
+ target_data->SetString(kAdbDebugUrl, page->debug_url());
+ targets.Append(target_data);
+ }
+
std::string json_string = "";
+ base::JSONWriter::Write(&targets, &json_string);
callback.Run(base::RefCountedString::TakeString(&json_string));
- return true;
}
bool InspectUI::HandleLocalXhrCallback(
diff --git a/chrome/browser/ui/webui/inspect_ui.h b/chrome/browser/ui/webui/inspect_ui.h
index ec382ba..264b9fd 100644
--- a/chrome/browser/ui/webui/inspect_ui.h
+++ b/chrome/browser/ui/webui/inspect_ui.h
@@ -44,7 +44,7 @@ class InspectUI : public content::WebUIController,
const std::string& path,
const content::WebUIDataSource::GotDataCallback& callback);
- bool HandleAdbDevicesCallback(
+ bool HandleAdbPagesCallback(
const std::string& path,
const content::WebUIDataSource::GotDataCallback& callback);
@@ -61,13 +61,16 @@ class InspectUI : public content::WebUIController,
int result,
const std::string& response);
+ void OnAdbPages(const content::WebUIDataSource::GotDataCallback& callback,
+ int result,
+ DevToolsAdbBridge::RemotePages* pages);
scoped_refptr<WorkerCreationDestructionListener> observer_;
// A scoped container for notification registries.
content::NotificationRegistrar registrar_;
- DevToolsAdbBridge* adb_bridge_;
+ scoped_ptr<DevToolsAdbBridge> adb_bridge_;
base::WeakPtrFactory<InspectUI> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(InspectUI);