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