text: // Copyright 2014 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include <stddef.h>
  #include <stdint.h>
  
  #include <algorithm>
  #include <unordered_map>
  #include <utility>
  
  #include "base/bind.h"
  #include "base/containers/queue.h"
  #include "base/location.h"
  #include "base/memory/ptr_util.h"
  #include "base/memory/ref_counted_memory.h"
  #include "base/run_loop.h"
  #include "base/single_thread_task_runner.h"
  #include "base/strings/utf_string_conversions.h"
  #include "base/threading/thread_task_runner_handle.h"
  #include "chrome/browser/devtools/device/adb/mock_adb_server.h"
  #include "chrome/browser/devtools/device/devtools_android_bridge.h"
  #include "chrome/browser/devtools/device/usb/android_usb_device.h"
  #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
  #include "chrome/browser/ui/browser.h"
  #include "chrome/test/base/in_process_browser_test.h"
  #include "content/public/browser/browser_task_traits.h"
  #include "content/public/browser/browser_thread.h"
  #include "content/public/test/browser_test.h"
  #include "content/public/test/test_utils.h"
  #include "mojo/public/cpp/bindings/pending_receiver.h"
  #include "mojo/public/cpp/bindings/pending_remote.h"
  #include "mojo/public/cpp/bindings/self_owned_receiver.h"
  #include "services/device/public/cpp/test/fake_usb_device.h"
  #include "services/device/public/cpp/test/fake_usb_device_info.h"
  #include "services/device/public/cpp/test/fake_usb_device_manager.h"
  #include "services/device/public/mojom/usb_device.mojom.h"
  #include "services/device/public/mojom/usb_enumeration_options.mojom.h"
  #include "services/device/public/mojom/usb_manager.mojom.h"
  #include "testing/gtest/include/gtest/gtest.h"
  
  using content::BrowserThread;
  
  using device::FakeUsbDevice;
  using device::FakeUsbDeviceInfo;
  using device::FakeUsbDeviceManager;
  using device::mojom::UsbAlternateInterfaceInfo;
  using device::mojom::UsbConfigurationInfo;
  using device::mojom::UsbConfigurationInfoPtr;
  using device::mojom::UsbDevice;
  using device::mojom::UsbEndpointInfo;
  using device::mojom::UsbEndpointInfoPtr;
  using device::mojom::UsbInterfaceInfo;
  using device::mojom::UsbInterfaceInfoPtr;
  using device::mojom::UsbTransferDirection;
  using device::mojom::UsbTransferStatus;
  using device::mojom::UsbTransferType;
  
  namespace {
  
  struct NoConfigTraits {
    static const int kClass = 0xff;
    static const int kSubclass = 0x42;
    static const int kProtocol = 0x1;
    static const bool kBreaks = false;
    static const bool kConfigured = false;
  };
  
  struct AndroidTraits {
    static const int kClass = 0xff;
    static const int kSubclass = 0x42;
    static const int kProtocol = 0x1;
    static const bool kBreaks = false;
    static const bool kConfigured = true;
  };
  
  struct NonAndroidTraits {
    static const int kClass = 0xf0;
    static const int kSubclass = 0x42;
    static const int kProtocol = 0x2;
    static const bool kBreaks = false;
    static const bool kConfigured = true;
  };
  
  struct BreakingAndroidTraits {
    static const int kClass = 0xff;
    static const int kSubclass = 0x42;
    static const int kProtocol = 0x1;
    static const bool kBreaks = true;
    static const bool kConfigured = true;
  };
  
  const uint32_t kMaxPayload = 4096;
  const uint32_t kVersion = 0x01000000;
  const uint8_t kAndroidConfigValue = 1;
  
  const char kDeviceManufacturer[] = "Test Manufacturer";
  const char kDeviceModel[] = "Nexus 6";
  const char kDeviceSerial[] = "01498B321301A00A";
  
  UsbConfigurationInfoPtr ConstructAndroidConfig(uint8_t class_code,
                                                 uint8_t subclass_code,
                                                 uint8_t protocol_code) {
    std::vector<UsbEndpointInfoPtr> endpoints;
    auto endpoint_1 = UsbEndpointInfo::New();
    endpoint_1->endpoint_number = 0x01;
    endpoint_1->direction = UsbTransferDirection::INBOUND;
    endpoint_1->type = UsbTransferType::BULK;
    endpoint_1->packet_size = 512;
    endpoints.push_back(std::move(endpoint_1));
  
    auto endpoint_2 = UsbEndpointInfo::New();
    endpoint_2->endpoint_number = 0x01;
    endpoint_2->direction = UsbTransferDirection::OUTBOUND;
    endpoint_2->type = UsbTransferType::BULK;
    endpoint_2->packet_size = 512;
    endpoints.push_back(std::move(endpoint_2));
  
    auto alternate = UsbAlternateInterfaceInfo::New();
    alternate->alternate_setting = 0;
    alternate->class_code = class_code;
    alternate->subclass_code = subclass_code;
    alternate->protocol_code = protocol_code;
    alternate->endpoints = std::move(endpoints);
  
    auto interface = UsbInterfaceInfo::New();
    interface->interface_number = 0;
    interface->alternates.push_back(std::move(alternate));
  
    auto config = UsbConfigurationInfo::New();
    config->configuration_value = kAndroidConfigValue;
    config->interfaces.push_back(std::move(interface));
  
    return config;
  }
  
  class FakeAndroidUsbDeviceInfo : public FakeUsbDeviceInfo {
   public:
    explicit FakeAndroidUsbDeviceInfo(bool is_broken)
        : FakeUsbDeviceInfo(/*vendor_id=*/0,
                            /*product_id=*/0,
                            kDeviceManufacturer,
                            kDeviceModel,
                            kDeviceSerial,
                            std::vector<UsbConfigurationInfoPtr>()),
          broken_traits_(is_broken) {}
  
    bool broken_traits() const { return broken_traits_; }
    device::mojom::UsbDeviceInfoPtr ClonePtr() { return GetDeviceInfo().Clone(); }
  
   private:
    ~FakeAndroidUsbDeviceInfo() override = default;
  
    bool broken_traits_;
  };
  
  template <class T>
  scoped_refptr<FakeAndroidUsbDeviceInfo> ConstructFakeUsbDevice() {
    const bool broken = T::kBreaks;
    auto device = base::MakeRefCounted<FakeAndroidUsbDeviceInfo>(broken);
    auto config = ConstructAndroidConfig(T::kClass, T::kSubclass, T::kProtocol);
    auto config_value = config->configuration_value;
    device->AddConfig(std::move(config));
    if (T::kConfigured)
      device->SetActiveConfig(config_value);
  
    return device;
  }
  
  class MockLocalSocket : public MockAndroidConnection::Delegate {
   public:
    using Callback =
        base::RepeatingCallback<void(int command, const std::string& message)>;
  
    MockLocalSocket(const Callback& callback,
                    const std::string& serial,
                    const std::string& command)
        : callback_(callback),
          connection_(
              std::make_unique<MockAndroidConnection>(this, serial, command)) {}
    ~MockLocalSocket() override = default;
  
    void Receive(const std::string& data) {
      connection_->Receive(data);
    }
  
   private:
    void SendSuccess(const std::string& message) override {
      if (!message.empty())
        callback_.Run(AdbMessage::kCommandWRTE, message);
    }
  
    void SendRaw(const std::string& message) override {
      callback_.Run(AdbMessage::kCommandWRTE, message);
    }
  
    void Close() override {
      callback_.Run(AdbMessage::kCommandCLSE, std::string());
    }
  
    Callback callback_;
    std::unique_ptr<MockAndroidConnection> connection_;
  };
  
  class FakeAndroidUsbDevice : public FakeUsbDevice {
   public:
    static void Create(
        scoped_refptr<FakeUsbDeviceInfo> device_info,
        mojo::PendingReceiver<device::mojom::UsbDevice> receiver,
        mojo::PendingRemote<device::mojom::UsbDeviceClient> client) {
      auto* device_object =
          new FakeAndroidUsbDevice(device_info, std::move(client));
      device_object->receiver_ = mojo::MakeSelfOwnedReceiver(
          base::WrapUnique(device_object), std::move(receiver));
    }
  
    ~FakeAndroidUsbDevice() override = default;
  
   protected:
    FakeAndroidUsbDevice(
        scoped_refptr<FakeUsbDeviceInfo> device,
        mojo::PendingRemote<device::mojom::UsbDeviceClient> client)
        : FakeUsbDevice(device,
                        /*blocked_interface_classes=*/{},
                        std::move(client)) {
      broken_traits_ =
          static_cast<FakeAndroidUsbDeviceInfo*>(device.get())->broken_traits();
    }
  
    // override device::FakeUsbDevice
    void GenericTransferIn(uint8_t endpoint_number,
                           uint32_t length,
                           uint32_t timeout,
                           GenericTransferInCallback callback) override {
      queries_.push(Query(std::move(callback), length));
      ProcessQueries();
    }
  
    void GenericTransferOut(uint8_t endpoint_number,
                            const std::vector<uint8_t>& buffer,
                            uint32_t timeout,
                            GenericTransferOutCallback callback) override {
      if (remaining_body_length_ == 0) {
        // A new message, parse header first.
        DCHECK_GE(buffer.size(), 6u);
        const auto* header = reinterpret_cast<const uint32_t*>(buffer.data());
        current_message_ = std::make_unique<AdbMessage>(header[0], header[1],
                                                        header[2], std::string());
        remaining_body_length_ = header[3];
        uint32_t magic = header[5];
        if ((current_message_->command ^ 0xffffffff) != magic) {
          DCHECK(false) << "Header checksum error";
          base::ThreadTaskRunnerHandle::Get()->PostTask(
              FROM_HERE, base::BindOnce(std::move(callback),
                                        UsbTransferStatus::TRANSFER_ERROR));
          return;
        }
      } else {
        // Parse body.
        DCHECK(current_message_.get());
        current_message_->body += std::string(
            reinterpret_cast<const char*>(buffer.data()), buffer.size());
        remaining_body_length_ -= buffer.size();
      }
  
      if (remaining_body_length_ == 0) {
        ProcessIncoming();
      }
  
      UsbTransferStatus status = broken_ ? UsbTransferStatus::TRANSFER_ERROR
                                         : UsbTransferStatus::COMPLETED;
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE, base::BindOnce(std::move(callback), status));
      ProcessQueries();
    }
  
    template <class D>
    void append(D data) {
      std::copy(reinterpret_cast<uint8_t*>(&data),
                (reinterpret_cast<uint8_t*>(&data)) + sizeof(D),
                std::back_inserter(output_buffer_));
    }
  
    // Copied from AndroidUsbDevice::Checksum
    uint32_t Checksum(const std::string& data) {
      unsigned char* x = (unsigned char*)data.data();
      int count = data.length();
      uint32_t sum = 0;
      while (count-- > 0)
        sum += *x++;
      return sum;
    }
  
    void ProcessIncoming() {
      DCHECK(current_message_.get());
      switch (current_message_->command) {
        case AdbMessage::kCommandCNXN: {
          WriteResponse(kVersion,
                        kMaxPayload,
                        AdbMessage::kCommandCNXN,
                        "device::ro.product.name=SampleProduct;ro.product.model="
                        "SampleModel;ro.product.device=SampleDevice;");
          break;
        }
        case AdbMessage::kCommandCLSE: {
          WriteResponse(0,
                        current_message_->arg0,
                        AdbMessage::kCommandCLSE,
                        std::string());
          local_sockets_.erase(current_message_->arg0);
          break;
        }
        case AdbMessage::kCommandWRTE: {
          if (broken_traits_) {
            broken_ = true;
            return;
          }
  
          auto it = local_sockets_.find(current_message_->arg0);
          if (it == local_sockets_.end())
            return;
  
          DCHECK(current_message_->arg1);
          WriteResponse(current_message_->arg1,
                        current_message_->arg0,
                        AdbMessage::kCommandOKAY,
                        std::string());
          it->second->Receive(current_message_->body);
          break;
        }
        case AdbMessage::kCommandOPEN: {
          DCHECK(!current_message_->arg1);
          DCHECK(current_message_->arg0);
          std::string response;
          WriteResponse(++last_local_socket_,
                        current_message_->arg0,
                        AdbMessage::kCommandOKAY,
                        std::string());
          local_sockets_[current_message_->arg0] =
              std::make_unique<MockLocalSocket>(
                  base::BindRepeating(&FakeAndroidUsbDevice::WriteResponse,
                                      base::Unretained(this), last_local_socket_,
                                      current_message_->arg0),
                  kDeviceSerial,
                  current_message_->body.substr(
                      0, current_message_->body.size() - 1));
          return;
        }
        default: {
          return;
        }
      }
      ProcessQueries();
    }
  
    void WriteResponse(int arg0, int arg1, int command, const std::string& body) {
      append(command);
      append(arg0);
      append(arg1);
      bool add_zero = !body.empty() && (command != AdbMessage::kCommandWRTE);
      append(static_cast<uint32_t>(body.size() + (add_zero ? 1 : 0)));
      append(Checksum(body));
      append(command ^ 0xffffffff);
      const auto* body_head = reinterpret_cast<const uint8_t*>(body.data());
      std::copy(body_head, body_head + body.size(),
                std::back_inserter(output_buffer_));
      if (add_zero) {
        output_buffer_.push_back(0);
      }
      ProcessQueries();
    }
  
    void ProcessQueries() {
      if (queries_.empty())
        return;
  
      if (broken_) {
        Query query = std::move(queries_.front());
        queries_.pop();
        base::ThreadTaskRunnerHandle::Get()->PostTask(
            FROM_HERE, base::BindOnce(std::move(query.callback),
                                      UsbTransferStatus::TRANSFER_ERROR,
                                      std::vector<uint8_t>()));
        return;
      }
  
      if (queries_.front().size > output_buffer_.size())
        return;
  
      Query query = std::move(queries_.front());
      queries_.pop();
      std::vector<uint8_t> response_buffer;
      std::copy(output_buffer_.begin(), output_buffer_.begin() + query.size,
                std::back_inserter(response_buffer));
      output_buffer_.erase(output_buffer_.begin(),
                           output_buffer_.begin() + query.size);
  
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE,
          base::BindOnce(std::move(query.callback), UsbTransferStatus::COMPLETED,
                         std::move(response_buffer)));
    }
  
    struct Query {
      GenericTransferInCallback callback;
      size_t size;
  
      Query(GenericTransferInCallback callback, int size)
          : callback(std::move(callback)), size(size) {}
    };
  
    uint32_t remaining_body_length_ = 0;
    std::unique_ptr<AdbMessage> current_message_;
    std::vector<uint8_t> output_buffer_;
    base::queue<Query> queries_;
    std::unordered_map<int, std::unique_ptr<MockLocalSocket>> local_sockets_;
    int last_local_socket_ = 0;
    bool broken_ = false;
    bool broken_traits_ = false;
  };
  
  class FakeAndroidUsbManager : public FakeUsbDeviceManager {
   public:
    FakeAndroidUsbManager() = default;
    ~FakeAndroidUsbManager() override = default;
  
    void GetDevice(
        const std::string& guid,
        const std::vector<uint8_t>& blocked_interface_classes,
        mojo::PendingReceiver<device::mojom::UsbDevice> device_receiver,
        mojo::PendingRemote<device::mojom::UsbDeviceClient> device_client)
        override {
      DCHECK(base::Contains(devices(), guid));
      FakeAndroidUsbDevice::Create(devices()[guid], std::move(device_receiver),
                                   std::move(device_client));
    }
  };
  
  class FakeUsbManagerForCheckingTraits : public FakeAndroidUsbManager {
   public:
    FakeUsbManagerForCheckingTraits() = default;
    ~FakeUsbManagerForCheckingTraits() override = default;
  
    void GetDevices(device::mojom::UsbEnumerationOptionsPtr options,
                    GetDevicesCallback callback) override {
      std::vector<device::mojom::UsbDeviceInfoPtr> device_infos;
      // This switch should be kept in sync with
      // AndroidUsbBrowserTest::DeviceCountChanged.
      switch (step_) {
        case 0:
          // No devices.
          break;
        case 1:
          // Android device.
          device_infos.push_back(
              ConstructFakeUsbDevice<AndroidTraits>()->ClonePtr());
          break;
        case 2:
          // Android and non-android device.
          device_infos.push_back(
              ConstructFakeUsbDevice<AndroidTraits>()->ClonePtr());
          device_infos.push_back(
              ConstructFakeUsbDevice<NonAndroidTraits>()->ClonePtr());
          break;
        case 3:
          // Non-android device.
          device_infos.push_back(
              ConstructFakeUsbDevice<NonAndroidTraits>()->ClonePtr());
          break;
      }
      step_++;
      std::move(callback).Run(std::move(device_infos));
    }
  
   private:
    int step_ = 0;
  };
  
  class DevToolsAndroidBridgeWarmUp
      : public DevToolsAndroidBridge::DeviceCountListener {
   public:
    DevToolsAndroidBridgeWarmUp(base::OnceClosure closure,
                                DevToolsAndroidBridge* adb_bridge)
        : closure_(std::move(closure)), adb_bridge_(adb_bridge) {}
    ~DevToolsAndroidBridgeWarmUp() override = default;
  
    void DeviceCountChanged(int count) override {
      adb_bridge_->RemoveDeviceCountListener(this);
      std::move(closure_).Run();
    }
  
   private:
    base::OnceClosure closure_;
    DevToolsAndroidBridge* adb_bridge_;
  };
  
  class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
   protected:
    AndroidUsbDiscoveryTest() = default;
    ~AndroidUsbDiscoveryTest() override = default;
  
    void SetUpOnMainThread() override {
      adb_bridge_ =
          DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
      DCHECK(adb_bridge_);
      adb_bridge_->set_task_scheduler_for_test(base::BindRepeating(
          &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest,
          base::Unretained(this)));
  
      AndroidDeviceManager::DeviceProviders providers;
      providers.push_back(
          base::MakeRefCounted<UsbDeviceProvider>(browser()->profile()));
      adb_bridge_->set_device_providers_for_test(providers);
      runner_ = base::MakeRefCounted<content::MessageLoopRunner>();
  
      // Set a fake USB device manager for AndroidUsbDevice.
      usb_manager_ = CreateFakeUsbManager();
      DCHECK(usb_manager_);
      mojo::PendingRemote<device::mojom::UsbDeviceManager> manager;
      usb_manager_->AddReceiver(manager.InitWithNewPipeAndPassReceiver());
      adb_bridge_->set_usb_device_manager_for_test(std::move(manager));
    }
  
    void ScheduleDeviceCountRequest(base::OnceClosure request) {
      DCHECK_CURRENTLY_ON(BrowserThread::UI);
      scheduler_invoked_++;
      content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(request));
    }
  
    virtual std::unique_ptr<FakeUsbDeviceManager> CreateFakeUsbManager() {
      auto manager = std::make_unique<FakeAndroidUsbManager>();
      manager->AddDevice(ConstructFakeUsbDevice<AndroidTraits>());
      return manager;
    }
  
    scoped_refptr<content::MessageLoopRunner> runner_;
    std::unique_ptr<FakeUsbDeviceManager> usb_manager_;
    DevToolsAndroidBridge* adb_bridge_;
    int scheduler_invoked_ = 0;
  };
  
  class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
   protected:
    AndroidUsbCountTest() = default;
    ~AndroidUsbCountTest() override = default;
  
    void SetUpOnMainThread() override {
      AndroidUsbDiscoveryTest::SetUpOnMainThread();
      DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_);
      adb_bridge_->AddDeviceCountListener(&warmup);
      runner_->Run();
      runner_ = base::MakeRefCounted<content::MessageLoopRunner>();
    }
  };
  
  class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
   protected:
    AndroidUsbTraitsTest() = default;
    ~AndroidUsbTraitsTest() override = default;
  
    std::unique_ptr<FakeUsbDeviceManager> CreateFakeUsbManager() override {
      return std::make_unique<FakeUsbManagerForCheckingTraits>();
    }
  };
  
  class AndroidBreakingUsbTest : public AndroidUsbDiscoveryTest {
   protected:
    AndroidBreakingUsbTest() = default;
    ~AndroidBreakingUsbTest() override = default;
  
    std::unique_ptr<FakeUsbDeviceManager> CreateFakeUsbManager() override {
      auto manager = std::make_unique<FakeAndroidUsbManager>();
      manager->AddDevice(ConstructFakeUsbDevice<BreakingAndroidTraits>());
      return manager;
    }
  };
  
  class AndroidNoConfigUsbTest : public AndroidUsbDiscoveryTest {
   protected:
    AndroidNoConfigUsbTest() = default;
    ~AndroidNoConfigUsbTest() override = default;
  
    std::unique_ptr<FakeUsbDeviceManager> CreateFakeUsbManager() override {
      auto manager = std::make_unique<FakeAndroidUsbManager>();
      manager->AddDevice(ConstructFakeUsbDevice<AndroidTraits>());
      manager->AddDevice(ConstructFakeUsbDevice<NoConfigTraits>());
      return manager;
    }
  };
  
  class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
   public:
    MockListListener(DevToolsAndroidBridge* adb_bridge,
                     base::OnceClosure callback)
        : adb_bridge_(adb_bridge), callback_(std::move(callback)) {}
    ~MockListListener() override = default;
  
    void DeviceListChanged(
        const DevToolsAndroidBridge::RemoteDevices& devices) override {
      for (const auto& device : devices) {
        if (device->is_connected()) {
          ASSERT_EQ(kDeviceModel, device->model());
          ASSERT_EQ(kDeviceSerial, device->serial());
          adb_bridge_->RemoveDeviceListListener(this);
          std::move(callback_).Run();
          break;
        }
      }
    }
  
    DevToolsAndroidBridge* adb_bridge_;
    base::OnceClosure callback_;
  };
  
  class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
   public:
    explicit MockCountListener(DevToolsAndroidBridge* adb_bridge)
        : adb_bridge_(adb_bridge) {}
    ~MockCountListener() override = default;
  
    void DeviceCountChanged(int count) override {
      ++invoked_;
      adb_bridge_->RemoveDeviceCountListener(this);
      Shutdown();
    }
  
    void Shutdown() { base::RunLoop::QuitCurrentWhenIdleDeprecated(); }
  
    DevToolsAndroidBridge* adb_bridge_;
    int invoked_ = 0;
  };
  
  class MockCountListenerWithReAdd : public MockCountListener {
   public:
    explicit MockCountListenerWithReAdd(DevToolsAndroidBridge* adb_bridge)
        : MockCountListener(adb_bridge) {}
    ~MockCountListenerWithReAdd() override = default;
  
    void DeviceCountChanged(int count) override {
      ++invoked_;
      adb_bridge_->RemoveDeviceCountListener(this);
      if (readd_count_ > 0) {
        readd_count_--;
        adb_bridge_->AddDeviceCountListener(this);
        adb_bridge_->RemoveDeviceCountListener(this);
        adb_bridge_->AddDeviceCountListener(this);
      } else {
        Shutdown();
      }
    }
  
    int readd_count_ = 2;
  };
  
  class MockCountListenerWithReAddWhileQueued : public MockCountListener {
   public:
    explicit MockCountListenerWithReAddWhileQueued(
        DevToolsAndroidBridge* adb_bridge)
        : MockCountListener(adb_bridge) {}
    ~MockCountListenerWithReAddWhileQueued() override = default;
  
    void DeviceCountChanged(int count) override {
      ++invoked_;
      if (!readded_) {
        readded_ = true;
        base::ThreadTaskRunnerHandle::Get()->PostTask(
            FROM_HERE,
            base::BindOnce(&MockCountListenerWithReAddWhileQueued::ReAdd,
                           base::Unretained(this)));
      } else {
        adb_bridge_->RemoveDeviceCountListener(this);
        Shutdown();
      }
    }
  
    void ReAdd() {
      adb_bridge_->RemoveDeviceCountListener(this);
      adb_bridge_->AddDeviceCountListener(this);
    }
  
    bool readded_ = false;
  };
  
  class MockCountListenerForCheckingTraits : public MockCountListener {
   public:
    explicit MockCountListenerForCheckingTraits(DevToolsAndroidBridge* adb_bridge)
        : MockCountListener(adb_bridge) {}
    ~MockCountListenerForCheckingTraits() override = default;
  
    void DeviceCountChanged(int count) override {
      switch (step_) {
        case 0:
          // Check for 0 devices when no devices present.
          EXPECT_EQ(0, count);
          break;
        case 1:
          // Check for 1 device when only android device present.
          EXPECT_EQ(1, count);
          break;
        case 2:
          // Check for 1 device when android and non-android devices present.
          EXPECT_EQ(1, count);
          break;
        case 3:
          // Check for 0 devices when only non-android devices present.
          EXPECT_EQ(0, count);
          adb_bridge_->RemoveDeviceCountListener(this);
          Shutdown();
          break;
        default:
          EXPECT_TRUE(false) << "Unknown step " << step_;
      }
      step_++;
    }
  
    int step_ = 0;
  };
  
  }  // namespace
  
  IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
    MockListListener listener(adb_bridge_, runner_->QuitClosure());
    adb_bridge_->AddDeviceListListener(&listener);
    runner_->Run();
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidBreakingUsbTest, TestDeviceBreaking) {
    MockListListener listener(adb_bridge_, runner_->QuitClosure());
    adb_bridge_->AddDeviceListListener(&listener);
    runner_->Run();
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidNoConfigUsbTest, TestDeviceNoConfig) {
    MockListListener listener(adb_bridge_, runner_->QuitClosure());
    adb_bridge_->AddDeviceListListener(&listener);
    runner_->Run();
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
                         TestNoMultipleCallsRemoveInCallback) {
    MockCountListener listener(adb_bridge_);
    adb_bridge_->AddDeviceCountListener(&listener);
    runner_->Run();
    EXPECT_EQ(1, listener.invoked_);
    EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
                         TestNoMultipleCallsRemoveAddInCallback) {
    MockCountListenerWithReAdd listener(adb_bridge_);
    adb_bridge_->AddDeviceCountListener(&listener);
    runner_->Run();
    EXPECT_EQ(3, listener.invoked_);
    EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
                         TestNoMultipleCallsRemoveAddOnStart) {
    MockCountListener listener(adb_bridge_);
    adb_bridge_->AddDeviceCountListener(&listener);
    adb_bridge_->RemoveDeviceCountListener(&listener);
    adb_bridge_->AddDeviceCountListener(&listener);
    runner_->Run();
    EXPECT_EQ(1, listener.invoked_);
    EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
                         TestNoMultipleCallsRemoveAddWhileQueued) {
    MockCountListenerWithReAddWhileQueued listener(adb_bridge_);
    adb_bridge_->AddDeviceCountListener(&listener);
    runner_->Run();
    EXPECT_EQ(2, listener.invoked_);
    EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
  }
  
  IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
    MockCountListenerForCheckingTraits listener(adb_bridge_);
    adb_bridge_->AddDeviceCountListener(&listener);
    runner_->Run();
  }
  