1 // 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 7 #include <map> 8 #include <vector> 9 10 #include "base/base64.h" 11 #include "base/bind.h" 12 #include "base/command_line.h" 13 #include "base/compiler_specific.h" 14 #include "base/json/json_reader.h" 15 #include "base/lazy_instance.h" 16 #include "base/logging.h" 17 #include "base/memory/singleton.h" 18 #include "base/message_loop/message_loop.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/stringprintf.h" 22 #include "base/threading/thread.h" 23 #include "base/values.h" 24 #include "chrome/browser/devtools/adb/android_rsa.h" 25 #include "chrome/browser/devtools/adb_client_socket.h" 26 #include "chrome/browser/devtools/adb_web_socket.h" 27 #include "chrome/browser/devtools/devtools_protocol.h" 28 #include "chrome/browser/devtools/devtools_window.h" 29 #include "chrome/browser/devtools/tethering_adb_filter.h" 30 #include "chrome/browser/profiles/profile.h" 31 #include "chrome/common/chrome_switches.h" 32 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h" 33 #include "content/public/browser/devtools_agent_host.h" 34 #include "content/public/browser/devtools_client_host.h" 35 #include "content/public/browser/devtools_external_agent_proxy.h" 36 #include "content/public/browser/devtools_external_agent_proxy_delegate.h" 37 #include "content/public/browser/devtools_manager.h" 38 #include "crypto/rsa_private_key.h" 39 #include "net/base/net_errors.h" 40 41 using content::BrowserThread; 42 43 namespace { 44 45 static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread"; 46 static const char kHostDevicesCommand[] = "host:devices"; 47 static const char kHostTransportCommand[] = "host:transport:%s|%s"; 48 static const char kLocalAbstractCommand[] = "localabstract:%s"; 49 static const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; 50 static const char kLocalChrome[] = "Local Chrome"; 51 static const char kChrome[] = "Chrome"; 52 static const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; 53 54 static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n"; 55 static const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n"; 56 static const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n"; 57 static const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n"; 58 const int kAdbPort = 5037; 59 const int kBufferSize = 16 * 1024; 60 const int kAdbPollingIntervalMs = 1000; 61 62 static const char kUrlParam[] = "url"; 63 static const char kPageReloadCommand[] = "Page.reload"; 64 static const char kPageNavigateCommand[] = "Page.navigate"; 65 66 typedef DevToolsAdbBridge::Callback Callback; 67 typedef std::vector<scoped_refptr<DevToolsAdbBridge::AndroidDevice> > 68 AndroidDevices; 69 typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback; 70 71 class AdbDeviceImpl : public DevToolsAdbBridge::AndroidDevice { 72 public: 73 explicit AdbDeviceImpl(const std::string& serial) 74 : AndroidDevice(serial) { 75 } 76 77 virtual void RunCommand(const std::string& command, 78 const CommandCallback& callback) OVERRIDE { 79 std::string query = base::StringPrintf(kHostTransportCommand, 80 serial().c_str(), command.c_str()); 81 AdbClientSocket::AdbQuery(kAdbPort, query, callback); 82 } 83 84 virtual void OpenSocket(const std::string& name, 85 const SocketCallback& callback) OVERRIDE { 86 std::string socket_name = 87 base::StringPrintf(kLocalAbstractCommand, name.c_str()); 88 AdbClientSocket::TransportQuery(kAdbPort, serial(), socket_name, callback); 89 } 90 private: 91 virtual ~AdbDeviceImpl() {} 92 }; 93 94 class UsbDeviceImpl : public DevToolsAdbBridge::AndroidDevice { 95 public: 96 explicit UsbDeviceImpl(AndroidUsbDevice* device) 97 : AndroidDevice(device->serial()), 98 device_(device) { 99 } 100 101 virtual void RunCommand(const std::string& command, 102 const CommandCallback& callback) OVERRIDE { 103 net::StreamSocket* socket = device_->CreateSocket(command); 104 int result = socket->Connect(base::Bind(&UsbDeviceImpl::OpenedForCommand, 105 this, callback, socket)); 106 if (result != net::ERR_IO_PENDING) 107 callback.Run(result, std::string()); 108 } 109 110 virtual void OpenSocket(const std::string& name, 111 const SocketCallback& callback) OVERRIDE { 112 std::string socket_name = 113 base::StringPrintf(kLocalAbstractCommand, name.c_str()); 114 net::StreamSocket* socket = device_->CreateSocket(socket_name); 115 int result = socket->Connect(base::Bind(&UsbDeviceImpl::OnOpenSocket, this, 116 callback, socket)); 117 if (result != net::ERR_IO_PENDING) 118 callback.Run(result, NULL); 119 } 120 121 private: 122 void OnOpenSocket(const SocketCallback& callback, 123 net::StreamSocket* socket, 124 int result) { 125 callback.Run(result, result == net::OK ? socket : NULL); 126 } 127 128 void OpenedForCommand(const CommandCallback& callback, 129 net::StreamSocket* socket, 130 int result) { 131 if (result != net::OK) { 132 callback.Run(result, std::string()); 133 return; 134 } 135 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kBufferSize); 136 result = socket->Read(buffer, kBufferSize, 137 base::Bind(&UsbDeviceImpl::OnRead, this, 138 socket, buffer, std::string(), callback)); 139 if (result != net::ERR_IO_PENDING) 140 OnRead(socket, buffer, std::string(), callback, result); 141 } 142 143 void OnRead(net::StreamSocket* socket, 144 scoped_refptr<net::IOBuffer> buffer, 145 const std::string& data, 146 const CommandCallback& callback, 147 int result) { 148 if (result <= 0) { 149 callback.Run(result, result == 0 ? data : std::string()); 150 delete socket; 151 return; 152 } 153 154 std::string new_data = data + std::string(buffer->data(), result); 155 result = socket->Read(buffer, kBufferSize, 156 base::Bind(&UsbDeviceImpl::OnRead, this, 157 socket, buffer, new_data, callback)); 158 if (result != net::ERR_IO_PENDING) 159 OnRead(socket, buffer, new_data, callback, result); 160 } 161 162 virtual ~UsbDeviceImpl() {} 163 scoped_refptr<AndroidUsbDevice> device_; 164 }; 165 166 class AdbPagesCommand : public base::RefCountedThreadSafe< 167 AdbPagesCommand, 168 content::BrowserThread::DeleteOnUIThread> { 169 public: 170 typedef base::Callback<void(DevToolsAdbBridge::RemoteDevices*)> Callback; 171 172 AdbPagesCommand(DevToolsAdbBridge* bridge, const Callback& callback) 173 : bridge_(bridge), 174 callback_(callback) { 175 remote_devices_.reset(new DevToolsAdbBridge::RemoteDevices()); 176 bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE, 177 base::Bind(&DevToolsAdbBridge::EnumerateUsbDevices, bridge_, 178 base::Bind(&AdbPagesCommand::ReceivedUsbDevices, this))); 179 } 180 181 private: 182 friend struct content::BrowserThread::DeleteOnThread< 183 content::BrowserThread::UI>; 184 friend class base::DeleteHelper<AdbPagesCommand>; 185 186 virtual ~AdbPagesCommand() { 187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 188 } 189 190 void ReceivedUsbDevices(const AndroidDevices& devices) { 191 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 192 devices_ = devices; 193 bridge_->EnumerateAdbDevices( 194 base::Bind(&AdbPagesCommand::ReceivedAdbDevices, this)); 195 } 196 197 void ReceivedAdbDevices(const AndroidDevices& devices) { 198 devices_.insert(devices_.end(), devices.begin(), devices.end()); 199 ProcessSerials(); 200 } 201 202 void ProcessSerials() { 203 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 204 if (devices_.size() == 0) { 205 BrowserThread::PostTask( 206 BrowserThread::UI, FROM_HERE, 207 base::Bind(&AdbPagesCommand::Respond, this)); 208 return; 209 } 210 211 #if defined(DEBUG_DEVTOOLS) 212 // For desktop remote debugging. 213 if (devices_.back()->serial().empty()) { 214 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = 215 devices_.back(); 216 device->set_model(kLocalChrome); 217 remote_devices_->push_back( 218 new DevToolsAdbBridge::RemoteDevice(bridge_, device)); 219 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser = 220 new DevToolsAdbBridge::RemoteBrowser(bridge_, device, std::string()); 221 remote_browser->set_product(kChrome); 222 remote_devices_->back()->AddBrowser(remote_browser); 223 browsers_.push_back(remote_browser); 224 device->HttpQuery( 225 std::string(), kVersionRequest, 226 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); 227 return; 228 } 229 #endif // defined(DEBUG_DEVTOOLS) 230 231 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); 232 device->RunCommand(kDeviceModelCommand, 233 base::Bind(&AdbPagesCommand::ReceivedModel, this)); 234 } 235 236 void ReceivedModel(int result, const std::string& response) { 237 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 238 if (result < 0) { 239 devices_.pop_back(); 240 ProcessSerials(); 241 return; 242 } 243 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); 244 device->set_model(response); 245 remote_devices_->push_back( 246 new DevToolsAdbBridge::RemoteDevice(bridge_, device)); 247 device->RunCommand(kOpenedUnixSocketsCommand, 248 base::Bind(&AdbPagesCommand::ReceivedSockets, this)); 249 } 250 251 void ReceivedSockets(int result, 252 const std::string& response) { 253 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 254 if (result < 0) { 255 devices_.pop_back(); 256 ProcessSerials(); 257 return; 258 } 259 260 ParseSocketsList(response); 261 if (browsers_.size() == 0) { 262 devices_.pop_back(); 263 ProcessSerials(); 264 } else { 265 ProcessSockets(); 266 } 267 } 268 269 void ProcessSockets() { 270 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 271 if (browsers_.size() == 0) { 272 devices_.pop_back(); 273 ProcessSerials(); 274 } else { 275 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); 276 device->HttpQuery(browsers_.back()->socket(), kVersionRequest, 277 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); 278 } 279 } 280 281 void ReceivedVersion(int result, 282 const std::string& response) { 283 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 284 if (result < 0) { 285 browsers_.pop_back(); 286 ProcessSockets(); 287 return; 288 } 289 290 // Parse version, append to package name if available, 291 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); 292 base::DictionaryValue* dict; 293 if (value && value->GetAsDictionary(&dict)) { 294 std::string browser; 295 if (dict->GetString("Browser", &browser)) { 296 std::vector<std::string> parts; 297 Tokenize(browser, "/", &parts); 298 if (parts.size() == 2) { 299 if (parts[0] != "Version") // WebView has this for legacy reasons. 300 browsers_.back()->set_product(parts[0]); 301 browsers_.back()->set_version(parts[1]); 302 } else { 303 browsers_.back()->set_version(browser); 304 } 305 } 306 } 307 308 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); 309 device->HttpQuery(browsers_.back()->socket(), kPageListRequest, 310 base::Bind(&AdbPagesCommand::ReceivedPages, this)); 311 } 312 313 void ReceivedPages(int result, 314 const std::string& response) { 315 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); 316 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = browsers_.back(); 317 browsers_.pop_back(); 318 if (result < 0) { 319 ProcessSockets(); 320 return; 321 } 322 323 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); 324 base::ListValue* list_value; 325 if (!value || !value->GetAsList(&list_value)) { 326 ProcessSockets(); 327 return; 328 } 329 330 base::Value* item; 331 332 for (size_t i = 0; i < list_value->GetSize(); ++i) { 333 list_value->Get(i, &item); 334 base::DictionaryValue* dict; 335 if (!item || !item->GetAsDictionary(&dict)) 336 continue; 337 browser->AddPage(new DevToolsAdbBridge::RemotePage( 338 bridge_, browser->device(), browser->socket(), *dict)); 339 } 340 ProcessSockets(); 341 } 342 343 void Respond() { 344 callback_.Run(remote_devices_.release()); 345 } 346 347 void ParseSocketsList(const std::string& response) { 348 // On Android, '/proc/net/unix' looks like this: 349 // 350 // Num RefCount Protocol Flags Type St Inode Path 351 // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote 352 // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote 353 // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote 354 // 355 // We need to find records with paths starting from '@' (abstract socket) 356 // and containing "devtools_remote". We have to extract the inode number 357 // in order to find the owning process name. 358 359 scoped_refptr<DevToolsAdbBridge::RemoteDevice> remote_device = 360 remote_devices_->back(); 361 362 std::vector<std::string> entries; 363 Tokenize(response, "\n", &entries); 364 const std::string channel_pattern = 365 base::StringPrintf(kDevToolsChannelNameFormat, ""); 366 for (size_t i = 1; i < entries.size(); ++i) { 367 std::vector<std::string> fields; 368 Tokenize(entries[i], " ", &fields); 369 if (fields.size() < 8) 370 continue; 371 if (fields[3] != "00010000" || fields[5] != "01") 372 continue; 373 std::string path_field = fields[7]; 374 if (path_field.size() < 1 || path_field[0] != '@') 375 continue; 376 size_t socket_name_pos = path_field.find(channel_pattern); 377 if (socket_name_pos == std::string::npos) 378 continue; 379 std::string socket = path_field.substr(1, path_field.size() - 2); 380 std::string package = path_field.substr(1, socket_name_pos - 1); 381 if (socket_name_pos + channel_pattern.size() < path_field.size() - 1) { 382 package += path_field.substr( 383 socket_name_pos + channel_pattern.size(), path_field.size() - 1); 384 } 385 package[0] = base::ToUpperASCII(package[0]); 386 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser = 387 new DevToolsAdbBridge::RemoteBrowser( 388 bridge_, remote_device->device(), socket); 389 remote_browser->set_product(package); 390 remote_device->AddBrowser(remote_browser); 391 } 392 browsers_ = remote_device->browsers(); 393 } 394 395 scoped_refptr<DevToolsAdbBridge> bridge_; 396 Callback callback_; 397 AndroidDevices devices_; 398 DevToolsAdbBridge::RemoteBrowsers browsers_; 399 scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_; 400 }; 401 402 // AdbProtocolCommand --------------------------------------------------------- 403 404 class AdbProtocolCommand : public AdbWebSocket::Delegate { 405 public: 406 AdbProtocolCommand( 407 scoped_refptr<DevToolsAdbBridge> bridge_, 408 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device, 409 const std::string& socket_name, 410 const std::string& debug_url, 411 const std::string& command); 412 413 private: 414 virtual void OnSocketOpened() OVERRIDE; 415 virtual void OnFrameRead(const std::string& message) OVERRIDE; 416 virtual void OnSocketClosed(bool closed_by_device) OVERRIDE; 417 virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE; 418 419 scoped_refptr<DevToolsAdbBridge> bridge_; 420 const std::string command_; 421 scoped_refptr<AdbWebSocket> web_socket_; 422 423 DISALLOW_COPY_AND_ASSIGN(AdbProtocolCommand); 424 }; 425 426 AdbProtocolCommand::AdbProtocolCommand( 427 scoped_refptr<DevToolsAdbBridge> bridge, 428 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device, 429 const std::string& socket_name, 430 const std::string& debug_url, 431 const std::string& command) 432 : bridge_(bridge), 433 command_(command) { 434 web_socket_ = new AdbWebSocket( 435 device, socket_name, debug_url, bridge_->GetAdbMessageLoop(), this); 436 } 437 438 void AdbProtocolCommand::OnSocketOpened() { 439 web_socket_->SendFrame(command_); 440 web_socket_->Disconnect(); 441 } 442 443 void AdbProtocolCommand::OnFrameRead(const std::string& message) {} 444 445 void AdbProtocolCommand::OnSocketClosed(bool closed_by_device) { 446 delete this; 447 } 448 449 bool AdbProtocolCommand::ProcessIncomingMessage(const std::string& message) { 450 return false; 451 } 452 453 } // namespace 454 455 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote"; 456 457 class AgentHostDelegate; 458 459 typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates; 460 461 base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates = 462 LAZY_INSTANCE_INITIALIZER; 463 464 DevToolsAdbBridge::Wrapper::Wrapper(Profile* profile) 465 : bridge_(new DevToolsAdbBridge(profile)) { 466 } 467 468 DevToolsAdbBridge::Wrapper::~Wrapper() { 469 } 470 471 DevToolsAdbBridge* DevToolsAdbBridge::Wrapper::Get() { 472 return bridge_.get(); 473 } 474 475 // static 476 DevToolsAdbBridge::Factory* DevToolsAdbBridge::Factory::GetInstance() { 477 return Singleton<DevToolsAdbBridge::Factory>::get(); 478 } 479 480 // static 481 DevToolsAdbBridge* DevToolsAdbBridge::Factory::GetForProfile( 482 Profile* profile) { 483 DevToolsAdbBridge::Wrapper* wrapper = 484 static_cast<DevToolsAdbBridge::Wrapper*>(GetInstance()-> 485 GetServiceForBrowserContext(profile, true)); 486 return wrapper ? wrapper->Get() : NULL; 487 } 488 489 DevToolsAdbBridge::Factory::Factory() 490 : BrowserContextKeyedServiceFactory( 491 "DevToolsAdbBridge", 492 BrowserContextDependencyManager::GetInstance()) {} 493 494 DevToolsAdbBridge::Factory::~Factory() {} 495 496 BrowserContextKeyedService* 497 DevToolsAdbBridge::Factory::BuildServiceInstanceFor( 498 content::BrowserContext* context) const { 499 return new DevToolsAdbBridge::Wrapper(Profile::FromBrowserContext(context)); 500 } 501 502 DevToolsAdbBridge::AndroidDevice::AndroidDevice(const std::string& serial) 503 : serial_(serial) { 504 } 505 506 void DevToolsAdbBridge::AndroidDevice::HttpQuery( 507 const std::string& la_name, 508 const std::string& request, 509 const CommandCallback& callback) { 510 OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened, this, 511 request, callback)); 512 } 513 514 void DevToolsAdbBridge::AndroidDevice::HttpUpgrade( 515 const std::string& la_name, 516 const std::string& request, 517 const SocketCallback& callback) { 518 OpenSocket(la_name, base::Bind(&AndroidDevice::OnHttpSocketOpened2, this, 519 request, callback)); 520 } 521 522 DevToolsAdbBridge::AndroidDevice::~AndroidDevice() { 523 } 524 525 void DevToolsAdbBridge::AndroidDevice::OnHttpSocketOpened( 526 const std::string& request, 527 const CommandCallback& callback, 528 int result, 529 net::StreamSocket* socket) { 530 if (result != net::OK) { 531 callback.Run(result, std::string()); 532 return; 533 } 534 AdbClientSocket::HttpQuery(socket, request, callback); 535 } 536 537 void DevToolsAdbBridge::AndroidDevice::OnHttpSocketOpened2( 538 const std::string& request, 539 const SocketCallback& callback, 540 int result, 541 net::StreamSocket* socket) { 542 if (result != net::OK) { 543 callback.Run(result, NULL); 544 return; 545 } 546 AdbClientSocket::HttpQuery(socket, request, callback); 547 } 548 549 class AgentHostDelegate : public content::DevToolsExternalAgentProxyDelegate, 550 public AdbWebSocket::Delegate { 551 public: 552 AgentHostDelegate( 553 const std::string& id, 554 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device, 555 const std::string& socket_name, 556 const std::string& debug_url, 557 const std::string& frontend_url, 558 base::MessageLoop* adb_message_loop, 559 Profile* profile) 560 : id_(id), 561 serial_(device->serial()), 562 frontend_url_(frontend_url), 563 adb_message_loop_(adb_message_loop), 564 profile_(profile) { 565 web_socket_ = new AdbWebSocket( 566 device, socket_name, debug_url, adb_message_loop, this); 567 g_host_delegates.Get()[id] = this; 568 } 569 570 void OpenFrontend() { 571 if (!proxy_) 572 return; 573 DevToolsWindow::OpenExternalFrontend( 574 profile_, frontend_url_, proxy_->GetAgentHost().get()); 575 } 576 577 private: 578 virtual ~AgentHostDelegate() { 579 g_host_delegates.Get().erase(id_); 580 } 581 582 virtual void Attach() OVERRIDE {} 583 584 virtual void Detach() OVERRIDE { 585 web_socket_->Disconnect(); 586 } 587 588 virtual void SendMessageToBackend(const std::string& message) OVERRIDE { 589 web_socket_->SendFrame(message); 590 } 591 592 virtual void OnSocketOpened() OVERRIDE { 593 proxy_.reset(content::DevToolsExternalAgentProxy::Create(this)); 594 OpenFrontend(); 595 } 596 597 virtual void OnFrameRead(const std::string& message) OVERRIDE { 598 proxy_->DispatchOnClientHost(message); 599 } 600 601 virtual void OnSocketClosed(bool closed_by_device) OVERRIDE { 602 if (proxy_ && closed_by_device) 603 proxy_->ConnectionClosed(); 604 delete this; 605 } 606 607 virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE { 608 return false; 609 } 610 611 const std::string id_; 612 const std::string serial_; 613 const std::string frontend_url_; 614 base::MessageLoop* adb_message_loop_; 615 Profile* profile_; 616 617 scoped_ptr<content::DevToolsExternalAgentProxy> proxy_; 618 scoped_refptr<AdbWebSocket> web_socket_; 619 DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate); 620 }; 621 622 DevToolsAdbBridge::RemotePage::RemotePage( 623 scoped_refptr<DevToolsAdbBridge> bridge, 624 scoped_refptr<AndroidDevice> device, 625 const std::string& socket, 626 const base::DictionaryValue& value) 627 : bridge_(bridge), 628 device_(device), 629 socket_(socket) { 630 value.GetString("id", &id_); 631 value.GetString("url", &url_); 632 value.GetString("title", &title_); 633 value.GetString("descirption", &description_); 634 value.GetString("faviconUrl", &favicon_url_); 635 value.GetString("webSocketDebuggerUrl", &debug_url_); 636 value.GetString("devtoolsFrontendUrl", &frontend_url_); 637 638 if (debug_url_.find("ws://") == 0) 639 debug_url_ = debug_url_.substr(5); 640 else 641 debug_url_ = ""; 642 643 size_t ws_param = frontend_url_.find("?ws"); 644 if (ws_param != std::string::npos) 645 frontend_url_ = frontend_url_.substr(0, ws_param); 646 if (frontend_url_.find("http:") == 0) 647 frontend_url_ = "https:" + frontend_url_.substr(5); 648 } 649 650 void DevToolsAdbBridge::RemotePage::Inspect(Profile* profile) { 651 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 652 std::string agent_id = base::StringPrintf("%s:%s:%s", 653 device_->serial().c_str(), socket_.c_str(), id_.c_str()); 654 AgentHostDelegates::iterator it = 655 g_host_delegates.Get().find(agent_id); 656 if (it != g_host_delegates.Get().end()) 657 it->second->OpenFrontend(); 658 else if (!debug_url_.empty()) 659 new AgentHostDelegate( 660 agent_id, device_, socket_, debug_url_, 661 frontend_url_, bridge_->GetAdbMessageLoop(), profile); 662 } 663 664 static void Noop(int, const std::string&) {} 665 666 void DevToolsAdbBridge::RemotePage::Close() { 667 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 668 if (attached()) 669 return; 670 std::string request = base::StringPrintf(kClosePageRequest, id_.c_str()); 671 bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE, 672 base::Bind(&AndroidDevice::HttpQuery, 673 device_, socket_, request, base::Bind(&Noop))); 674 } 675 676 void DevToolsAdbBridge::RemotePage::Reload() { 677 SendProtocolCommand(kPageReloadCommand, NULL); 678 } 679 680 void DevToolsAdbBridge::RemotePage::SendProtocolCommand( 681 const std::string& method, 682 base::DictionaryValue* params) { 683 if (attached()) 684 return; 685 DevToolsProtocol::Command command(1, method, params); 686 new AdbProtocolCommand( 687 bridge_, device_, socket_, debug_url_, command.Serialize()); 688 } 689 690 DevToolsAdbBridge::RemotePage::~RemotePage() { 691 } 692 693 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser( 694 scoped_refptr<DevToolsAdbBridge> bridge, 695 scoped_refptr<AndroidDevice> device, 696 const std::string& socket) 697 : bridge_(bridge), 698 device_(device), 699 socket_(socket) { 700 } 701 702 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) { 703 bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE, 704 base::Bind(&AndroidDevice::HttpQuery, 705 device_, socket_, kNewPageRequest, 706 base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url))); 707 } 708 709 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread( 710 const std::string& url, int result, const std::string& response) { 711 if (result < 0) 712 return; 713 BrowserThread::PostTask( 714 BrowserThread::UI, FROM_HERE, 715 base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url)); 716 } 717 718 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread( 719 const std::string& response, const std::string& url) { 720 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); 721 base::DictionaryValue* dict; 722 if (value && value->GetAsDictionary(&dict)) { 723 scoped_refptr<RemotePage> new_page = 724 new RemotePage(bridge_, device_, socket_, *dict); 725 base::DictionaryValue params; 726 params.SetString(kUrlParam, url); 727 new_page->SendProtocolCommand(kPageNavigateCommand, ¶ms); 728 } 729 } 730 731 DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() { 732 } 733 734 DevToolsAdbBridge::RemoteDevice::RemoteDevice( 735 scoped_refptr<DevToolsAdbBridge> bridge, 736 scoped_refptr<AndroidDevice> device) 737 : bridge_(bridge), 738 device_(device) { 739 } 740 741 DevToolsAdbBridge::RemoteDevice::~RemoteDevice() { 742 } 743 744 745 DevToolsAdbBridge::RefCountedAdbThread* 746 DevToolsAdbBridge::RefCountedAdbThread::instance_ = NULL; 747 748 // static 749 scoped_refptr<DevToolsAdbBridge::RefCountedAdbThread> 750 DevToolsAdbBridge::RefCountedAdbThread::GetInstance() { 751 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 752 if (!instance_) 753 new RefCountedAdbThread(); 754 return instance_; 755 } 756 757 DevToolsAdbBridge::RefCountedAdbThread::RefCountedAdbThread() { 758 instance_ = this; 759 thread_ = new base::Thread(kDevToolsAdbBridgeThreadName); 760 base::Thread::Options options; 761 options.message_loop_type = base::MessageLoop::TYPE_IO; 762 if (!thread_->StartWithOptions(options)) { 763 delete thread_; 764 thread_ = NULL; 765 } 766 } 767 768 base::MessageLoop* DevToolsAdbBridge::RefCountedAdbThread::message_loop() { 769 return thread_ ? thread_->message_loop() : NULL; 770 } 771 772 // static 773 void DevToolsAdbBridge::RefCountedAdbThread::StopThread(base::Thread* thread) { 774 thread->Stop(); 775 } 776 777 DevToolsAdbBridge::RefCountedAdbThread::~RefCountedAdbThread() { 778 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 779 instance_ = NULL; 780 if (!thread_) 781 return; 782 // Shut down thread on FILE thread to join into IO. 783 BrowserThread::PostTask( 784 BrowserThread::FILE, FROM_HERE, 785 base::Bind(&RefCountedAdbThread::StopThread, thread_)); 786 } 787 788 DevToolsAdbBridge::DevToolsAdbBridge(Profile* profile) 789 : profile_(profile), 790 adb_thread_(RefCountedAdbThread::GetInstance()), 791 has_message_loop_(adb_thread_->message_loop() != NULL) { 792 rsa_key_.reset(AndroidRSAPrivateKey(profile)); 793 port_forwarding_controller_.reset( 794 new PortForwardingController(GetAdbMessageLoop(), profile->GetPrefs())); 795 } 796 797 void DevToolsAdbBridge::EnumerateUsbDevices( 798 const AndroidDevicesCallback& callback) { 799 DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop()); 800 if (CommandLine::ForCurrentProcess()->HasSwitch( 801 switches::kRemoteDebuggingRawUSB)) { 802 AndroidUsbDevice::Enumerate(rsa_key_.get(), 803 base::Bind(&DevToolsAdbBridge::ReceivedUsbDevices, this, callback)); 804 } else { 805 ReceivedUsbDevices(callback, AndroidUsbDevices()); 806 } 807 } 808 809 void DevToolsAdbBridge::EnumerateAdbDevices( 810 const AndroidDevicesCallback& callback) { 811 DCHECK_EQ(base::MessageLoop::current(), adb_thread_->message_loop()); 812 813 AdbClientSocket::AdbQuery( 814 kAdbPort, kHostDevicesCommand, 815 base::Bind(&DevToolsAdbBridge::ReceivedAdbDevices, this, callback)); 816 } 817 818 void DevToolsAdbBridge::AddListener(Listener* listener) { 819 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 820 if (listeners_.empty()) 821 RequestRemoteDevices(); 822 listeners_.push_back(listener); 823 } 824 825 void DevToolsAdbBridge::RemoveListener(Listener* listener) { 826 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 827 Listeners::iterator it = 828 std::find(listeners_.begin(), listeners_.end(), listener); 829 DCHECK(it != listeners_.end()); 830 listeners_.erase(it); 831 } 832 833 base::MessageLoop* DevToolsAdbBridge::GetAdbMessageLoop() { 834 return adb_thread_->message_loop(); 835 } 836 837 DevToolsAdbBridge::~DevToolsAdbBridge() { 838 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 839 DCHECK(listeners_.empty()); 840 } 841 842 void DevToolsAdbBridge::ReceivedUsbDevices( 843 const AndroidDevicesCallback& callback, 844 const AndroidUsbDevices& usb_devices) { 845 AndroidDevices devices; 846 847 #if defined(DEBUG_DEVTOOLS) 848 devices.push_back(new AdbDeviceImpl("")); // For desktop remote debugging. 849 #endif // defined(DEBUG_DEVTOOLS) 850 851 for (AndroidUsbDevices::const_iterator it = usb_devices.begin(); 852 it != usb_devices.end(); ++it) { 853 devices.push_back(new UsbDeviceImpl(*it)); 854 } 855 856 callback.Run(devices); 857 } 858 859 void DevToolsAdbBridge::ReceivedAdbDevices( 860 const AndroidDevicesCallback& callback, 861 int result, 862 const std::string& response) { 863 AndroidDevices devices; 864 if (result != net::OK) { 865 callback.Run(devices); 866 return; 867 } 868 869 std::vector<std::string> serials; 870 Tokenize(response, "\n", &serials); 871 for (size_t i = 0; i < serials.size(); ++i) { 872 std::vector<std::string> tokens; 873 Tokenize(serials[i], "\t ", &tokens); 874 devices.push_back(new AdbDeviceImpl(tokens[0])); 875 } 876 callback.Run(devices); 877 } 878 879 void DevToolsAdbBridge::RequestRemoteDevices() { 880 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 881 if (!has_message_loop_) 882 return; 883 884 new AdbPagesCommand( 885 this, base::Bind(&DevToolsAdbBridge::ReceivedRemoteDevices, this)); 886 } 887 888 void DevToolsAdbBridge::ReceivedRemoteDevices(RemoteDevices* devices_ptr) { 889 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 890 891 scoped_ptr<RemoteDevices> devices(devices_ptr); 892 port_forwarding_controller_->UpdateDeviceList(*devices.get()); 893 894 Listeners copy(listeners_); 895 for (Listeners::iterator it = copy.begin(); it != copy.end(); ++it) 896 (*it)->RemoteDevicesChanged(devices.get()); 897 898 if (listeners_.empty()) 899 return; 900 901 BrowserThread::PostDelayedTask( 902 BrowserThread::UI, 903 FROM_HERE, 904 base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this), 905 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs)); 906 } 907