| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/devtools/devtools_adb_bridge.h" | 5 #include "chrome/browser/devtools/devtools_adb_bridge.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/base64.h" | 10 #include "base/base64.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 | 40 |
| 41 using content::BrowserThread; | 41 using content::BrowserThread; |
| 42 | 42 |
| 43 namespace { | 43 namespace { |
| 44 | 44 |
| 45 static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread"; | 45 static const char kDevToolsAdbBridgeThreadName[] = "Chrome_DevToolsADBThread"; |
| 46 static const char kHostDevicesCommand[] = "host:devices"; | 46 static const char kHostDevicesCommand[] = "host:devices"; |
| 47 static const char kHostTransportCommand[] = "host:transport:%s|%s"; | 47 static const char kHostTransportCommand[] = "host:transport:%s|%s"; |
| 48 static const char kLocalAbstractCommand[] = "localabstract:%s"; | 48 static const char kLocalAbstractCommand[] = "localabstract:%s"; |
| 49 static const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; | 49 static const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; |
| 50 static const char kUnknownModel[] = "Unknown"; | 50 static const char kLocalChrome[] = "Local Chrome"; |
| 51 static const char kChrome[] = "Chrome"; |
| 51 static const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; | 52 static const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; |
| 52 | 53 |
| 53 static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n"; | 54 static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n"; |
| 54 static const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n"; | 55 static const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n"; |
| 55 static const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n"; | 56 static const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n"; |
| 56 static const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n"; | 57 static const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n"; |
| 57 const int kAdbPort = 5037; | 58 const int kAdbPort = 5037; |
| 58 const int kBufferSize = 16 * 1024; | 59 const int kBufferSize = 16 * 1024; |
| 59 const int kAdbPollingIntervalMs = 1000; | 60 const int kAdbPollingIntervalMs = 1000; |
| 60 | 61 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 BrowserThread::UI, FROM_HERE, | 206 BrowserThread::UI, FROM_HERE, |
| 206 base::Bind(&AdbPagesCommand::Respond, this)); | 207 base::Bind(&AdbPagesCommand::Respond, this)); |
| 207 return; | 208 return; |
| 208 } | 209 } |
| 209 | 210 |
| 210 #if defined(DEBUG_DEVTOOLS) | 211 #if defined(DEBUG_DEVTOOLS) |
| 211 // For desktop remote debugging. | 212 // For desktop remote debugging. |
| 212 if (devices_.back()->serial().empty()) { | 213 if (devices_.back()->serial().empty()) { |
| 213 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = | 214 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = |
| 214 devices_.back(); | 215 devices_.back(); |
| 215 sockets_.push_back(std::string()); | 216 device->set_model(kLocalChrome); |
| 216 device->set_model(kUnknownModel); | |
| 217 remote_devices_->push_back( | 217 remote_devices_->push_back( |
| 218 new DevToolsAdbBridge::RemoteDevice(bridge_, device)); | 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); |
| 219 device->HttpQuery( | 224 device->HttpQuery( |
| 220 std::string(), kVersionRequest, | 225 std::string(), kVersionRequest, |
| 221 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); | 226 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); |
| 222 return; | 227 return; |
| 223 } | 228 } |
| 224 #endif // defined(DEBUG_DEVTOOLS) | 229 #endif // defined(DEBUG_DEVTOOLS) |
| 225 | 230 |
| 226 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); | 231 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); |
| 227 device->RunCommand(kDeviceModelCommand, | 232 device->RunCommand(kDeviceModelCommand, |
| 228 base::Bind(&AdbPagesCommand::ReceivedModel, this)); | 233 base::Bind(&AdbPagesCommand::ReceivedModel, this)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 246 void ReceivedSockets(int result, | 251 void ReceivedSockets(int result, |
| 247 const std::string& response) { | 252 const std::string& response) { |
| 248 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); | 253 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); |
| 249 if (result < 0) { | 254 if (result < 0) { |
| 250 devices_.pop_back(); | 255 devices_.pop_back(); |
| 251 ProcessSerials(); | 256 ProcessSerials(); |
| 252 return; | 257 return; |
| 253 } | 258 } |
| 254 | 259 |
| 255 ParseSocketsList(response); | 260 ParseSocketsList(response); |
| 256 if (sockets_.size() == 0) { | 261 if (browsers_.size() == 0) { |
| 257 devices_.pop_back(); | 262 devices_.pop_back(); |
| 258 ProcessSerials(); | 263 ProcessSerials(); |
| 259 } else { | 264 } else { |
| 260 ProcessSockets(); | 265 ProcessSockets(); |
| 261 } | 266 } |
| 262 } | 267 } |
| 263 | 268 |
| 264 void ProcessSockets() { | 269 void ProcessSockets() { |
| 265 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); | 270 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); |
| 266 if (sockets_.size() == 0) { | 271 if (browsers_.size() == 0) { |
| 267 devices_.pop_back(); | 272 devices_.pop_back(); |
| 268 ProcessSerials(); | 273 ProcessSerials(); |
| 269 } else { | 274 } else { |
| 270 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); | 275 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); |
| 271 device->HttpQuery(sockets_.back(), kVersionRequest, | 276 device->HttpQuery(browsers_.back()->socket(), kVersionRequest, |
| 272 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); | 277 base::Bind(&AdbPagesCommand::ReceivedVersion, this)); |
| 273 } | 278 } |
| 274 } | 279 } |
| 275 | 280 |
| 276 void ReceivedVersion(int result, | 281 void ReceivedVersion(int result, |
| 277 const std::string& response) { | 282 const std::string& response) { |
| 278 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); | 283 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); |
| 279 if (result < 0) { | 284 if (result < 0) { |
| 280 sockets_.pop_back(); | 285 browsers_.pop_back(); |
| 281 ProcessSockets(); | 286 ProcessSockets(); |
| 282 return; | 287 return; |
| 283 } | 288 } |
| 284 | 289 |
| 285 // Parse version, append to package name if available, | 290 // Parse version, append to package name if available, |
| 286 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); | 291 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); |
| 287 base::DictionaryValue* dict; | 292 base::DictionaryValue* dict; |
| 288 if (value && value->GetAsDictionary(&dict)) { | 293 if (value && value->GetAsDictionary(&dict)) { |
| 289 std::string browser; | 294 std::string browser; |
| 290 if (dict->GetString("Browser", &browser)) { | 295 if (dict->GetString("Browser", &browser)) { |
| 291 socket_to_package_[sockets_.back()] = base::StringPrintf( | 296 std::vector<std::string> parts; |
| 292 "%s (%s)", socket_to_package_[sockets_.back()].c_str(), | 297 Tokenize(browser, "/", &parts); |
| 293 browser.c_str()); | 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 } |
| 294 } | 305 } |
| 295 } | 306 } |
| 296 | 307 |
| 297 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); | 308 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); |
| 298 device->HttpQuery(sockets_.back(), kPageListRequest, | 309 device->HttpQuery(browsers_.back()->socket(), kPageListRequest, |
| 299 base::Bind(&AdbPagesCommand::ReceivedPages, this)); | 310 base::Bind(&AdbPagesCommand::ReceivedPages, this)); |
| 300 } | 311 } |
| 301 | 312 |
| 302 void ReceivedPages(int result, | 313 void ReceivedPages(int result, |
| 303 const std::string& response) { | 314 const std::string& response) { |
| 304 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); | 315 DCHECK_EQ(bridge_->GetAdbMessageLoop(), base::MessageLoop::current()); |
| 305 std::string socket = sockets_.back(); | 316 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = browsers_.back(); |
| 306 sockets_.pop_back(); | 317 browsers_.pop_back(); |
| 307 if (result < 0) { | 318 if (result < 0) { |
| 308 ProcessSockets(); | 319 ProcessSockets(); |
| 309 return; | 320 return; |
| 310 } | 321 } |
| 311 | 322 |
| 312 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); | 323 scoped_ptr<base::Value> value(base::JSONReader::Read(response)); |
| 313 base::ListValue* list_value; | 324 base::ListValue* list_value; |
| 314 if (!value || !value->GetAsList(&list_value)) { | 325 if (!value || !value->GetAsList(&list_value)) { |
| 315 ProcessSockets(); | 326 ProcessSockets(); |
| 316 return; | 327 return; |
| 317 } | 328 } |
| 318 | 329 |
| 319 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device = devices_.back(); | |
| 320 base::Value* item; | 330 base::Value* item; |
| 321 | 331 |
| 322 scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser = | |
| 323 new DevToolsAdbBridge::RemoteBrowser( | |
| 324 bridge_, device, socket, socket_to_package_[socket]); | |
| 325 remote_devices_->back()->AddBrowser(remote_browser); | |
| 326 | |
| 327 for (size_t i = 0; i < list_value->GetSize(); ++i) { | 332 for (size_t i = 0; i < list_value->GetSize(); ++i) { |
| 328 list_value->Get(i, &item); | 333 list_value->Get(i, &item); |
| 329 base::DictionaryValue* dict; | 334 base::DictionaryValue* dict; |
| 330 if (!item || !item->GetAsDictionary(&dict)) | 335 if (!item || !item->GetAsDictionary(&dict)) |
| 331 continue; | 336 continue; |
| 332 remote_browser->AddPage(new DevToolsAdbBridge::RemotePage( | 337 browser->AddPage(new DevToolsAdbBridge::RemotePage( |
| 333 bridge_, device, remote_browser->socket(), *dict)); | 338 bridge_, browser->device(), browser->socket(), *dict)); |
| 334 } | 339 } |
| 335 ProcessSockets(); | 340 ProcessSockets(); |
| 336 } | 341 } |
| 337 | 342 |
| 338 void Respond() { | 343 void Respond() { |
| 339 callback_.Run(remote_devices_.release()); | 344 callback_.Run(remote_devices_.release()); |
| 340 } | 345 } |
| 341 | 346 |
| 342 void ParseSocketsList(const std::string& response) { | 347 void ParseSocketsList(const std::string& response) { |
| 343 // On Android, '/proc/net/unix' looks like this: | 348 // On Android, '/proc/net/unix' looks like this: |
| 344 // | 349 // |
| 345 // Num RefCount Protocol Flags Type St Inode Path | 350 // Num RefCount Protocol Flags Type St Inode Path |
| 346 // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote | 351 // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote |
| 347 // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote | 352 // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote |
| 348 // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote | 353 // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote |
| 349 // | 354 // |
| 350 // We need to find records with paths starting from '@' (abstract socket) | 355 // We need to find records with paths starting from '@' (abstract socket) |
| 351 // and containing "devtools_remote". We have to extract the inode number | 356 // and containing "devtools_remote". We have to extract the inode number |
| 352 // in order to find the owning process name. | 357 // in order to find the owning process name. |
| 353 | 358 |
| 354 socket_to_package_.clear(); | 359 scoped_refptr<DevToolsAdbBridge::RemoteDevice> remote_device = |
| 360 remote_devices_->back(); |
| 361 |
| 355 std::vector<std::string> entries; | 362 std::vector<std::string> entries; |
| 356 Tokenize(response, "\n", &entries); | 363 Tokenize(response, "\n", &entries); |
| 357 const std::string channel_pattern = | 364 const std::string channel_pattern = |
| 358 base::StringPrintf(kDevToolsChannelNameFormat, ""); | 365 base::StringPrintf(kDevToolsChannelNameFormat, ""); |
| 359 for (size_t i = 1; i < entries.size(); ++i) { | 366 for (size_t i = 1; i < entries.size(); ++i) { |
| 360 std::vector<std::string> fields; | 367 std::vector<std::string> fields; |
| 361 Tokenize(entries[i], " ", &fields); | 368 Tokenize(entries[i], " ", &fields); |
| 362 if (fields.size() < 8) | 369 if (fields.size() < 8) |
| 363 continue; | 370 continue; |
| 364 if (fields[3] != "00010000" || fields[5] != "01") | 371 if (fields[3] != "00010000" || fields[5] != "01") |
| 365 continue; | 372 continue; |
| 366 std::string path_field = fields[7]; | 373 std::string path_field = fields[7]; |
| 367 if (path_field.size() < 1 || path_field[0] != '@') | 374 if (path_field.size() < 1 || path_field[0] != '@') |
| 368 continue; | 375 continue; |
| 369 size_t socket_name_pos = path_field.find(channel_pattern); | 376 size_t socket_name_pos = path_field.find(channel_pattern); |
| 370 if (socket_name_pos == std::string::npos) | 377 if (socket_name_pos == std::string::npos) |
| 371 continue; | 378 continue; |
| 372 std::string socket = path_field.substr(1, path_field.size() - 2); | 379 std::string socket = path_field.substr(1, path_field.size() - 2); |
| 373 sockets_.push_back(socket); | |
| 374 std::string package = path_field.substr(1, socket_name_pos - 1); | 380 std::string package = path_field.substr(1, socket_name_pos - 1); |
| 375 if (socket_name_pos + channel_pattern.size() < path_field.size() - 1) { | 381 if (socket_name_pos + channel_pattern.size() < path_field.size() - 1) { |
| 376 package += path_field.substr( | 382 package += path_field.substr( |
| 377 socket_name_pos + channel_pattern.size(), path_field.size() - 1); | 383 socket_name_pos + channel_pattern.size(), path_field.size() - 1); |
| 378 } | 384 } |
| 379 package[0] = base::ToUpperASCII(package[0]); | 385 package[0] = base::ToUpperASCII(package[0]); |
| 380 socket_to_package_[socket] = package; | 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); |
| 381 } | 391 } |
| 392 browsers_ = remote_device->browsers(); |
| 382 } | 393 } |
| 383 | 394 |
| 384 scoped_refptr<DevToolsAdbBridge> bridge_; | 395 scoped_refptr<DevToolsAdbBridge> bridge_; |
| 385 Callback callback_; | 396 Callback callback_; |
| 386 AndroidDevices devices_; | 397 AndroidDevices devices_; |
| 387 std::vector<std::string> sockets_; | 398 DevToolsAdbBridge::RemoteBrowsers browsers_; |
| 388 std::map<std::string, std::string> socket_to_package_; | |
| 389 scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_; | 399 scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_; |
| 390 }; | 400 }; |
| 391 | 401 |
| 392 // AdbProtocolCommand --------------------------------------------------------- | 402 // AdbProtocolCommand --------------------------------------------------------- |
| 393 | 403 |
| 394 class AdbProtocolCommand : public AdbWebSocket::Delegate { | 404 class AdbProtocolCommand : public AdbWebSocket::Delegate { |
| 395 public: | 405 public: |
| 396 AdbProtocolCommand( | 406 AdbProtocolCommand( |
| 397 scoped_refptr<DevToolsAdbBridge> bridge_, | 407 scoped_refptr<DevToolsAdbBridge> bridge_, |
| 398 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device, | 408 scoped_refptr<DevToolsAdbBridge::AndroidDevice> device, |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 new AdbProtocolCommand( | 686 new AdbProtocolCommand( |
| 677 bridge_, device_, socket_, debug_url_, command.Serialize()); | 687 bridge_, device_, socket_, debug_url_, command.Serialize()); |
| 678 } | 688 } |
| 679 | 689 |
| 680 DevToolsAdbBridge::RemotePage::~RemotePage() { | 690 DevToolsAdbBridge::RemotePage::~RemotePage() { |
| 681 } | 691 } |
| 682 | 692 |
| 683 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser( | 693 DevToolsAdbBridge::RemoteBrowser::RemoteBrowser( |
| 684 scoped_refptr<DevToolsAdbBridge> bridge, | 694 scoped_refptr<DevToolsAdbBridge> bridge, |
| 685 scoped_refptr<AndroidDevice> device, | 695 scoped_refptr<AndroidDevice> device, |
| 686 const std::string& socket, | 696 const std::string& socket) |
| 687 const std::string& name) | |
| 688 : bridge_(bridge), | 697 : bridge_(bridge), |
| 689 device_(device), | 698 device_(device), |
| 690 socket_(socket), | 699 socket_(socket) { |
| 691 name_(name) { | |
| 692 } | 700 } |
| 693 | 701 |
| 694 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) { | 702 void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) { |
| 695 bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE, | 703 bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE, |
| 696 base::Bind(&AndroidDevice::HttpQuery, | 704 base::Bind(&AndroidDevice::HttpQuery, |
| 697 device_, socket_, kNewPageRequest, | 705 device_, socket_, kNewPageRequest, |
| 698 base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url))); | 706 base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url))); |
| 699 } | 707 } |
| 700 | 708 |
| 701 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread( | 709 void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread( |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 | 897 |
| 890 if (listeners_.empty()) | 898 if (listeners_.empty()) |
| 891 return; | 899 return; |
| 892 | 900 |
| 893 BrowserThread::PostDelayedTask( | 901 BrowserThread::PostDelayedTask( |
| 894 BrowserThread::UI, | 902 BrowserThread::UI, |
| 895 FROM_HERE, | 903 FROM_HERE, |
| 896 base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this), | 904 base::Bind(&DevToolsAdbBridge::RequestRemoteDevices, this), |
| 897 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs)); | 905 base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs)); |
| 898 } | 906 } |
| OLD | NEW |