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 |