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 |