Chromium Code Reviews| 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() { | |
| 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 virtual void DeviceListChanged( | |
| 643 const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE { | |
| 644 if (devices.size() > 0) { | |
| 645 if (devices[0]->is_connected()) { | |
| 646 ASSERT_EQ(kDeviceModel, devices[0]->model()); | |
| 647 ASSERT_EQ(kDeviceSerial, devices[0]->serial()); | |
| 648 adb_bridge_->RemoveDeviceListListener(this); | |
| 649 callback_.Run(); | |
| 650 } | |
| 651 } | |
| 652 } | |
| 653 | |
| 654 scoped_refptr<DevToolsAndroidBridge> adb_bridge_; | |
| 655 base::Closure callback_; | |
| 656 }; | |
| 657 | |
| 658 class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener { | |
| 659 public: | |
| 660 explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge) | |
| 661 : adb_bridge_(adb_bridge), | |
| 662 reposts_left_(10), | |
| 663 invoked_(0) { | |
| 664 } | |
| 665 | |
| 666 virtual void DeviceCountChanged(int count) OVERRIDE { | |
| 667 ++invoked_; | |
| 668 adb_bridge_->RemoveDeviceCountListener(this); | |
| 669 Shutdown(); | |
| 670 } | |
| 671 | |
| 672 void Shutdown() { | |
| 673 ShutdownOnUIThread(); | |
| 674 }; | |
| 675 | |
| 676 void ShutdownOnUIThread() { | |
| 677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 678 if (reposts_left_-- == 0) { | |
| 679 base::MessageLoop::current()->Quit(); | |
| 680 } else { | |
| 681 BrowserThread::PostTask( | |
| 682 BrowserThread::FILE, | |
| 683 FROM_HERE, | |
| 684 base::Bind(&MockCountListener::ShutdownOnFileThread, | |
| 685 base::Unretained(this))); | |
| 686 } | |
| 687 } | |
| 688 | |
| 689 void ShutdownOnFileThread() { | |
| 690 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 691 BrowserThread::PostTask(BrowserThread::UI, | |
| 692 FROM_HERE, | |
| 693 base::Bind(&MockCountListener::ShutdownOnUIThread, | |
| 694 base::Unretained(this))); | |
| 695 } | |
| 696 | |
| 697 scoped_refptr<DevToolsAndroidBridge> adb_bridge_; | |
| 698 int reposts_left_; | |
| 699 int invoked_; | |
| 700 }; | |
| 701 | |
| 702 class MockCountListenerWithReAdd : public MockCountListener { | |
| 703 public: | |
| 704 explicit MockCountListenerWithReAdd( | |
| 705 scoped_refptr<DevToolsAndroidBridge> adb_bridge) | |
| 706 : MockCountListener(adb_bridge), | |
| 707 readd_count_(2) { | |
| 708 } | |
| 709 | |
| 710 virtual void DeviceCountChanged(int count) OVERRIDE { | |
| 711 ++invoked_; | |
| 712 adb_bridge_->RemoveDeviceCountListener(this); | |
| 713 if (readd_count_ > 0) { | |
| 714 readd_count_--; | |
| 715 adb_bridge_->AddDeviceCountListener(this); | |
| 716 adb_bridge_->RemoveDeviceCountListener(this); | |
| 717 adb_bridge_->AddDeviceCountListener(this); | |
| 718 } else { | |
| 719 Shutdown(); | |
| 720 } | |
| 721 } | |
| 722 | |
| 723 int readd_count_; | |
| 724 }; | |
| 725 | |
| 726 class MockCountListenerWithReAddWhileQueued : public MockCountListener { | |
| 727 public: | |
| 728 MockCountListenerWithReAddWhileQueued( | |
| 729 scoped_refptr<DevToolsAndroidBridge> adb_bridge) | |
| 730 : MockCountListener(adb_bridge), | |
| 731 readded_(false) { | |
| 732 } | |
| 733 | |
| 734 virtual void DeviceCountChanged(int count) OVERRIDE { | |
| 735 ++invoked_; | |
| 736 if (!readded_) { | |
| 737 readded_ = true; | |
| 738 base::MessageLoop::current()->PostTask( | |
| 739 FROM_HERE, | |
| 740 base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd, | |
| 741 base::Unretained(this))); | |
| 742 } else { | |
| 743 adb_bridge_->RemoveDeviceCountListener(this); | |
| 744 Shutdown(); | |
| 745 } | |
| 746 } | |
| 747 | |
| 748 void ReAdd() { | |
| 749 adb_bridge_->RemoveDeviceCountListener(this); | |
| 750 adb_bridge_->AddDeviceCountListener(this); | |
| 751 } | |
| 752 | |
| 753 bool readded_; | |
| 754 }; | |
| 755 | |
| 756 class MockCountListenerForCheckingTraits : public MockCountListener { | |
| 757 public: | |
| 758 MockCountListenerForCheckingTraits( | |
| 759 scoped_refptr<DevToolsAndroidBridge> adb_bridge) | |
| 760 : MockCountListener(adb_bridge), | |
| 761 step_(0) { | |
| 762 } | |
| 763 virtual void DeviceCountChanged(int count) OVERRIDE { | |
| 764 switch (step_) { | |
| 765 case 0: | |
| 766 // Check for 0 devices when no devices present. | |
| 767 EXPECT_EQ(0, count); | |
| 768 break; | |
| 769 case 1: | |
| 770 // Check for 1 device when only android device present. | |
| 771 EXPECT_EQ(1, count); | |
| 772 break; | |
| 773 case 2: | |
| 774 // Check for 1 device when android and non-android devices present. | |
| 775 EXPECT_EQ(1, count); | |
| 776 break; | |
| 777 case 3: | |
| 778 // Check for 0 devices when only non-android devices present. | |
| 779 EXPECT_EQ(0, count); | |
| 780 adb_bridge_->RemoveDeviceCountListener(this); | |
| 781 Shutdown(); | |
| 782 break; | |
| 783 default: | |
| 784 EXPECT_TRUE(false) << "Unknown step " << step_; | |
| 785 } | |
| 786 step_++; | |
| 787 } | |
| 788 | |
| 789 int step_; | |
| 790 }; | |
| 791 | |
| 792 } // namespace | |
| 793 | |
| 794 IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) { | |
| 795 scoped_ptr<MockListListener> listener( | |
| 796 new MockListListener(adb_bridge_, runner_->QuitClosure())); | |
| 797 adb_bridge_->AddDeviceListListener(listener.get()); | |
| 798 runner_->Run(); | |
| 799 } | |
| 800 | |
| 801 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, | |
| 802 TestNoMultipleCallsRemoveInCallback) { | |
| 803 scoped_ptr<MockCountListener> listener(new MockCountListener(adb_bridge_)); | |
|
Vladislav Kaznacheev
2014/06/17 10:27:16
Is there a reason you are using scoped_ptr instead
vkuzkokov
2014/06/17 13:01:44
No reason. Moved to stack.
| |
| 804 | |
| 805 adb_bridge_->AddDeviceCountListener(listener.get()); | |
| 806 | |
| 807 runner_->Run(); | |
| 808 EXPECT_EQ(1, listener->invoked_); | |
| 809 EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_); | |
| 810 } | |
| 811 | |
| 812 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, | |
| 813 TestNoMultipleCallsRemoveAddInCallback) { | |
| 814 scoped_ptr<MockCountListener> listener( | |
| 815 new MockCountListenerWithReAdd(adb_bridge_)); | |
| 816 | |
| 817 adb_bridge_->AddDeviceCountListener(listener.get()); | |
| 818 | |
| 819 runner_->Run(); | |
| 820 EXPECT_EQ(3, listener->invoked_); | |
| 821 EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_); | |
| 822 } | |
| 823 | |
| 824 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, | |
| 825 TestNoMultipleCallsRemoveAddOnStart) { | |
| 826 scoped_ptr<MockCountListener> listener(new MockCountListener(adb_bridge_)); | |
| 827 | |
| 828 adb_bridge_->AddDeviceCountListener(listener.get()); | |
| 829 adb_bridge_->RemoveDeviceCountListener(listener.get()); | |
| 830 adb_bridge_->AddDeviceCountListener(listener.get()); | |
| 831 | |
| 832 runner_->Run(); | |
| 833 EXPECT_EQ(1, listener->invoked_); | |
| 834 EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_); | |
| 835 } | |
| 836 | |
| 837 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest, | |
| 838 TestNoMultipleCallsRemoveAddWhileQueued) { | |
| 839 scoped_ptr<MockCountListener> listener( | |
| 840 new MockCountListenerWithReAddWhileQueued(adb_bridge_)); | |
| 841 | |
| 842 adb_bridge_->AddDeviceCountListener(listener.get()); | |
| 843 | |
| 844 runner_->Run(); | |
| 845 EXPECT_EQ(2, listener->invoked_); | |
| 846 EXPECT_EQ(listener->invoked_ - 1, scheduler_invoked_); | |
| 847 } | |
| 848 | |
| 849 IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) { | |
| 850 scoped_ptr<MockCountListener> listener( | |
| 851 new MockCountListenerForCheckingTraits(adb_bridge_)); | |
| 852 | |
| 853 adb_bridge_->AddDeviceCountListener(listener.get()); | |
| 854 runner_->Run(); | |
| 855 } | |
| OLD | NEW |