1 // Copyright 2014 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 <algorithm> 6 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/devtools/device/devtools_android_bridge.h" 9 #include "chrome/browser/devtools/device/usb/android_usb_device.h" 10 #include "chrome/browser/devtools/device/usb/usb_device_provider.h" 11 #include "chrome/browser/ui/browser.h" 12 #include "chrome/test/base/in_process_browser_test.h" 13 #include "components/usb_service/usb_device.h" 14 #include "components/usb_service/usb_device_handle.h" 15 #include "components/usb_service/usb_interface.h" 16 #include "components/usb_service/usb_service.h" 17 #include "content/public/browser/browser_thread.h" 18 #include "content/public/test/test_utils.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 using content::BrowserThread; 22 using namespace usb_service; 23 24 namespace { 25 26 struct AndroidTraits { 27 static const int kClass = 0xff; 28 static const int kSubclass = 0x42; 29 static const int kProtocol = 0x1; 30 }; 31 32 struct NonAndroidTraits { 33 static const int kClass = 0xf0; 34 static const int kSubclass = 0x42; 35 static const int kProtocol = 0x2; 36 }; 37 38 const uint32 kMaxPayload = 4096; 39 const uint32 kVersion = 0x01000000; 40 41 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; 42 const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; 43 const char kDumpsysCommand[] = "shell:dumpsys window policy"; 44 const char kListProcessesCommand[] = "shell:ps"; 45 const char kInstalledChromePackagesCommand[] = "shell:pm list packages"; 46 const char kDeviceModel[] = "Nexus 5"; 47 const char kDeviceSerial[] = "Sample serial"; 48 49 const char kSampleOpenedUnixSockets[] = 50 "Num RefCount Protocol Flags Type St Inode Path\n" 51 "00000000: 00000004 00000000" 52 " 00000000 0002 01 3328 /dev/socket/wpa_wlan0\n" 53 "00000000: 00000002 00000000" 54 " 00010000 0001 01 5394 /dev/socket/vold\n"; 55 56 const char kSampleListProcesses[] = 57 "USER PID PPID VSIZE RSS WCHAN PC NAME\n" 58 "root 1 0 688 508 ffffffff 00000000 S /init\r\n" 59 "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\r\n" 60 "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc\r\n" 61 "u0_a76 1001 124 111111 222222 ffffffff 00000000 S com.android.chrome\r\n" 62 "u0_a78 1003 126 111111 222222 ffffffff 00000000 S com.noprocess.app\r\n"; 63 64 const char kSampleListPackages[] = 65 "package:com.sample.feed\r\n" 66 "package:com.android.nfc\r\n" 67 "package:com.android.chrome\r\n" 68 "package:com.chrome.beta\r\n" 69 "package:com.google.android.apps.chrome\r\n"; 70 71 const char kSampleDumpsys[] = 72 "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n" 73 " mSafeMode=false mSystemReady=true mSystemBooted=true\r\n" 74 " mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed 75 " mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n"; 76 77 const char* GetMockShellResponse(std::string command) { 78 if (command == kDeviceModelCommand) { 79 return kDeviceModel; 80 } else if (command == kOpenedUnixSocketsCommand) { 81 return kSampleOpenedUnixSockets; 82 } else if (command == kDumpsysCommand) { 83 return kSampleDumpsys; 84 } else if (command == kListProcessesCommand) { 85 return kSampleListProcesses; 86 } else if (command == kInstalledChromePackagesCommand) { 87 return kSampleListPackages; 88 } 89 90 DCHECK(false) << "Should not be reached"; 91 92 return ""; 93 } 94 95 class MockUsbEndpointDescriptor : public UsbEndpointDescriptor { 96 public: 97 virtual int GetAddress() const OVERRIDE { return address_; } 98 99 virtual UsbEndpointDirection GetDirection() const OVERRIDE { 100 return direction_; 101 } 102 103 virtual int GetMaximumPacketSize() const OVERRIDE { 104 return maximum_packet_size_; 105 } 106 107 virtual UsbSynchronizationType GetSynchronizationType() const OVERRIDE { 108 return usb_synchronization_type_; 109 } 110 111 virtual UsbTransferType GetTransferType() const OVERRIDE { 112 return usb_transfer_type_; 113 } 114 virtual UsbUsageType GetUsageType() const OVERRIDE { return usb_usage_type_; } 115 116 virtual int GetPollingInterval() const OVERRIDE { return polling_interval_; } 117 118 int address_; 119 UsbEndpointDirection direction_; 120 int maximum_packet_size_; 121 UsbSynchronizationType usb_synchronization_type_; 122 UsbTransferType usb_transfer_type_; 123 UsbUsageType usb_usage_type_; 124 int polling_interval_; 125 126 private: 127 virtual ~MockUsbEndpointDescriptor() {} 128 }; 129 130 template <class T> 131 class MockUsbInterfaceAltSettingDescriptor 132 : public UsbInterfaceAltSettingDescriptor { 133 public: 134 MockUsbInterfaceAltSettingDescriptor(int interface_number, 135 int alternate_setting) 136 : interface_number_(interface_number), 137 alternate_setting_(alternate_setting) {} 138 139 virtual size_t GetNumEndpoints() const OVERRIDE { 140 // See IsAndroidInterface function in android_usb_device.cc 141 return 2; 142 } 143 144 virtual scoped_refptr<const UsbEndpointDescriptor> GetEndpoint( 145 size_t index) const OVERRIDE { 146 EXPECT_GT(static_cast<size_t>(2), index); 147 MockUsbEndpointDescriptor* result = new MockUsbEndpointDescriptor(); 148 result->address_ = index + 1; 149 result->usb_transfer_type_ = USB_TRANSFER_BULK; 150 result->direction_ = 151 ((index == 0) ? USB_DIRECTION_INBOUND : USB_DIRECTION_OUTBOUND); 152 result->maximum_packet_size_ = 1 << 20; // 1Mb maximum packet size 153 return result; 154 } 155 156 virtual int GetInterfaceNumber() const OVERRIDE { return interface_number_; } 157 158 virtual int GetAlternateSetting() const OVERRIDE { 159 return alternate_setting_; 160 } 161 162 virtual int GetInterfaceClass() const OVERRIDE { return T::kClass; } 163 164 virtual int GetInterfaceSubclass() const OVERRIDE { return T::kSubclass; } 165 166 virtual int GetInterfaceProtocol() const OVERRIDE { return T::kProtocol; } 167 168 protected: 169 virtual ~MockUsbInterfaceAltSettingDescriptor() {}; 170 171 private: 172 const int interface_number_; 173 const int alternate_setting_; 174 }; 175 176 template <class T> 177 class MockUsbInterfaceDescriptor : public UsbInterfaceDescriptor { 178 public: 179 explicit MockUsbInterfaceDescriptor(int interface_number) 180 : interface_number_(interface_number) {} 181 182 virtual size_t GetNumAltSettings() const OVERRIDE { 183 // See IsAndroidInterface function in android_usb_device.cc 184 return 1; 185 } 186 virtual scoped_refptr<const UsbInterfaceAltSettingDescriptor> GetAltSetting( 187 size_t index) const OVERRIDE { 188 EXPECT_EQ(static_cast<size_t>(0), index); 189 return new MockUsbInterfaceAltSettingDescriptor<T>(interface_number_, 0); 190 } 191 192 protected: 193 const int interface_number_; 194 virtual ~MockUsbInterfaceDescriptor() {} 195 }; 196 197 template <class T> 198 class MockUsbConfigDescriptor : public UsbConfigDescriptor { 199 public: 200 MockUsbConfigDescriptor() {} 201 202 virtual size_t GetNumInterfaces() const OVERRIDE { return 1; } 203 204 virtual scoped_refptr<const UsbInterfaceDescriptor> GetInterface( 205 size_t index) const OVERRIDE { 206 EXPECT_EQ(static_cast<size_t>(0), index); 207 return new MockUsbInterfaceDescriptor<T>(index); 208 } 209 210 protected: 211 virtual ~MockUsbConfigDescriptor() {}; 212 }; 213 214 template <class T> 215 class MockUsbDevice; 216 217 template <class T> 218 class MockUsbDeviceHandle : public UsbDeviceHandle { 219 public: 220 explicit MockUsbDeviceHandle(MockUsbDevice<T>* device) 221 : device_(device), 222 remaining_body_length_(0), 223 next_local_socket_(0) {} 224 225 virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE { 226 return device_; 227 } 228 229 virtual void Close() OVERRIDE { device_ = NULL; } 230 231 bool ClaimInterface(const int interface_number) { 232 if (device_->claimed_interfaces_.find(interface_number) != 233 device_->claimed_interfaces_.end()) 234 return false; 235 236 device_->claimed_interfaces_.insert(interface_number); 237 return true; 238 } 239 240 bool ReleaseInterface(const int interface_number) { 241 if (device_->claimed_interfaces_.find(interface_number) == 242 device_->claimed_interfaces_.end()) 243 return false; 244 245 device_->claimed_interfaces_.erase(interface_number); 246 return true; 247 } 248 249 virtual bool SetInterfaceAlternateSetting( 250 const int interface_number, 251 const int alternate_setting) OVERRIDE { 252 return true; 253 } 254 255 virtual bool ResetDevice() OVERRIDE { return true; } 256 257 virtual bool GetSerial(base::string16* serial) OVERRIDE { 258 *serial = base::UTF8ToUTF16(kDeviceSerial); 259 return true; 260 } 261 262 // Async IO. Can be called on any thread. 263 virtual void ControlTransfer(const UsbEndpointDirection direction, 264 const TransferRequestType request_type, 265 const TransferRecipient recipient, 266 const uint8 request, 267 const uint16 value, 268 const uint16 index, 269 net::IOBuffer* buffer, 270 const size_t length, 271 const unsigned int timeout, 272 const UsbTransferCallback& callback) OVERRIDE {} 273 274 virtual void BulkTransfer(const UsbEndpointDirection direction, 275 const uint8 endpoint, 276 net::IOBuffer* buffer, 277 const size_t length, 278 const unsigned int timeout, 279 const UsbTransferCallback& callback) OVERRIDE { 280 if (direction == USB_DIRECTION_OUTBOUND) { 281 if (remaining_body_length_ == 0) { 282 std::vector<uint32> header(6); 283 memcpy(&header[0], buffer->data(), length); 284 current_message_ = new AdbMessage(header[0], header[1], header[2], ""); 285 remaining_body_length_ = header[3]; 286 uint32 magic = header[5]; 287 if ((current_message_->command ^ 0xffffffff) != magic) { 288 DCHECK(false) << "Header checksum error"; 289 return; 290 } 291 } else { 292 DCHECK(current_message_); 293 current_message_->body += std::string(buffer->data(), length); 294 remaining_body_length_ -= length; 295 } 296 297 if (remaining_body_length_ == 0) { 298 ProcessIncoming(); 299 } 300 301 base::MessageLoop::current()->PostTask( 302 FROM_HERE, 303 base::Bind(callback, 304 usb_service::USB_TRANSFER_COMPLETED, 305 scoped_refptr<net::IOBuffer>(), 306 0)); 307 308 } else if (direction == USB_DIRECTION_INBOUND) { 309 queries_.push(Query(callback, make_scoped_refptr(buffer), length)); 310 ProcessQueries(); 311 } 312 } 313 314 template <class D> 315 void append(D data) { 316 std::copy(reinterpret_cast<char*>(&data), 317 (reinterpret_cast<char*>(&data)) + sizeof(D), 318 std::back_inserter(output_buffer_)); 319 } 320 321 // Copied from AndroidUsbDevice::Checksum 322 uint32 Checksum(const std::string& data) { 323 unsigned char* x = (unsigned char*)data.data(); 324 int count = data.length(); 325 uint32 sum = 0; 326 while (count-- > 0) 327 sum += *x++; 328 return sum; 329 } 330 331 void ProcessIncoming() { 332 DCHECK(current_message_); 333 switch (current_message_->command) { 334 case AdbMessage::kCommandCNXN: 335 WriteResponse(new AdbMessage(AdbMessage::kCommandCNXN, 336 kVersion, 337 kMaxPayload, 338 "device::ro.product.name=SampleProduct;ro." 339 "product.model=SampleModel;ro.product." 340 "device=SampleDevice;")); 341 break; 342 case AdbMessage::kCommandOPEN: 343 DCHECK(current_message_->arg1 == 0); 344 DCHECK(current_message_->arg0 != 0); 345 if (current_message_->body.find("shell:") != std::string::npos) { 346 WriteResponse(new AdbMessage(AdbMessage::kCommandOKAY, 347 ++next_local_socket_, 348 current_message_->arg0, 349 "")); 350 WriteResponse( 351 new AdbMessage(AdbMessage::kCommandWRTE, 352 next_local_socket_, 353 current_message_->arg0, 354 GetMockShellResponse(current_message_->body.substr( 355 0, current_message_->body.size() - 1)))); 356 WriteResponse(new AdbMessage( 357 AdbMessage::kCommandCLSE, 0, current_message_->arg0, "")); 358 } 359 default: 360 return; 361 } 362 ProcessQueries(); 363 } 364 365 void WriteResponse(scoped_refptr<AdbMessage> response) { 366 append(response->command); 367 append(response->arg0); 368 append(response->arg1); 369 bool add_zero = response->body.length() && 370 (response->command != AdbMessage::kCommandWRTE); 371 append(static_cast<uint32>(response->body.length() + (add_zero ? 1 : 0))); 372 append(Checksum(response->body)); 373 append(response->command ^ 0xffffffff); 374 std::copy(response->body.begin(), 375 response->body.end(), 376 std::back_inserter(output_buffer_)); 377 if (add_zero) { 378 output_buffer_.push_back(0); 379 } 380 ProcessQueries(); 381 } 382 383 void ProcessQueries() { 384 if (!queries_.size()) 385 return; 386 Query query = queries_.front(); 387 388 if (query.size > output_buffer_.size()) 389 return; 390 391 queries_.pop(); 392 std::copy(output_buffer_.begin(), 393 output_buffer_.begin() + query.size, 394 query.buffer->data()); 395 output_buffer_.erase(output_buffer_.begin(), 396 output_buffer_.begin() + query.size); 397 base::MessageLoop::current()->PostTask( 398 FROM_HERE, 399 base::Bind(query.callback, 400 usb_service::USB_TRANSFER_COMPLETED, 401 query.buffer, 402 query.size)); 403 } 404 405 virtual void InterruptTransfer(const UsbEndpointDirection direction, 406 const uint8 endpoint, 407 net::IOBuffer* buffer, 408 const size_t length, 409 const unsigned int timeout, 410 const UsbTransferCallback& callback) OVERRIDE { 411 } 412 413 virtual void IsochronousTransfer( 414 const UsbEndpointDirection direction, 415 const uint8 endpoint, 416 net::IOBuffer* buffer, 417 const size_t length, 418 const unsigned int packets, 419 const unsigned int packet_length, 420 const unsigned int timeout, 421 const UsbTransferCallback& callback) OVERRIDE {} 422 423 protected: 424 virtual ~MockUsbDeviceHandle() {} 425 426 struct Query { 427 UsbTransferCallback callback; 428 scoped_refptr<net::IOBuffer> buffer; 429 size_t size; 430 431 Query(UsbTransferCallback callback, 432 scoped_refptr<net::IOBuffer> buffer, 433 int size) 434 : callback(callback), buffer(buffer), size(size) {}; 435 }; 436 437 scoped_refptr<MockUsbDevice<T> > device_; 438 uint32 remaining_body_length_; 439 scoped_refptr<AdbMessage> current_message_; 440 std::vector<char> output_buffer_; 441 std::queue<Query> queries_; 442 int next_local_socket_; 443 }; 444 445 template <class T> 446 class MockUsbDevice : public UsbDevice { 447 public: 448 MockUsbDevice() : UsbDevice(0, 0, 0) {} 449 450 virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE { 451 return new MockUsbDeviceHandle<T>(this); 452 } 453 454 virtual scoped_refptr<UsbConfigDescriptor> ListInterfaces() OVERRIDE { 455 return new MockUsbConfigDescriptor<T>(); 456 } 457 458 virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) OVERRIDE { 459 return true; 460 } 461 462 #if defined(OS_CHROMEOS) 463 // On ChromeOS, if an interface of a claimed device is not claimed, the 464 // permission broker can change the owner of the device so that the unclaimed 465 // interfaces can be used. If this argument is missing, permission broker will 466 // not be used and this method fails if the device is claimed. 467 virtual void RequestUsbAcess( 468 int interface_id, 469 const base::Callback<void(bool success)>& callback) OVERRIDE { 470 callback.Run(true); 471 } 472 #endif // OS_CHROMEOS 473 474 std::set<int> claimed_interfaces_; 475 476 protected: 477 virtual ~MockUsbDevice() {} 478 }; 479 480 class MockUsbService : public UsbService { 481 public: 482 MockUsbService() { 483 devices_.push_back(new MockUsbDevice<AndroidTraits>()); 484 } 485 486 virtual ~MockUsbService() {} 487 488 virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE { 489 NOTIMPLEMENTED(); 490 return NULL; 491 } 492 493 virtual void GetDevices( 494 std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE { 495 STLClearObject(devices); 496 std::copy(devices_.begin(), devices_.end(), back_inserter(*devices)); 497 } 498 499 std::vector<scoped_refptr<UsbDevice> > devices_; 500 }; 501 502 class MockUsbServiceForCheckingTraits : public UsbService { 503 public: 504 MockUsbServiceForCheckingTraits() : step_(0) {} 505 506 virtual ~MockUsbServiceForCheckingTraits() {} 507 508 virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE { 509 NOTIMPLEMENTED(); 510 return NULL; 511 } 512 513 virtual void GetDevices( 514 std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE { 515 STLClearObject(devices); 516 // This switch should be kept in sync with 517 // AndroidUsbBrowserTest::DeviceCountChanged. 518 switch (step_) { 519 case 0: 520 // No devices. 521 break; 522 case 1: 523 // Android device. 524 devices->push_back(new MockUsbDevice<AndroidTraits>()); 525 break; 526 case 2: 527 // Android and non-android device. 528 devices->push_back(new MockUsbDevice<AndroidTraits>()); 529 devices->push_back(new MockUsbDevice<NonAndroidTraits>()); 530 break; 531 case 3: 532 // Non-android device. 533 devices->push_back(new MockUsbDevice<NonAndroidTraits>()); 534 break; 535 } 536 step_++; 537 } 538 539 private: 540 int step_; 541 }; 542 543 class DevToolsAndroidBridgeWarmUp 544 : public DevToolsAndroidBridge::DeviceCountListener { 545 public: 546 DevToolsAndroidBridgeWarmUp(base::Closure closure, 547 scoped_refptr<DevToolsAndroidBridge> adb_bridge) 548 : closure_(closure), adb_bridge_(adb_bridge) {} 549 550 virtual void DeviceCountChanged(int count) OVERRIDE { 551 adb_bridge_->RemoveDeviceCountListener(this); 552 closure_.Run(); 553 } 554 555 base::Closure closure_; 556 scoped_refptr<DevToolsAndroidBridge> adb_bridge_; 557 }; 558 559 class AndroidUsbDiscoveryTest : public InProcessBrowserTest { 560 protected: 561 AndroidUsbDiscoveryTest() 562 : scheduler_invoked_(0) { 563 } 564 virtual void SetUpOnMainThread() OVERRIDE { 565 scoped_refptr<content::MessageLoopRunner> runner = 566 new content::MessageLoopRunner; 567 568 BrowserThread::PostTaskAndReply( 569 BrowserThread::FILE, 570 FROM_HERE, 571 base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this), 572 runner->QuitClosure()); 573 runner->Run(); 574 575 adb_bridge_ = 576 DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile()); 577 DCHECK(adb_bridge_); 578 adb_bridge_->set_task_scheduler_for_test(base::Bind( 579 &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest, this)); 580 581 scoped_refptr<UsbDeviceProvider> provider = 582 new UsbDeviceProvider(browser()->profile()); 583 584 AndroidDeviceManager::DeviceProviders providers; 585 providers.push_back(provider); 586 adb_bridge_->set_device_providers_for_test(providers); 587 runner_ = new content::MessageLoopRunner; 588 } 589 590 void ScheduleDeviceCountRequest(const base::Closure& request) { 591 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 592 scheduler_invoked_++; 593 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request); 594 } 595 596 virtual void SetUpService() { 597 UsbService::SetInstanceForTest(new MockUsbService()); 598 } 599 600 virtual void CleanUpOnMainThread() OVERRIDE { 601 scoped_refptr<content::MessageLoopRunner> runner = 602 new content::MessageLoopRunner; 603 UsbService* service = NULL; 604 BrowserThread::PostTaskAndReply( 605 BrowserThread::FILE, 606 FROM_HERE, 607 base::Bind(&UsbService::SetInstanceForTest, service), 608 runner->QuitClosure()); 609 runner->Run(); 610 } 611 612 scoped_refptr<content::MessageLoopRunner> runner_; 613 scoped_refptr<DevToolsAndroidBridge> adb_bridge_; 614 int scheduler_invoked_; 615 }; 616 617 class AndroidUsbCountTest : public AndroidUsbDiscoveryTest { 618 protected: 619 virtual void SetUpOnMainThread() OVERRIDE { 620 AndroidUsbDiscoveryTest::SetUpOnMainThread(); 621 DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_); 622 adb_bridge_->AddDeviceCountListener(&warmup); 623 runner_->Run(); 624 runner_ = new content::MessageLoopRunner; 625 } 626 }; 627 628 class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest { 629 protected: 630 virtual void SetUpService() OVERRIDE { 631 UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits()); 632 } 633 }; 634 635 class MockListListener : public DevToolsAndroidBridge::DeviceListListener { 636 public: 637 MockListListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge, 638 const base::Closure& callback) 639 : adb_bridge_(adb_bridge), 640 callback_(callback) { 641 } 642 643 virtual void DeviceListChanged( 644 const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE { 645 if (devices.size() > 0) { 646 if (devices[0]->is_connected()) { 647 ASSERT_EQ(kDeviceModel, devices[0]->model()); 648 ASSERT_EQ(kDeviceSerial, devices[0]->serial()); 649 adb_bridge_->RemoveDeviceListListener(this); 650 callback_.Run(); 651 } 652 } 653 } 654 655 scoped_refptr<DevToolsAndroidBridge> adb_bridge_; 656 base::Closure callback_; 657 }; 658 659 class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener { 660 public: 661 explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge) 662 : adb_bridge_(adb_bridge), 663 reposts_left_(10), 664 invoked_(0) { 665 } 666 667 virtual void DeviceCountChanged(int count) OVERRIDE { 668 ++invoked_; 669 adb_bridge_->RemoveDeviceCountListener(this); 670 Shutdown(); 671 } 672 673 void Shutdown() { 674 ShutdownOnUIThread(); 675 }; 676 677 void ShutdownOnUIThread() { 678 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 679 if (reposts_left_-- == 0) { 680 base::MessageLoop::current()->Quit(); 681 } else { 682 BrowserThread::PostTask( 683 BrowserThread::FILE, 684 FROM_HERE, 685 base::Bind(&MockCountListener::ShutdownOnFileThread, 686 base::Unretained(this))); 687 } 688 } 689 690 void ShutdownOnFileThread() { 691 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 692 BrowserThread::PostTask(BrowserThread::UI, 693 FROM_HERE, 694 base::Bind(&MockCountListener::ShutdownOnUIThread, 695 base::Unretained(this))); 696 } 697 698 scoped_refptr<DevToolsAndroidBridge> adb_bridge_; 699 int reposts_left_; 700 int invoked_; 701 }; 702 703 class MockCountListenerWithReAdd : public MockCountListener { 704 public: 705 explicit MockCountListenerWithReAdd( 706 scoped_refptr<DevToolsAndroidBridge> adb_bridge) 707 : MockCountListener(adb_bridge), 708 readd_count_(2) { 709 } 710 711 virtual void DeviceCountChanged(int count) OVERRIDE { 712 ++invoked_; 713 adb_bridge_->RemoveDeviceCountListener(this); 714 if (readd_count_ > 0) { 715 readd_count_--; 716 adb_bridge_->AddDeviceCountListener(this); 717 adb_bridge_->RemoveDeviceCountListener(this); 718 adb_bridge_->AddDeviceCountListener(this); 719 } else { 720 Shutdown(); 721 } 722 } 723 724 int readd_count_; 725 }; 726 727 class MockCountListenerWithReAddWhileQueued : public MockCountListener { 728 public: 729 MockCountListenerWithReAddWhileQueued( 730 scoped_refptr<DevToolsAndroidBridge> adb_bridge) 731 : MockCountListener(adb_bridge), 732 readded_(false) { 733 } 734 735 virtual void DeviceCountChanged(int count) OVERRIDE { 736 ++invoked_; 737 if (!readded_) { 738 readded_ = true; 739 base::MessageLoop::current()->PostTask( 740 FROM_HERE, 741 base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd, 742 base::Unretained(this))); 743 } else { 744 adb_bridge_->RemoveDeviceCountListener(this); 745 Shutdown(); 746 } 747 } 748 749 void ReAdd() { 750 adb_bridge_->RemoveDeviceCountListener(this); 751 adb_bridge_->AddDeviceCountListener(this); 752 } 753 754 bool readded_; 755 }; 756 757 class MockCountListenerForCheckingTraits : public MockCountListener { 758 public: 759 MockCountListenerForCheckingTraits( 760 scoped_refptr<DevToolsAndroidBridge> adb_bridge) 761 : MockCountListener(adb_bridge), 762 step_(0) { 763 } 764 virtual void DeviceCountChanged(int count) OVERRIDE { 765 switch (step_) { 766 case 0: 767 // Check for 0 devices when no devices present. 768 EXPECT_EQ(0, count); 769 break; 770 case 1: 771 // Check for 1 device when only android device present. 772 EXPECT_EQ(1, count); 773 break; 774 case 2: 775 // Check for 1 device when android and non-android devices present. 776 EXPECT_EQ(1, count); 777 break; 778 case 3: 779 // Check for 0 devices when only non-android devices present. 780 EXPECT_EQ(0, count); 781 adb_bridge_->RemoveDeviceCountListener(this); 782 Shutdown(); 783 break; 784 default: 785 EXPECT_TRUE(false) << "Unknown step " << step_; 786 } 787 step_++; 788 } 789 790 int step_; 791 }; 792 793 } // namespace 794 795 IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) { 796 MockListListener listener(adb_bridge_, runner_->QuitClosure()); 797 adb_bridge_->AddDeviceListListener(&listener); 798 runner_->Run(); 799 } 800 801 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, 802 TestNoMultipleCallsRemoveInCallback) { 803 MockCountListener listener(adb_bridge_); 804 adb_bridge_->AddDeviceCountListener(&listener); 805 runner_->Run(); 806 EXPECT_EQ(1, listener.invoked_); 807 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_); 808 } 809 810 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, 811 TestNoMultipleCallsRemoveAddInCallback) { 812 MockCountListenerWithReAdd listener(adb_bridge_); 813 adb_bridge_->AddDeviceCountListener(&listener); 814 runner_->Run(); 815 EXPECT_EQ(3, listener.invoked_); 816 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_); 817 } 818 819 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, 820 TestNoMultipleCallsRemoveAddOnStart) { 821 MockCountListener listener(adb_bridge_); 822 adb_bridge_->AddDeviceCountListener(&listener); 823 adb_bridge_->RemoveDeviceCountListener(&listener); 824 adb_bridge_->AddDeviceCountListener(&listener); 825 runner_->Run(); 826 EXPECT_EQ(1, listener.invoked_); 827 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_); 828 } 829 830 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, 831 TestNoMultipleCallsRemoveAddWhileQueued) { 832 MockCountListenerWithReAddWhileQueued listener(adb_bridge_); 833 adb_bridge_->AddDeviceCountListener(&listener); 834 runner_->Run(); 835 EXPECT_EQ(2, listener.invoked_); 836 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_); 837 } 838 839 IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) { 840 MockCountListenerForCheckingTraits listener(adb_bridge_); 841 adb_bridge_->AddDeviceCountListener(&listener); 842 runner_->Run(); 843 } 844