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
21using content::BrowserThread;
22using device::UsbConfigDescriptor;
23using device::UsbDevice;
24using device::UsbDeviceHandle;
25using device::UsbEndpointDescriptor;
26using device::UsbEndpointDirection;
27using device::UsbInterfaceDescriptor;
28using device::UsbService;
29using device::UsbSynchronizationType;
30using device::UsbTransferCallback;
31using device::UsbTransferType;
32using device::UsbUsageType;
33
34namespace {
35
36struct AndroidTraits {
37  static const int kClass = 0xff;
38  static const int kSubclass = 0x42;
39  static const int kProtocol = 0x1;
40};
41
42struct NonAndroidTraits {
43  static const int kClass = 0xf0;
44  static const int kSubclass = 0x42;
45  static const int kProtocol = 0x2;
46};
47
48const uint32 kMaxPayload = 4096;
49const uint32 kVersion = 0x01000000;
50
51const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
52const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
53const char kDumpsysCommand[] = "shell:dumpsys window policy";
54const char kListProcessesCommand[] = "shell:ps";
55const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
56const char kDeviceManufacturer[] = "Test Manufacturer";
57const char kDeviceModel[] = "Nexus 5";
58const char kDeviceSerial[] = "Sample serial";
59
60const 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
67const 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
75const 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
82const 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
88const 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
106template <class T>
107class MockUsbDevice;
108
109template <class T>
110class 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
334template <class T>
335class 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
410class 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
432class 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
473class 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
489class 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
547class 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
558class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
559 protected:
560  virtual void SetUpService() OVERRIDE {
561    UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
562  }
563};
564
565class 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
589class 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
633class 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
657class 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
687class 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
725IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
726  MockListListener listener(adb_bridge_, runner_->QuitClosure());
727  adb_bridge_->AddDeviceListListener(&listener);
728  runner_->Run();
729}
730
731IN_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
740IN_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
749IN_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
760IN_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
769IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
770  MockCountListenerForCheckingTraits listener(adb_bridge_);
771  adb_bridge_->AddDeviceCountListener(&listener);
772  runner_->Run();
773}
774