OLD | NEW |
(Empty) | |
| 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 } |
OLD | NEW |