910e62b5创建于 1月15日历史提交
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_API_USB_USB_DEVICE_MANAGER_H_
#define EXTENSIONS_BROWSER_API_USB_USB_DEVICE_MANAGER_H_

#include <map>
#include <string>
#include <vector>

#include "base/containers/queue.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "build/build_config.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/event_router.h"
#include "extensions/common/api/usb.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/usb_manager.mojom.h"
#include "services/device/public/mojom/usb_manager_client.mojom.h"

namespace extensions {

// A BrowserContext-scoped object which is registered as an observer of the
// EventRouter and UsbDeviceManager in order to manage the connection to the
// Device Service and generate device add/remove events.
class UsbDeviceManager : public BrowserContextKeyedAPI,
                         public EventRouter::Observer,
                         public device::mojom::UsbDeviceManagerClient {
 public:
  explicit UsbDeviceManager(content::BrowserContext* context);
  ~UsbDeviceManager() override;
  UsbDeviceManager(const UsbDeviceManager&) = delete;
  UsbDeviceManager& operator=(const UsbDeviceManager&) = delete;

  static UsbDeviceManager* Get(content::BrowserContext* browser_context);

  // BrowserContextKeyedAPI implementation.
  static BrowserContextKeyedAPIFactory<UsbDeviceManager>* GetFactoryInstance();

  class Observer : public base::CheckedObserver {
   public:
    virtual void OnDeviceAdded(const device::mojom::UsbDeviceInfo&);
    virtual void OnDeviceRemoved(const device::mojom::UsbDeviceInfo&);
    virtual void OnDeviceManagerConnectionError();
  };

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // Returns an ID for this device GUID. If the GUID is unknown to the
  // UsbGuidMap a new ID is generated for it.
  int GetIdFromGuid(const std::string& guid);

  // Looks up a device GUID for a given extensions USB device ID. If the ID is
  // unknown (e.g., the corresponding device was unplugged), this returns
  // `false`; otherwise it returns `true`.
  bool GetGuidFromId(int id, std::string* guid);

  // Populates an instance of the chrome.usb.Device object from the given
  // device.
  void GetApiDevice(const device::mojom::UsbDeviceInfo& device_in,
                    api::usb::Device* device_out);

  // Forward UsbDeviceManager methods.
  void GetDevices(device::mojom::UsbDeviceManager::GetDevicesCallback callback);
  void GetDevice(
      const std::string& guid,
      mojo::PendingReceiver<device::mojom::UsbDevice> device_receiver);

  const device::mojom::UsbDeviceInfo* GetDeviceInfo(const std::string& guid);
  bool UpdateActiveConfig(const std::string& guid, uint8_t config_value);

#if BUILDFLAG(IS_CHROMEOS)
  void CheckAccess(
      const std::string& guid,
      device::mojom::UsbDeviceManager::CheckAccessCallback callback);
#endif  // BUILDFLAG(IS_CHROMEOS)

  void EnsureConnectionWithDeviceManager();

  void SetDeviceManagerForTesting(
      mojo::PendingRemote<device::mojom::UsbDeviceManager> fake_device_manager);

 private:
  friend class BrowserContextKeyedAPIFactory<UsbDeviceManager>;

  // BrowserContextKeyedAPI implementation.
  static const char* service_name() { return "UsbDeviceManager"; }
  static const bool kServiceHasOwnInstanceInIncognito = true;

  // KeyedService implementation.
  void Shutdown() override;

  // EventRouter::Observer implementation.
  void OnListenerAdded(const EventListenerInfo& details) override;

  // UsbService::Observer implementation.
  void OnDeviceAdded(device::mojom::UsbDeviceInfoPtr device_info) override;
  void OnDeviceRemoved(device::mojom::UsbDeviceInfoPtr device_info) override;

  void SetUpDeviceManagerConnection();
  void InitDeviceList(std::vector<device::mojom::UsbDeviceInfoPtr> devices);
  void OnDeviceManagerConnectionError();

  // Broadcasts a device add or remove event for the given device.
  void DispatchEvent(const std::string& event_name,
                     const device::mojom::UsbDeviceInfo& device_info);

  const raw_ptr<content::BrowserContext> browser_context_;

  // Legacy integer IDs are used in USB extensions API so we need to maps USB
  // device GUIDs to integer IDs.
  int next_id_ = 0;
  std::map<std::string, int> guid_to_id_map_;
  std::map<int, std::string> id_to_guid_map_;

  bool is_initialized_ = false;
  base::queue<device::mojom::UsbDeviceManager::GetDevicesCallback>
      pending_get_devices_requests_;
  std::map<std::string, device::mojom::UsbDeviceInfoPtr> devices_;

  // Connection to `device_manager_instance_`.
  mojo::Remote<device::mojom::UsbDeviceManager> device_manager_;
  mojo::AssociatedReceiver<device::mojom::UsbDeviceManagerClient>
      client_receiver_{this};

  base::ObserverList<Observer> observer_list_;

  base::WeakPtrFactory<UsbDeviceManager> weak_factory_{this};
};

template <>
void BrowserContextKeyedAPIFactory<
    UsbDeviceManager>::DeclareFactoryDependencies();

}  // namespace extensions

#endif  // EXTENSIONS_BROWSER_API_USB_USB_DEVICE_MANAGER_H_