blob: fb006f19bb5281e644fed10c1909b1d447f8deff [file] [log] [blame]
[email protected]50a80dd2013-03-11 17:37:401// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/devtools/devtools_adb_bridge.h"
6
[email protected]cf57e1b2013-03-27 14:29:437#include <map>
[email protected]29b0a202013-03-22 09:34:158#include <vector>
9
[email protected]50a80dd2013-03-11 17:37:4010#include "base/bind.h"
11#include "base/compiler_specific.h"
[email protected]29b0a202013-03-22 09:34:1512#include "base/json/json_reader.h"
[email protected]cf57e1b2013-03-27 14:29:4313#include "base/lazy_instance.h"
[email protected]50a80dd2013-03-11 17:37:4014#include "base/logging.h"
[email protected]76ae8a62013-05-10 05:34:2215#include "base/message_loop/message_loop_proxy.h"
[email protected]cf57e1b2013-03-27 14:29:4316#include "base/rand_util.h"
[email protected]50a80dd2013-03-11 17:37:4017#include "base/strings/string_number_conversions.h"
[email protected]340f55d7c2013-06-10 20:49:1118#include "base/strings/string_util.h"
19#include "base/strings/stringprintf.h"
[email protected]50a80dd2013-03-11 17:37:4020#include "base/threading/thread.h"
[email protected]29b0a202013-03-22 09:34:1521#include "base/values.h"
[email protected]50a80dd2013-03-11 17:37:4022#include "chrome/browser/devtools/adb_client_socket.h"
[email protected]b9960e22013-04-02 13:13:1523#include "chrome/browser/devtools/devtools_window.h"
[email protected]eafc8452013-04-16 04:18:3524#include "chrome/browser/devtools/tethering_adb_filter.h"
[email protected]49d892062013-03-26 06:18:4125#include "chrome/browser/profiles/profile.h"
[email protected]50a80dd2013-03-11 17:37:4026#include "content/public/browser/browser_thread.h"
[email protected]49d892062013-03-26 06:18:4127#include "content/public/browser/devtools_agent_host.h"
28#include "content/public/browser/devtools_client_host.h"
[email protected]cf57e1b2013-03-27 14:29:4329#include "content/public/browser/devtools_external_agent_proxy.h"
30#include "content/public/browser/devtools_external_agent_proxy_delegate.h"
[email protected]49d892062013-03-26 06:18:4131#include "content/public/browser/devtools_manager.h"
[email protected]29b0a202013-03-22 09:34:1532#include "net/base/net_errors.h"
[email protected]49d892062013-03-26 06:18:4133#include "net/server/web_socket.h"
[email protected]50a80dd2013-03-11 17:37:4034
35using content::BrowserThread;
[email protected]49d892062013-03-26 06:18:4136using net::WebSocket;
[email protected]50a80dd2013-03-11 17:37:4037
38namespace {
39
[email protected]29b0a202013-03-22 09:34:1540static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread";
[email protected]2ce6d312013-04-23 15:58:5541static const char kDevToolsChannelPattern[] = "devtools_remote";
[email protected]29b0a202013-03-22 09:34:1542static const char kHostDevicesCommand[] = "host:devices";
43static const char kDeviceModelCommand[] =
44 "host:transport:%s|shell:getprop ro.product.model";
[email protected]2ce6d312013-04-23 15:58:5545static const char kUnknownModel[] = "Unknown";
46static const char kOpenedUnixSocketsCommand[] =
47 "host:transport:%s|shell:cat /proc/net/unix";
[email protected]49d892062013-03-26 06:18:4148
49static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
[email protected]817b3f12013-04-25 18:10:2150static const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
[email protected]49d892062013-03-26 06:18:4151static const char kWebSocketUpgradeRequest[] = "GET %s HTTP/1.1\r\n"
52 "Upgrade: WebSocket\r\n"
53 "Connection: Upgrade\r\n"
54 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
55 "Sec-WebSocket-Version: 13\r\n"
56 "\r\n";
[email protected]50a80dd2013-03-11 17:37:4057const int kAdbPort = 5037;
[email protected]49d892062013-03-26 06:18:4158const int kBufferSize = 16 * 1024;
59
60typedef DevToolsAdbBridge::Callback Callback;
61typedef DevToolsAdbBridge::PagesCallback PagesCallback;
62
63class AdbQueryCommand : public base::RefCounted<AdbQueryCommand> {
64 public:
65 AdbQueryCommand(const std::string& query,
66 const Callback& callback)
67 : query_(query),
68 callback_(callback) {
69 }
70
71 void Run() {
72 AdbClientSocket::AdbQuery(kAdbPort, query_,
73 base::Bind(&AdbQueryCommand::Handle, this));
74 }
75
76 private:
77 friend class base::RefCounted<AdbQueryCommand>;
78 virtual ~AdbQueryCommand() {}
79
80 void Handle(int result, const std::string& response) {
81 BrowserThread::PostTask(
82 BrowserThread::UI, FROM_HERE,
83 base::Bind(&AdbQueryCommand::Respond, this, result, response));
84 }
85
86 void Respond(int result, const std::string& response) {
87 callback_.Run(result, response);
88 }
89
90 std::string query_;
91 Callback callback_;
92};
93
94class AdbPagesCommand : public base::RefCounted<AdbPagesCommand> {
95 public:
96 explicit AdbPagesCommand(const PagesCallback& callback)
97 : callback_(callback) {
98 pages_.reset(new DevToolsAdbBridge::RemotePages());
[email protected]37066c42013-04-15 13:08:0599#if defined(DEBUG_DEVTOOLS)
100 serials_.push_back(std::string()); // For desktop remote debugging.
101#endif // defined(DEBUG_DEVTOOLS)
[email protected]49d892062013-03-26 06:18:41102 }
103
104 void Run() {
105 AdbClientSocket::AdbQuery(
106 kAdbPort, kHostDevicesCommand,
107 base::Bind(&AdbPagesCommand::ReceivedDevices, this));
108 }
109
110 private:
111 friend class base::RefCounted<AdbPagesCommand>;
112 virtual ~AdbPagesCommand() {}
113
114 void ReceivedDevices(int result, const std::string& response) {
115 if (result != net::OK) {
116 ProcessSerials();
117 return;
118 }
119
120 std::vector<std::string> devices;
121 Tokenize(response, "\n", &devices);
122 for (size_t i = 0; i < devices.size(); ++i) {
123 std::vector<std::string> tokens;
124 Tokenize(devices[i], "\t ", &tokens);
125 std::string serial = tokens[0];
126 serials_.push_back(serial);
127 }
128
129 ProcessSerials();
130 }
131
132 void ProcessSerials() {
133 if (serials_.size() == 0) {
134 BrowserThread::PostTask(
135 BrowserThread::UI, FROM_HERE,
136 base::Bind(&AdbPagesCommand::Respond, this));
137 return;
138 }
139
140 AdbClientSocket::AdbQuery(
141 kAdbPort,
142 base::StringPrintf(kDeviceModelCommand, serials_.back().c_str()),
143 base::Bind(&AdbPagesCommand::ReceivedModel, this));
144 }
145
146 void ReceivedModel(int result, const std::string& response) {
[email protected]2ce6d312013-04-23 15:58:55147 std::string model;
148 if (result == net::OK) {
149 model = response;
150 } else {
151 model = kUnknownModel;
152#if defined(DEBUG_DEVTOOLS)
153 // For desktop remote debugging.
[email protected]817b3f12013-04-25 18:10:21154 if (serials_.back().empty()) {
155 sockets_.push_back(std::string());
156 AdbClientSocket::HttpQuery(
157 kAdbPort, serials_.back(), sockets_.back(), kVersionRequest,
158 base::Bind(&AdbPagesCommand::ReceivedVersion, this, model));
159 return;
160 }
[email protected]2ce6d312013-04-23 15:58:55161#endif // defined(DEBUG_DEVTOOLS)
162 }
163 AdbClientSocket::AdbQuery(
164 kAdbPort,
165 base::StringPrintf(kOpenedUnixSocketsCommand, serials_.back().c_str()),
166 base::Bind(&AdbPagesCommand::ReceivedSockets, this, model));
167 }
168
169 void ReceivedSockets(const std::string& model,
170 int result,
171 const std::string& response) {
172 if (result < 0) {
173 serials_.pop_back();
174 ProcessSerials();
175 return;
176 }
177
178 ParseSocketsList(response);
179 if (sockets_.size() == 0) {
180 serials_.pop_back();
181 ProcessSerials();
182 } else {
183 ProcessSockets(model);
184 }
185 }
186
187 void ProcessSockets(const std::string& model) {
188 if (sockets_.size() == 0) {
189 serials_.pop_back();
190 ProcessSerials();
191 } else {
192 AdbClientSocket::HttpQuery(
[email protected]817b3f12013-04-25 18:10:21193 kAdbPort, serials_.back(), sockets_.back(), kVersionRequest,
194 base::Bind(&AdbPagesCommand::ReceivedVersion, this, model));
195 }
196 }
197
198 void ReceivedVersion(const std::string& model,
199 int result,
200 const std::string& response) {
201 if (result < 0) {
202 sockets_.pop_back();
203 ProcessSockets(model);
204 return;
205 }
206
207 // Parse version, append to package name if available,
208 std::string body = response.substr(result);
209 scoped_ptr<base::Value> value(base::JSONReader::Read(body));
210 base::DictionaryValue* dict;
211 if (value && value->GetAsDictionary(&dict)) {
212 std::string browser;
213 if (dict->GetString("Browser", &browser)) {
214 socket_to_package_[sockets_.back()] = base::StringPrintf(
215 "%s (%s)", socket_to_package_[sockets_.back()].c_str(),
216 browser.c_str());
217 }
218 }
219
220 AdbClientSocket::HttpQuery(
[email protected]2ce6d312013-04-23 15:58:55221 kAdbPort, serials_.back(), sockets_.back(), kPageListRequest,
222 base::Bind(&AdbPagesCommand::ReceivedPages, this, model));
[email protected]49d892062013-03-26 06:18:41223 }
224
225 void ReceivedPages(const std::string& model,
226 int result,
227 const std::string& response) {
[email protected]2ce6d312013-04-23 15:58:55228 std::string socket = sockets_.back();
229 sockets_.pop_back();
[email protected]49d892062013-03-26 06:18:41230 if (result < 0) {
[email protected]2ce6d312013-04-23 15:58:55231 ProcessSockets(model);
[email protected]49d892062013-03-26 06:18:41232 return;
233 }
234
[email protected]2ce6d312013-04-23 15:58:55235 std::string serial = serials_.back();
236
[email protected]49d892062013-03-26 06:18:41237 std::string body = response.substr(result);
238 scoped_ptr<base::Value> value(base::JSONReader::Read(body));
239 base::ListValue* list_value;
240 if (!value || !value->GetAsList(&list_value)) {
[email protected]2ce6d312013-04-23 15:58:55241 ProcessSockets(model);
[email protected]49d892062013-03-26 06:18:41242 return;
243 }
244
245 base::Value* item;
246 for (size_t i = 0; i < list_value->GetSize(); ++i) {
247 list_value->Get(i, &item);
248 base::DictionaryValue* dict;
249 if (!item || !item->GetAsDictionary(&dict))
250 continue;
251 pages_->push_back(
[email protected]2ce6d312013-04-23 15:58:55252 new DevToolsAdbBridge::RemotePage(
253 serial, model, socket_to_package_[socket], socket, *dict));
[email protected]49d892062013-03-26 06:18:41254 }
[email protected]2ce6d312013-04-23 15:58:55255 ProcessSockets(model);
[email protected]49d892062013-03-26 06:18:41256 }
257
258 void Respond() {
259 callback_.Run(net::OK, pages_.release());
260 }
261
[email protected]2ce6d312013-04-23 15:58:55262 void ParseSocketsList(const std::string& response) {
263 // On Android, '/proc/net/unix' looks like this:
264 //
265 // Num RefCount Protocol Flags Type St Inode Path
266 // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote
267 // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote
268 // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote
269 //
270 // We need to find records with paths starting from '@' (abstract socket)
271 // and containing "devtools_remote". We have to extract the inode number
272 // in order to find the owning process name.
273
274 socket_to_package_.clear();
275 std::vector<std::string> entries;
276 Tokenize(response, "\n", &entries);
277 const std::string channel_pattern = kDevToolsChannelPattern;
278 for (size_t i = 1; i < entries.size(); ++i) {
279 std::vector<std::string> fields;
280 Tokenize(entries[i], " ", &fields);
281 if (fields.size() < 8)
282 continue;
[email protected]817b3f12013-04-25 18:10:21283 if (fields[3] != "00010000" || fields[5] != "01")
284 continue;
[email protected]2ce6d312013-04-23 15:58:55285 std::string path_field = fields[7];
286 if (path_field.size() < 1 || path_field[0] != '@')
287 continue;
288 size_t socket_name_pos = path_field.find(channel_pattern);
289 if (socket_name_pos == std::string::npos)
290 continue;
291 std::string socket = path_field.substr(1, path_field.size() - 2);
292 sockets_.push_back(socket);
293 std::string package = path_field.substr(1, socket_name_pos - 2);
294 if (socket_name_pos + channel_pattern.size() < path_field.size() - 1) {
295 package += path_field.substr(
296 socket_name_pos + channel_pattern.size(), path_field.size() - 1);
297 }
298 package[0] = base::ToUpperASCII(package[0]);
299 socket_to_package_[socket] = package;
300 }
301 }
302
[email protected]49d892062013-03-26 06:18:41303 PagesCallback callback_;
304 std::vector<std::string> serials_;
[email protected]2ce6d312013-04-23 15:58:55305 std::vector<std::string> sockets_;
306 std::map<std::string, std::string> socket_to_package_;
[email protected]49d892062013-03-26 06:18:41307 scoped_ptr<DevToolsAdbBridge::RemotePages> pages_;
308};
309
[email protected]cf57e1b2013-03-27 14:29:43310} // namespace
311
312class AgentHostDelegate;
313
314typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates;
315
316base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates =
317 LAZY_INSTANCE_INITIALIZER;
318
319class AgentHostDelegate : public base::RefCountedThreadSafe<AgentHostDelegate>,
320 public content::DevToolsExternalAgentProxyDelegate {
321 public:
322 AgentHostDelegate(
323 const std::string& id,
[email protected]eafc8452013-04-16 04:18:35324 const std::string& serial,
[email protected]cf57e1b2013-03-27 14:29:43325 scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread,
[email protected]37066c42013-04-15 13:08:05326 net::StreamSocket* socket)
[email protected]cf57e1b2013-03-27 14:29:43327 : id_(id),
[email protected]eafc8452013-04-16 04:18:35328 serial_(serial),
[email protected]cf57e1b2013-03-27 14:29:43329 adb_thread_(adb_thread),
[email protected]eafc8452013-04-16 04:18:35330 socket_(socket),
331 tethering_adb_filter_(kAdbPort, serial) {
[email protected]cf57e1b2013-03-27 14:29:43332 AddRef(); // Balanced in SelfDestruct.
333 proxy_.reset(content::DevToolsExternalAgentProxy::Create(this));
334 g_host_delegates.Get()[id] = this;
335 }
336
337 scoped_refptr<content::DevToolsAgentHost> GetAgentHost() {
338 return proxy_->GetAgentHost();
339 }
340
341 private:
342 friend class base::RefCountedThreadSafe<AgentHostDelegate>;
343
344 virtual ~AgentHostDelegate() {
345 g_host_delegates.Get().erase(id_);
346 }
347
348 virtual void Attach() OVERRIDE {
349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
350 adb_thread_->message_loop()->PostTask(
351 FROM_HERE,
352 base::Bind(&AgentHostDelegate::StartListeningOnHandlerThread, this));
353 }
354
355 virtual void Detach() OVERRIDE {
356 adb_thread_->message_loop()->PostTask(
357 FROM_HERE,
358 base::Bind(&AgentHostDelegate::CloseConnection, this, net::OK, false));
359 }
360
361 virtual void SendMessageToBackend(const std::string& message) OVERRIDE {
362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
363 adb_thread_->message_loop()->PostTask(
364 FROM_HERE,
365 base::Bind(&AgentHostDelegate::SendFrameOnHandlerThread, this,
366 message));
367 }
368
369 void StartListeningOnHandlerThread() {
370 scoped_refptr<net::IOBuffer> response_buffer =
371 new net::IOBuffer(kBufferSize);
[email protected]dc24976f2013-06-02 21:15:09372 int result = socket_->Read(
373 response_buffer.get(),
374 kBufferSize,
[email protected]cf57e1b2013-03-27 14:29:43375 base::Bind(&AgentHostDelegate::OnBytesRead, this, response_buffer));
376 if (result != net::ERR_IO_PENDING)
377 OnBytesRead(response_buffer, result);
378 }
379
380 void OnBytesRead(scoped_refptr<net::IOBuffer> response_buffer, int result) {
381 if (!socket_)
382 return;
383
384 if (result <= 0) {
385 CloseIfNecessary(net::ERR_CONNECTION_CLOSED);
386 return;
387 }
388
389 std::string data = std::string(response_buffer->data(), result);
390 response_buffer_ += data;
391
392 int bytes_consumed;
393 std::string output;
394 WebSocket::ParseResult parse_result = WebSocket::DecodeFrameHybi17(
395 response_buffer_, false, &bytes_consumed, &output);
396
397 while (parse_result == WebSocket::FRAME_OK) {
398 response_buffer_ = response_buffer_.substr(bytes_consumed);
[email protected]eafc8452013-04-16 04:18:35399 if (!tethering_adb_filter_.ProcessIncomingMessage(output)) {
400 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
401 base::Bind(&AgentHostDelegate::OnFrameRead, this, output));
402 }
[email protected]cf57e1b2013-03-27 14:29:43403 parse_result = WebSocket::DecodeFrameHybi17(
404 response_buffer_, false, &bytes_consumed, &output);
405 }
406
407 if (parse_result == WebSocket::FRAME_ERROR ||
408 parse_result == WebSocket::FRAME_CLOSE) {
409 CloseIfNecessary(net::ERR_CONNECTION_CLOSED);
410 return;
411 }
412
[email protected]dc24976f2013-06-02 21:15:09413 result = socket_->Read(
414 response_buffer.get(),
415 kBufferSize,
[email protected]cf57e1b2013-03-27 14:29:43416 base::Bind(&AgentHostDelegate::OnBytesRead, this, response_buffer));
417 if (result != net::ERR_IO_PENDING)
418 OnBytesRead(response_buffer, result);
419 }
420
421 void SendFrameOnHandlerThread(const std::string& data) {
[email protected]eafc8452013-04-16 04:18:35422 tethering_adb_filter_.ProcessOutgoingMessage(data);
[email protected]cf57e1b2013-03-27 14:29:43423 int mask = base::RandInt(0, 0x7FFFFFFF);
424 std::string encoded_frame = WebSocket::EncodeFrameHybi17(data, mask);
425 scoped_refptr<net::StringIOBuffer> request_buffer =
426 new net::StringIOBuffer(encoded_frame);
427 if (!socket_)
428 return;
[email protected]dc24976f2013-06-02 21:15:09429 int result =
430 socket_->Write(request_buffer.get(),
431 request_buffer->size(),
432 base::Bind(&AgentHostDelegate::CloseIfNecessary, this));
[email protected]cf57e1b2013-03-27 14:29:43433 if (result != net::ERR_IO_PENDING)
434 CloseIfNecessary(result);
435 }
436
437 void CloseConnection(int result, bool initiated_by_me) {
438 if (!socket_)
439 return;
440 socket_->Disconnect();
441 socket_.reset();
442 if (initiated_by_me) {
443 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
444 base::Bind(&AgentHostDelegate::OnSocketClosed, this, result));
445 }
446 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
447 base::Bind(&AgentHostDelegate::SelfDestruct, this));
448 }
449
450 void SelfDestruct() {
451 Release(); // Balanced in constructor.
452 }
453
454 void CloseIfNecessary(int result) {
455 if (result >= 0)
456 return;
457 CloseConnection(result, true);
458 }
459
460 void OnFrameRead(const std::string& message) {
[email protected]94305ee92013-04-01 14:19:58461 proxy_->DispatchOnClientHost(message);
[email protected]cf57e1b2013-03-27 14:29:43462 }
463
464 void OnSocketClosed(int result) {
465 proxy_->ConnectionClosed();
466 }
467
468 std::string id_;
[email protected]eafc8452013-04-16 04:18:35469 std::string serial_;
[email protected]cf57e1b2013-03-27 14:29:43470 scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> adb_thread_;
[email protected]37066c42013-04-15 13:08:05471 scoped_ptr<net::StreamSocket> socket_;
[email protected]cf57e1b2013-03-27 14:29:43472 scoped_ptr<content::DevToolsExternalAgentProxy> proxy_;
473 std::string response_buffer_;
[email protected]eafc8452013-04-16 04:18:35474 TetheringAdbFilter tethering_adb_filter_;
[email protected]cf57e1b2013-03-27 14:29:43475 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
476};
477
[email protected]49d892062013-03-26 06:18:41478class AdbAttachCommand : public base::RefCounted<AdbAttachCommand> {
479 public:
[email protected]2ce6d312013-04-23 15:58:55480 AdbAttachCommand(const base::WeakPtr<DevToolsAdbBridge>& bridge,
481 const std::string& serial,
482 const std::string& socket,
483 const std::string& debug_url,
484 const std::string& frontend_url)
[email protected]cf57e1b2013-03-27 14:29:43485 : bridge_(bridge),
486 serial_(serial),
[email protected]2ce6d312013-04-23 15:58:55487 socket_(socket),
[email protected]cf57e1b2013-03-27 14:29:43488 debug_url_(debug_url),
489 frontend_url_(frontend_url) {
[email protected]49d892062013-03-26 06:18:41490 }
491
492 void Run() {
493 AdbClientSocket::HttpQuery(
[email protected]2ce6d312013-04-23 15:58:55494 kAdbPort, serial_, socket_,
[email protected]cf57e1b2013-03-27 14:29:43495 base::StringPrintf(kWebSocketUpgradeRequest, debug_url_.c_str()),
[email protected]49d892062013-03-26 06:18:41496 base::Bind(&AdbAttachCommand::Handle, this));
497 }
498
499 private:
500 friend class base::RefCounted<AdbAttachCommand>;
501 virtual ~AdbAttachCommand() {}
502
[email protected]37066c42013-04-15 13:08:05503 void Handle(int result, net::StreamSocket* socket) {
[email protected]49d892062013-03-26 06:18:41504 if (result != net::OK || socket == NULL)
505 return;
506
507 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
508 base::Bind(&AdbAttachCommand::OpenDevToolsWindow, this, socket));
509 }
510
[email protected]37066c42013-04-15 13:08:05511 void OpenDevToolsWindow(net::StreamSocket* socket) {
[email protected]49d892062013-03-26 06:18:41512 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]cf57e1b2013-03-27 14:29:43513
514 DevToolsAdbBridge* bridge = bridge_.get();
515 if (!bridge)
516 return;
517
518 std::string id = base::StringPrintf("%s:%s", serial_.c_str(),
519 debug_url_.c_str());
520 AgentHostDelegates::iterator it = g_host_delegates.Get().find(id);
521 AgentHostDelegate* delegate;
522 if (it != g_host_delegates.Get().end())
523 delegate = it->second;
524 else
[email protected]eafc8452013-04-16 04:18:35525 delegate = new AgentHostDelegate(id, serial_, bridge->adb_thread_,
526 socket);
[email protected]cadac622013-06-11 16:46:36527 DevToolsWindow::OpenExternalFrontend(
528 bridge->profile_, frontend_url_, delegate->GetAgentHost().get());
[email protected]49d892062013-03-26 06:18:41529 }
530
[email protected]cf57e1b2013-03-27 14:29:43531 base::WeakPtr<DevToolsAdbBridge> bridge_;
532 std::string serial_;
[email protected]2ce6d312013-04-23 15:58:55533 std::string socket_;
[email protected]cf57e1b2013-03-27 14:29:43534 std::string debug_url_;
535 std::string frontend_url_;
[email protected]49d892062013-03-26 06:18:41536};
[email protected]50a80dd2013-03-11 17:37:40537
[email protected]49d892062013-03-26 06:18:41538DevToolsAdbBridge::RemotePage::RemotePage(const std::string& serial,
539 const std::string& model,
[email protected]2ce6d312013-04-23 15:58:55540 const std::string& package,
541 const std::string& socket,
[email protected]49d892062013-03-26 06:18:41542 const base::DictionaryValue& value)
[email protected]29b0a202013-03-22 09:34:15543 : serial_(serial),
[email protected]2ce6d312013-04-23 15:58:55544 model_(model),
545 package_(package),
546 socket_(socket) {
[email protected]29b0a202013-03-22 09:34:15547 value.GetString("id", &id_);
[email protected]49d892062013-03-26 06:18:41548 value.GetString("url", &url_);
[email protected]29b0a202013-03-22 09:34:15549 value.GetString("title", &title_);
550 value.GetString("descirption", &description_);
551 value.GetString("faviconUrl", &favicon_url_);
552 value.GetString("webSocketDebuggerUrl", &debug_url_);
[email protected]49d892062013-03-26 06:18:41553 value.GetString("devtoolsFrontendUrl", &frontend_url_);
554
555 if (debug_url_.find("ws://") == 0)
556 debug_url_ = debug_url_.substr(5);
557 else
558 debug_url_ = "";
559
560 size_t ws_param = frontend_url_.find("?ws");
561 if (ws_param != std::string::npos)
562 frontend_url_ = frontend_url_.substr(0, ws_param);
[email protected]cf57e1b2013-03-27 14:29:43563 if (frontend_url_.find("http:") == 0)
564 frontend_url_ = "https:" + frontend_url_.substr(5);
[email protected]29b0a202013-03-22 09:34:15565}
566
[email protected]49d892062013-03-26 06:18:41567DevToolsAdbBridge::RemotePage::~RemotePage() {
568}
569
570DevToolsAdbBridge::RefCountedAdbThread*
571DevToolsAdbBridge::RefCountedAdbThread::instance_ = NULL;
572
573// static
574scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread>
575DevToolsAdbBridge::RefCountedAdbThread::GetInstance() {
576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
577 if (!instance_)
578 new RefCountedAdbThread();
579 return instance_;
580}
581
582DevToolsAdbBridge::RefCountedAdbThread::RefCountedAdbThread() {
583 instance_ = this;
584 thread_ = new base::Thread(kDevToolsAdbBridgeThreadName);
585 base::Thread::Options options;
[email protected]b3a25092013-05-28 22:08:16586 options.message_loop_type = base::MessageLoop::TYPE_IO;
[email protected]49d892062013-03-26 06:18:41587 if (!thread_->StartWithOptions(options)) {
588 delete thread_;
589 thread_ = NULL;
590 }
591}
592
[email protected]9e7154122013-05-30 23:11:04593base::MessageLoop* DevToolsAdbBridge::RefCountedAdbThread::message_loop() {
[email protected]49d892062013-03-26 06:18:41594 return thread_ ? thread_->message_loop() : NULL;
[email protected]29b0a202013-03-22 09:34:15595}
596
[email protected]50a80dd2013-03-11 17:37:40597// static
[email protected]49d892062013-03-26 06:18:41598void DevToolsAdbBridge::RefCountedAdbThread::StopThread(base::Thread* thread) {
599 thread->Stop();
[email protected]50a80dd2013-03-11 17:37:40600}
601
[email protected]49d892062013-03-26 06:18:41602DevToolsAdbBridge::RefCountedAdbThread::~RefCountedAdbThread() {
[email protected]50a80dd2013-03-11 17:37:40603 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]49d892062013-03-26 06:18:41604 instance_ = NULL;
605 if (!thread_)
[email protected]50a80dd2013-03-11 17:37:40606 return;
[email protected]49d892062013-03-26 06:18:41607 // Shut down thread on FILE thread to join into IO.
608 BrowserThread::PostTask(
[email protected]50a80dd2013-03-11 17:37:40609 BrowserThread::FILE, FROM_HERE,
[email protected]49d892062013-03-26 06:18:41610 base::Bind(&RefCountedAdbThread::StopThread, thread_));
611}
612
613DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile)
614 : profile_(profile),
615 adb_thread_(RefCountedAdbThread::GetInstance()),
[email protected]9c009092013-05-01 03:14:09616 weak_factory_(this),
[email protected]49d892062013-03-26 06:18:41617 has_message_loop_(adb_thread_->message_loop() != NULL) {
618}
619
620DevToolsAdbBridge::~DevToolsAdbBridge() {
621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]50a80dd2013-03-11 17:37:40622}
623
624void DevToolsAdbBridge::Query(
625 const std::string query,
626 const Callback& callback) {
627 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]49d892062013-03-26 06:18:41628 if (!has_message_loop_) {
629 callback.Run(net::ERR_FAILED, "Could not start ADB thread");
[email protected]50a80dd2013-03-11 17:37:40630 return;
631 }
[email protected]49d892062013-03-26 06:18:41632 scoped_refptr<AdbQueryCommand> command(new AdbQueryCommand(query, callback));
633 adb_thread_->message_loop()->PostTask(FROM_HERE,
634 base::Bind(&AdbQueryCommand::Run, command));
[email protected]29b0a202013-03-22 09:34:15635}
636
[email protected]49d892062013-03-26 06:18:41637void DevToolsAdbBridge::Pages(const PagesCallback& callback) {
[email protected]29b0a202013-03-22 09:34:15638 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]49d892062013-03-26 06:18:41639 if (!has_message_loop_)
[email protected]29b0a202013-03-22 09:34:15640 return;
641
[email protected]49d892062013-03-26 06:18:41642 scoped_refptr<AdbPagesCommand> command(new AdbPagesCommand(callback));
643 adb_thread_->message_loop()->PostTask(FROM_HERE,
644 base::Bind(&AdbPagesCommand::Run, command));
[email protected]50a80dd2013-03-11 17:37:40645}
646
[email protected]cf57e1b2013-03-27 14:29:43647void DevToolsAdbBridge::Attach(const std::string& serial,
[email protected]2ce6d312013-04-23 15:58:55648 const std::string& socket,
[email protected]cf57e1b2013-03-27 14:29:43649 const std::string& debug_url,
650 const std::string& frontend_url) {
[email protected]50a80dd2013-03-11 17:37:40651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]49d892062013-03-26 06:18:41652 if (!has_message_loop_)
[email protected]50a80dd2013-03-11 17:37:40653 return;
[email protected]50a80dd2013-03-11 17:37:40654
[email protected]cf57e1b2013-03-27 14:29:43655 scoped_refptr<AdbAttachCommand> command(
[email protected]2ce6d312013-04-23 15:58:55656 new AdbAttachCommand(weak_factory_.GetWeakPtr(), serial, socket,
657 debug_url, frontend_url));
[email protected]49d892062013-03-26 06:18:41658 adb_thread_->message_loop()->PostTask(
659 FROM_HERE,
660 base::Bind(&AdbAttachCommand::Run, command));
[email protected]50a80dd2013-03-11 17:37:40661}