Home | History | Annotate | Download | only in usb
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
      9 #include "chrome/browser/devtools/device/usb/android_usb_device.h"
     10 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
     11 #include "chrome/browser/ui/browser.h"
     12 #include "chrome/test/base/in_process_browser_test.h"
     13 #include "components/usb_service/usb_device.h"
     14 #include "components/usb_service/usb_device_handle.h"
     15 #include "components/usb_service/usb_interface.h"
     16 #include "components/usb_service/usb_service.h"
     17 #include "content/public/browser/browser_thread.h"
     18 #include "content/public/test/test_utils.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 using content::BrowserThread;
     22 using namespace usb_service;
     23 
     24 namespace {
     25 
     26 struct AndroidTraits {
     27   static const int kClass = 0xff;
     28   static const int kSubclass = 0x42;
     29   static const int kProtocol = 0x1;
     30 };
     31 
     32 struct NonAndroidTraits {
     33   static const int kClass = 0xf0;
     34   static const int kSubclass = 0x42;
     35   static const int kProtocol = 0x2;
     36 };
     37 
     38 const uint32 kMaxPayload = 4096;
     39 const uint32 kVersion = 0x01000000;
     40 
     41 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
     42 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
     43 const char kDumpsysCommand[] = "shell:dumpsys window policy";
     44 const char kListProcessesCommand[] = "shell:ps";
     45 const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
     46 const char kDeviceModel[] = "Nexus 5";
     47 const char kDeviceSerial[] = "Sample serial";
     48 
     49 const char kSampleOpenedUnixSockets[] =
     50     "Num       RefCount Protocol Flags    Type St Inode Path\n"
     51     "00000000: 00000004 00000000"
     52     " 00000000 0002 01  3328 /dev/socket/wpa_wlan0\n"
     53     "00000000: 00000002 00000000"
     54     " 00010000 0001 01  5394 /dev/socket/vold\n";
     55 
     56 const char kSampleListProcesses[] =
     57     "USER   PID  PPID VSIZE  RSS    WCHAN    PC         NAME\n"
     58     "root   1    0    688    508    ffffffff 00000000 S /init\r\n"
     59     "u0_a75 2425 123  933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
     60     "nfc    741  123  706448 26316  ffffffff 00000000 S com.android.nfc\r\n"
     61     "u0_a76 1001 124  111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
     62     "u0_a78 1003 126  111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
     63 
     64 const char kSampleListPackages[] =
     65     "package:com.sample.feed\r\n"
     66     "package:com.android.nfc\r\n"
     67     "package:com.android.chrome\r\n"
     68     "package:com.chrome.beta\r\n"
     69     "package:com.google.android.apps.chrome\r\n";
     70 
     71 const char kSampleDumpsys[] =
     72     "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
     73     "    mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
     74     "    mStable=(0,50)-(720,1184)\r\n"  // Only mStable parameter is parsed
     75     "    mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
     76 
     77 const char* GetMockShellResponse(std::string command) {
     78   if (command == kDeviceModelCommand) {
     79     return kDeviceModel;
     80   } else if (command == kOpenedUnixSocketsCommand) {
     81     return kSampleOpenedUnixSockets;
     82   } else if (command == kDumpsysCommand) {
     83     return kSampleDumpsys;
     84   } else if (command == kListProcessesCommand) {
     85     return kSampleListProcesses;
     86   } else if (command == kInstalledChromePackagesCommand) {
     87     return kSampleListPackages;
     88   }
     89 
     90   DCHECK(false) << "Should not be reached";
     91 
     92   return "";
     93 }
     94 
     95 class MockUsbEndpointDescriptor : public UsbEndpointDescriptor {
     96  public:
     97   virtual int GetAddress() const OVERRIDE { return address_; }
     98 
     99   virtual UsbEndpointDirection GetDirection() const OVERRIDE {
    100     return direction_;
    101   }
    102 
    103   virtual int GetMaximumPacketSize() const OVERRIDE {
    104     return maximum_packet_size_;
    105   }
    106 
    107   virtual UsbSynchronizationType GetSynchronizationType() const OVERRIDE {
    108     return usb_synchronization_type_;
    109   }
    110 
    111   virtual UsbTransferType GetTransferType() const OVERRIDE {
    112     return usb_transfer_type_;
    113   }
    114   virtual UsbUsageType GetUsageType() const OVERRIDE { return usb_usage_type_; }
    115 
    116   virtual int GetPollingInterval() const OVERRIDE { return polling_interval_; }
    117 
    118   int address_;
    119   UsbEndpointDirection direction_;
    120   int maximum_packet_size_;
    121   UsbSynchronizationType usb_synchronization_type_;
    122   UsbTransferType usb_transfer_type_;
    123   UsbUsageType usb_usage_type_;
    124   int polling_interval_;
    125 
    126  private:
    127   virtual ~MockUsbEndpointDescriptor() {}
    128 };
    129 
    130 template <class T>
    131 class MockUsbInterfaceAltSettingDescriptor
    132     : public UsbInterfaceAltSettingDescriptor {
    133  public:
    134   MockUsbInterfaceAltSettingDescriptor(int interface_number,
    135                                        int alternate_setting)
    136       : interface_number_(interface_number),
    137         alternate_setting_(alternate_setting) {}
    138 
    139   virtual size_t GetNumEndpoints() const OVERRIDE {
    140     // See IsAndroidInterface function in android_usb_device.cc
    141     return 2;
    142   }
    143 
    144   virtual scoped_refptr<const UsbEndpointDescriptor> GetEndpoint(
    145       size_t index) const OVERRIDE {
    146     EXPECT_GT(static_cast<size_t>(2), index);
    147     MockUsbEndpointDescriptor* result = new MockUsbEndpointDescriptor();
    148     result->address_ = index + 1;
    149     result->usb_transfer_type_ = USB_TRANSFER_BULK;
    150     result->direction_ =
    151         ((index == 0) ? USB_DIRECTION_INBOUND : USB_DIRECTION_OUTBOUND);
    152     result->maximum_packet_size_ = 1 << 20;  // 1Mb maximum packet size
    153     return result;
    154   }
    155 
    156   virtual int GetInterfaceNumber() const OVERRIDE { return interface_number_; }
    157 
    158   virtual int GetAlternateSetting() const OVERRIDE {
    159     return alternate_setting_;
    160   }
    161 
    162   virtual int GetInterfaceClass() const OVERRIDE { return T::kClass; }
    163 
    164   virtual int GetInterfaceSubclass() const OVERRIDE { return T::kSubclass; }
    165 
    166   virtual int GetInterfaceProtocol() const OVERRIDE { return T::kProtocol; }
    167 
    168  protected:
    169   virtual ~MockUsbInterfaceAltSettingDescriptor() {};
    170 
    171  private:
    172   const int interface_number_;
    173   const int alternate_setting_;
    174 };
    175 
    176 template <class T>
    177 class MockUsbInterfaceDescriptor : public UsbInterfaceDescriptor {
    178  public:
    179   explicit MockUsbInterfaceDescriptor(int interface_number)
    180       : interface_number_(interface_number) {}
    181 
    182   virtual size_t GetNumAltSettings() const OVERRIDE {
    183     // See IsAndroidInterface function in android_usb_device.cc
    184     return 1;
    185   }
    186   virtual scoped_refptr<const UsbInterfaceAltSettingDescriptor> GetAltSetting(
    187       size_t index) const OVERRIDE {
    188     EXPECT_EQ(static_cast<size_t>(0), index);
    189     return new MockUsbInterfaceAltSettingDescriptor<T>(interface_number_, 0);
    190   }
    191 
    192  protected:
    193   const int interface_number_;
    194   virtual ~MockUsbInterfaceDescriptor() {}
    195 };
    196 
    197 template <class T>
    198 class MockUsbConfigDescriptor : public UsbConfigDescriptor {
    199  public:
    200   MockUsbConfigDescriptor() {}
    201 
    202   virtual size_t GetNumInterfaces() const OVERRIDE { return 1; }
    203 
    204   virtual scoped_refptr<const UsbInterfaceDescriptor> GetInterface(
    205       size_t index) const OVERRIDE {
    206     EXPECT_EQ(static_cast<size_t>(0), index);
    207     return new MockUsbInterfaceDescriptor<T>(index);
    208   }
    209 
    210  protected:
    211   virtual ~MockUsbConfigDescriptor() {};
    212 };
    213 
    214 template <class T>
    215 class MockUsbDevice;
    216 
    217 template <class T>
    218 class MockUsbDeviceHandle : public UsbDeviceHandle {
    219  public:
    220   explicit MockUsbDeviceHandle(MockUsbDevice<T>* device)
    221       : device_(device),
    222         remaining_body_length_(0),
    223         next_local_socket_(0) {}
    224 
    225   virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE {
    226     return device_;
    227   }
    228 
    229   virtual void Close() OVERRIDE { device_ = NULL; }
    230 
    231   bool ClaimInterface(const int interface_number) {
    232     if (device_->claimed_interfaces_.find(interface_number) !=
    233         device_->claimed_interfaces_.end())
    234       return false;
    235 
    236     device_->claimed_interfaces_.insert(interface_number);
    237     return true;
    238   }
    239 
    240   bool ReleaseInterface(const int interface_number) {
    241     if (device_->claimed_interfaces_.find(interface_number) ==
    242         device_->claimed_interfaces_.end())
    243       return false;
    244 
    245     device_->claimed_interfaces_.erase(interface_number);
    246     return true;
    247   }
    248 
    249   virtual bool SetInterfaceAlternateSetting(
    250       const int interface_number,
    251       const int alternate_setting) OVERRIDE {
    252     return true;
    253   }
    254 
    255   virtual bool ResetDevice() OVERRIDE { return true; }
    256 
    257   virtual bool GetSerial(base::string16* serial) OVERRIDE {
    258     *serial = base::UTF8ToUTF16(kDeviceSerial);
    259     return true;
    260   }
    261 
    262   // Async IO. Can be called on any thread.
    263   virtual void ControlTransfer(const UsbEndpointDirection direction,
    264                                const TransferRequestType request_type,
    265                                const TransferRecipient recipient,
    266                                const uint8 request,
    267                                const uint16 value,
    268                                const uint16 index,
    269                                net::IOBuffer* buffer,
    270                                const size_t length,
    271                                const unsigned int timeout,
    272                                const UsbTransferCallback& callback) OVERRIDE {}
    273 
    274   virtual void BulkTransfer(const UsbEndpointDirection direction,
    275                             const uint8 endpoint,
    276                             net::IOBuffer* buffer,
    277                             const size_t length,
    278                             const unsigned int timeout,
    279                             const UsbTransferCallback& callback) OVERRIDE {
    280     if (direction == USB_DIRECTION_OUTBOUND) {
    281       if (remaining_body_length_ == 0) {
    282         std::vector<uint32> header(6);
    283         memcpy(&header[0], buffer->data(), length);
    284         current_message_ = new AdbMessage(header[0], header[1], header[2], "");
    285         remaining_body_length_ = header[3];
    286         uint32 magic = header[5];
    287         if ((current_message_->command ^ 0xffffffff) != magic) {
    288           DCHECK(false) << "Header checksum error";
    289           return;
    290         }
    291       } else {
    292         DCHECK(current_message_);
    293         current_message_->body += std::string(buffer->data(), length);
    294         remaining_body_length_ -= length;
    295       }
    296 
    297       if (remaining_body_length_ == 0) {
    298         ProcessIncoming();
    299       }
    300 
    301       base::MessageLoop::current()->PostTask(
    302           FROM_HERE,
    303           base::Bind(callback,
    304                      usb_service::USB_TRANSFER_COMPLETED,
    305                      scoped_refptr<net::IOBuffer>(),
    306                      0));
    307 
    308     } else if (direction == USB_DIRECTION_INBOUND) {
    309       queries_.push(Query(callback, make_scoped_refptr(buffer), length));
    310       ProcessQueries();
    311     }
    312   }
    313 
    314   template <class D>
    315   void append(D data) {
    316     std::copy(reinterpret_cast<char*>(&data),
    317               (reinterpret_cast<char*>(&data)) + sizeof(D),
    318               std::back_inserter(output_buffer_));
    319   }
    320 
    321   // Copied from AndroidUsbDevice::Checksum
    322   uint32 Checksum(const std::string& data) {
    323     unsigned char* x = (unsigned char*)data.data();
    324     int count = data.length();
    325     uint32 sum = 0;
    326     while (count-- > 0)
    327       sum += *x++;
    328     return sum;
    329   }
    330 
    331   void ProcessIncoming() {
    332     DCHECK(current_message_);
    333     switch (current_message_->command) {
    334       case AdbMessage::kCommandCNXN:
    335         WriteResponse(new AdbMessage(AdbMessage::kCommandCNXN,
    336                                      kVersion,
    337                                      kMaxPayload,
    338                                      "device::ro.product.name=SampleProduct;ro."
    339                                      "product.model=SampleModel;ro.product."
    340                                      "device=SampleDevice;"));
    341         break;
    342       case AdbMessage::kCommandOPEN:
    343         DCHECK(current_message_->arg1 == 0);
    344         DCHECK(current_message_->arg0 != 0);
    345         if (current_message_->body.find("shell:") != std::string::npos) {
    346           WriteResponse(new AdbMessage(AdbMessage::kCommandOKAY,
    347                                        ++next_local_socket_,
    348                                        current_message_->arg0,
    349                                        ""));
    350           WriteResponse(
    351               new AdbMessage(AdbMessage::kCommandWRTE,
    352                              next_local_socket_,
    353                              current_message_->arg0,
    354                              GetMockShellResponse(current_message_->body.substr(
    355                                  0, current_message_->body.size() - 1))));
    356           WriteResponse(new AdbMessage(
    357               AdbMessage::kCommandCLSE, 0, current_message_->arg0, ""));
    358         }
    359       default:
    360         return;
    361     }
    362     ProcessQueries();
    363   }
    364 
    365   void WriteResponse(scoped_refptr<AdbMessage> response) {
    366     append(response->command);
    367     append(response->arg0);
    368     append(response->arg1);
    369     bool add_zero = response->body.length() &&
    370                     (response->command != AdbMessage::kCommandWRTE);
    371     append(static_cast<uint32>(response->body.length() + (add_zero ? 1 : 0)));
    372     append(Checksum(response->body));
    373     append(response->command ^ 0xffffffff);
    374     std::copy(response->body.begin(),
    375               response->body.end(),
    376               std::back_inserter(output_buffer_));
    377     if (add_zero) {
    378       output_buffer_.push_back(0);
    379     }
    380     ProcessQueries();
    381   }
    382 
    383   void ProcessQueries() {
    384     if (!queries_.size())
    385       return;
    386     Query query = queries_.front();
    387 
    388     if (query.size > output_buffer_.size())
    389       return;
    390 
    391     queries_.pop();
    392     std::copy(output_buffer_.begin(),
    393               output_buffer_.begin() + query.size,
    394               query.buffer->data());
    395     output_buffer_.erase(output_buffer_.begin(),
    396                          output_buffer_.begin() + query.size);
    397     base::MessageLoop::current()->PostTask(
    398         FROM_HERE,
    399         base::Bind(query.callback,
    400                    usb_service::USB_TRANSFER_COMPLETED,
    401                    query.buffer,
    402                    query.size));
    403   }
    404 
    405   virtual void InterruptTransfer(const UsbEndpointDirection direction,
    406                                  const uint8 endpoint,
    407                                  net::IOBuffer* buffer,
    408                                  const size_t length,
    409                                  const unsigned int timeout,
    410                                  const UsbTransferCallback& callback) OVERRIDE {
    411   }
    412 
    413   virtual void IsochronousTransfer(
    414       const UsbEndpointDirection direction,
    415       const uint8 endpoint,
    416       net::IOBuffer* buffer,
    417       const size_t length,
    418       const unsigned int packets,
    419       const unsigned int packet_length,
    420       const unsigned int timeout,
    421       const UsbTransferCallback& callback) OVERRIDE {}
    422 
    423  protected:
    424   virtual ~MockUsbDeviceHandle() {}
    425 
    426   struct Query {
    427     UsbTransferCallback callback;
    428     scoped_refptr<net::IOBuffer> buffer;
    429     size_t size;
    430 
    431     Query(UsbTransferCallback callback,
    432           scoped_refptr<net::IOBuffer> buffer,
    433           int size)
    434         : callback(callback), buffer(buffer), size(size) {};
    435   };
    436 
    437   scoped_refptr<MockUsbDevice<T> > device_;
    438   uint32 remaining_body_length_;
    439   scoped_refptr<AdbMessage> current_message_;
    440   std::vector<char> output_buffer_;
    441   std::queue<Query> queries_;
    442   int next_local_socket_;
    443 };
    444 
    445 template <class T>
    446 class MockUsbDevice : public UsbDevice {
    447  public:
    448   MockUsbDevice() : UsbDevice(0, 0, 0) {}
    449 
    450   virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE {
    451     return new MockUsbDeviceHandle<T>(this);
    452   }
    453 
    454   virtual scoped_refptr<UsbConfigDescriptor> ListInterfaces() OVERRIDE {
    455     return new MockUsbConfigDescriptor<T>();
    456   }
    457 
    458   virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) OVERRIDE {
    459     return true;
    460   }
    461 
    462 #if defined(OS_CHROMEOS)
    463   // On ChromeOS, if an interface of a claimed device is not claimed, the
    464   // permission broker can change the owner of the device so that the unclaimed
    465   // interfaces can be used. If this argument is missing, permission broker will
    466   // not be used and this method fails if the device is claimed.
    467   virtual void RequestUsbAcess(
    468       int interface_id,
    469       const base::Callback<void(bool success)>& callback) OVERRIDE {
    470     callback.Run(true);
    471   }
    472 #endif  // OS_CHROMEOS
    473 
    474   std::set<int> claimed_interfaces_;
    475 
    476  protected:
    477   virtual ~MockUsbDevice() {}
    478 };
    479 
    480 class MockUsbService : public UsbService {
    481  public:
    482   MockUsbService() {
    483     devices_.push_back(new MockUsbDevice<AndroidTraits>());
    484   }
    485 
    486   virtual ~MockUsbService() {}
    487 
    488   virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE {
    489     NOTIMPLEMENTED();
    490     return NULL;
    491   }
    492 
    493   virtual void GetDevices(
    494       std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE {
    495     STLClearObject(devices);
    496     std::copy(devices_.begin(), devices_.end(), back_inserter(*devices));
    497   }
    498 
    499   std::vector<scoped_refptr<UsbDevice> > devices_;
    500 };
    501 
    502 class MockUsbServiceForCheckingTraits : public UsbService {
    503  public:
    504   MockUsbServiceForCheckingTraits() : step_(0) {}
    505 
    506   virtual ~MockUsbServiceForCheckingTraits() {}
    507 
    508   virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE {
    509     NOTIMPLEMENTED();
    510     return NULL;
    511   }
    512 
    513   virtual void GetDevices(
    514       std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE {
    515     STLClearObject(devices);
    516     // This switch should be kept in sync with
    517     // AndroidUsbBrowserTest::DeviceCountChanged.
    518     switch (step_) {
    519       case 0:
    520         // No devices.
    521         break;
    522       case 1:
    523         // Android device.
    524         devices->push_back(new MockUsbDevice<AndroidTraits>());
    525         break;
    526       case 2:
    527         // Android and non-android device.
    528         devices->push_back(new MockUsbDevice<AndroidTraits>());
    529         devices->push_back(new MockUsbDevice<NonAndroidTraits>());
    530         break;
    531       case 3:
    532         // Non-android device.
    533         devices->push_back(new MockUsbDevice<NonAndroidTraits>());
    534         break;
    535     }
    536     step_++;
    537   }
    538 
    539  private:
    540   int step_;
    541 };
    542 
    543 class DevToolsAndroidBridgeWarmUp
    544     : public DevToolsAndroidBridge::DeviceCountListener {
    545  public:
    546   DevToolsAndroidBridgeWarmUp(base::Closure closure,
    547                               scoped_refptr<DevToolsAndroidBridge> adb_bridge)
    548       : closure_(closure), adb_bridge_(adb_bridge) {}
    549 
    550   virtual void DeviceCountChanged(int count) OVERRIDE {
    551     adb_bridge_->RemoveDeviceCountListener(this);
    552     closure_.Run();
    553   }
    554 
    555   base::Closure closure_;
    556   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
    557 };
    558 
    559 class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
    560  protected:
    561   AndroidUsbDiscoveryTest()
    562       : scheduler_invoked_(0) {
    563   }
    564   virtual void SetUpOnMainThread() OVERRIDE {
    565     scoped_refptr<content::MessageLoopRunner> runner =
    566         new content::MessageLoopRunner;
    567 
    568     BrowserThread::PostTaskAndReply(
    569         BrowserThread::FILE,
    570         FROM_HERE,
    571         base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this),
    572         runner->QuitClosure());
    573     runner->Run();
    574 
    575     adb_bridge_ =
    576         DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
    577     DCHECK(adb_bridge_);
    578     adb_bridge_->set_task_scheduler_for_test(base::Bind(
    579         &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest, this));
    580 
    581     scoped_refptr<UsbDeviceProvider> provider =
    582         new UsbDeviceProvider(browser()->profile());
    583 
    584     AndroidDeviceManager::DeviceProviders providers;
    585     providers.push_back(provider);
    586     adb_bridge_->set_device_providers_for_test(providers);
    587     runner_ = new content::MessageLoopRunner;
    588   }
    589 
    590   void ScheduleDeviceCountRequest(const base::Closure& request) {
    591     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    592     scheduler_invoked_++;
    593     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
    594   }
    595 
    596   virtual void SetUpService() {
    597     UsbService::SetInstanceForTest(new MockUsbService());
    598   }
    599 
    600   virtual void CleanUpOnMainThread() OVERRIDE {
    601     scoped_refptr<content::MessageLoopRunner> runner =
    602         new content::MessageLoopRunner;
    603     UsbService* service = NULL;
    604     BrowserThread::PostTaskAndReply(
    605         BrowserThread::FILE,
    606         FROM_HERE,
    607         base::Bind(&UsbService::SetInstanceForTest, service),
    608         runner->QuitClosure());
    609     runner->Run();
    610   }
    611 
    612   scoped_refptr<content::MessageLoopRunner> runner_;
    613   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
    614   int scheduler_invoked_;
    615 };
    616 
    617 class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
    618  protected:
    619   virtual void SetUpOnMainThread() OVERRIDE {
    620     AndroidUsbDiscoveryTest::SetUpOnMainThread();
    621     DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_);
    622     adb_bridge_->AddDeviceCountListener(&warmup);
    623     runner_->Run();
    624     runner_ = new content::MessageLoopRunner;
    625   }
    626 };
    627 
    628 class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
    629  protected:
    630   virtual void SetUpService() OVERRIDE {
    631     UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
    632   }
    633 };
    634 
    635 class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
    636  public:
    637   MockListListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge,
    638                    const base::Closure& callback)
    639       : adb_bridge_(adb_bridge),
    640         callback_(callback) {
    641   }
    642 
    643   virtual void DeviceListChanged(
    644       const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE {
    645     if (devices.size() > 0) {
    646       if (devices[0]->is_connected()) {
    647         ASSERT_EQ(kDeviceModel, devices[0]->model());
    648         ASSERT_EQ(kDeviceSerial, devices[0]->serial());
    649         adb_bridge_->RemoveDeviceListListener(this);
    650         callback_.Run();
    651       }
    652     }
    653   }
    654 
    655   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
    656   base::Closure callback_;
    657 };
    658 
    659 class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
    660  public:
    661   explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge)
    662       : adb_bridge_(adb_bridge),
    663         reposts_left_(10),
    664         invoked_(0) {
    665   }
    666 
    667   virtual void DeviceCountChanged(int count) OVERRIDE {
    668     ++invoked_;
    669     adb_bridge_->RemoveDeviceCountListener(this);
    670     Shutdown();
    671   }
    672 
    673   void Shutdown() {
    674     ShutdownOnUIThread();
    675   };
    676 
    677   void ShutdownOnUIThread() {
    678     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    679     if (reposts_left_-- == 0) {
    680       base::MessageLoop::current()->Quit();
    681     } else {
    682       BrowserThread::PostTask(
    683           BrowserThread::FILE,
    684           FROM_HERE,
    685           base::Bind(&MockCountListener::ShutdownOnFileThread,
    686                      base::Unretained(this)));
    687     }
    688   }
    689 
    690   void ShutdownOnFileThread() {
    691     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    692     BrowserThread::PostTask(BrowserThread::UI,
    693                             FROM_HERE,
    694                             base::Bind(&MockCountListener::ShutdownOnUIThread,
    695                                        base::Unretained(this)));
    696   }
    697 
    698   scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
    699   int reposts_left_;
    700   int invoked_;
    701 };
    702 
    703 class MockCountListenerWithReAdd : public MockCountListener {
    704  public:
    705   explicit MockCountListenerWithReAdd(
    706       scoped_refptr<DevToolsAndroidBridge> adb_bridge)
    707       : MockCountListener(adb_bridge),
    708         readd_count_(2) {
    709   }
    710 
    711   virtual void DeviceCountChanged(int count) OVERRIDE {
    712     ++invoked_;
    713     adb_bridge_->RemoveDeviceCountListener(this);
    714     if (readd_count_ > 0) {
    715       readd_count_--;
    716       adb_bridge_->AddDeviceCountListener(this);
    717       adb_bridge_->RemoveDeviceCountListener(this);
    718       adb_bridge_->AddDeviceCountListener(this);
    719     } else {
    720       Shutdown();
    721     }
    722   }
    723 
    724   int readd_count_;
    725 };
    726 
    727 class MockCountListenerWithReAddWhileQueued : public MockCountListener {
    728  public:
    729   MockCountListenerWithReAddWhileQueued(
    730       scoped_refptr<DevToolsAndroidBridge> adb_bridge)
    731       : MockCountListener(adb_bridge),
    732         readded_(false) {
    733   }
    734 
    735   virtual void DeviceCountChanged(int count) OVERRIDE {
    736     ++invoked_;
    737     if (!readded_) {
    738       readded_ = true;
    739       base::MessageLoop::current()->PostTask(
    740           FROM_HERE,
    741           base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd,
    742                      base::Unretained(this)));
    743     } else {
    744       adb_bridge_->RemoveDeviceCountListener(this);
    745       Shutdown();
    746     }
    747   }
    748 
    749   void ReAdd() {
    750     adb_bridge_->RemoveDeviceCountListener(this);
    751     adb_bridge_->AddDeviceCountListener(this);
    752   }
    753 
    754   bool readded_;
    755 };
    756 
    757 class MockCountListenerForCheckingTraits : public MockCountListener {
    758  public:
    759   MockCountListenerForCheckingTraits(
    760       scoped_refptr<DevToolsAndroidBridge> adb_bridge)
    761       : MockCountListener(adb_bridge),
    762         step_(0) {
    763   }
    764   virtual void DeviceCountChanged(int count) OVERRIDE {
    765     switch (step_) {
    766       case 0:
    767         // Check for 0 devices when no devices present.
    768         EXPECT_EQ(0, count);
    769         break;
    770       case 1:
    771         // Check for 1 device when only android device present.
    772         EXPECT_EQ(1, count);
    773         break;
    774       case 2:
    775         // Check for 1 device when android and non-android devices present.
    776         EXPECT_EQ(1, count);
    777         break;
    778       case 3:
    779         // Check for 0 devices when only non-android devices present.
    780         EXPECT_EQ(0, count);
    781         adb_bridge_->RemoveDeviceCountListener(this);
    782         Shutdown();
    783         break;
    784       default:
    785         EXPECT_TRUE(false) << "Unknown step " << step_;
    786     }
    787     step_++;
    788   }
    789 
    790   int step_;
    791 };
    792 
    793 }  // namespace
    794 
    795 IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
    796   MockListListener listener(adb_bridge_, runner_->QuitClosure());
    797   adb_bridge_->AddDeviceListListener(&listener);
    798   runner_->Run();
    799 }
    800 
    801 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
    802                        TestNoMultipleCallsRemoveInCallback) {
    803   MockCountListener listener(adb_bridge_);
    804   adb_bridge_->AddDeviceCountListener(&listener);
    805   runner_->Run();
    806   EXPECT_EQ(1, listener.invoked_);
    807   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
    808 }
    809 
    810 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
    811                        TestNoMultipleCallsRemoveAddInCallback) {
    812   MockCountListenerWithReAdd listener(adb_bridge_);
    813   adb_bridge_->AddDeviceCountListener(&listener);
    814   runner_->Run();
    815   EXPECT_EQ(3, listener.invoked_);
    816   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
    817 }
    818 
    819 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
    820                        TestNoMultipleCallsRemoveAddOnStart) {
    821   MockCountListener listener(adb_bridge_);
    822   adb_bridge_->AddDeviceCountListener(&listener);
    823   adb_bridge_->RemoveDeviceCountListener(&listener);
    824   adb_bridge_->AddDeviceCountListener(&listener);
    825   runner_->Run();
    826   EXPECT_EQ(1, listener.invoked_);
    827   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
    828 }
    829 
    830 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
    831                        TestNoMultipleCallsRemoveAddWhileQueued) {
    832   MockCountListenerWithReAddWhileQueued listener(adb_bridge_);
    833   adb_bridge_->AddDeviceCountListener(&listener);
    834   runner_->Run();
    835   EXPECT_EQ(2, listener.invoked_);
    836   EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
    837 }
    838 
    839 IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
    840   MockCountListenerForCheckingTraits listener(adb_bridge_);
    841   adb_bridge_->AddDeviceCountListener(&listener);
    842   runner_->Run();
    843 }
    844