android_usb_browsertest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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
21using content::BrowserThread;
22using namespace usb_service;
23
24namespace {
25
26struct AndroidTraits {
27  static const int kClass = 0xff;
28  static const int kSubclass = 0x42;
29  static const int kProtocol = 0x1;
30};
31
32struct NonAndroidTraits {
33  static const int kClass = 0xf0;
34  static const int kSubclass = 0x42;
35  static const int kProtocol = 0x2;
36};
37
38const uint32 kMaxPayload = 4096;
39const uint32 kVersion = 0x01000000;
40
41const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
42const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
43const char kDumpsysCommand[] = "shell:dumpsys window policy";
44const char kListProcessesCommand[] = "shell:ps";
45const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
46const char kDeviceModel[] = "Nexus 5";
47const char kDeviceSerial[] = "Sample serial";
48
49const 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
56const 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
64const 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
71const 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
77const 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
95class 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
130template <class T>
131class 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
176template <class T>
177class 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
197template <class T>
198class 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
214template <class T>
215class MockUsbDevice;
216
217template <class T>
218class 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
445template <class T>
446class 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
480class 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
502class 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
543class 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
559class 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
617class 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
628class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
629 protected:
630  virtual void SetUpService() OVERRIDE {
631    UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
632  }
633};
634
635class 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
659class 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
703class 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
727class 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
757class 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
795IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
796  MockListListener listener(adb_bridge_, runner_->QuitClosure());
797  adb_bridge_->AddDeviceListListener(&listener);
798  runner_->Run();
799}
800
801IN_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
810IN_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
819IN_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
830IN_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
839IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
840  MockCountListenerForCheckingTraits listener(adb_bridge_);
841  adb_bridge_->AddDeviceCountListener(&listener);
842  runner_->Run();
843}
844