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