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

#include "services/device/usb/mojo/device_manager_impl.h"

#include <stddef.h>

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "services/device/public/cpp/usb/usb_utils.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_client.mojom.h"
#include "services/device/usb/mojo/device_impl.h"
#include "services/device/usb/usb_device.h"
#include "services/device/usb/usb_service.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/dbus/permission_broker/permission_broker_client.h"  // nogncheck
#include "services/device/usb/usb_device_linux.h"
#endif  // BUILDFLAG(IS_CHROMEOS)

namespace device::usb {

DeviceManagerImpl::DeviceManagerImpl()
    : DeviceManagerImpl(UsbService::Create()) {}

DeviceManagerImpl::DeviceManagerImpl(std::unique_ptr<UsbService> usb_service)
    : usb_service_(std::move(usb_service)) {
  if (usb_service_)
    observation_.Observe(usb_service_.get());
}

DeviceManagerImpl::~DeviceManagerImpl() = default;

void DeviceManagerImpl::AddReceiver(
    mojo::PendingReceiver<mojom::UsbDeviceManager> receiver) {
  if (usb_service_)
    receivers_.Add(this, std::move(receiver));
}

void DeviceManagerImpl::EnumerateDevicesAndSetClient(
    mojo::PendingAssociatedRemote<mojom::UsbDeviceManagerClient> client,
    EnumerateDevicesAndSetClientCallback callback) {
  usb_service_->GetDevices(base::BindOnce(
      &DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(),
      /*options=*/nullptr, std::move(client), std::move(callback)));
}

void DeviceManagerImpl::GetDevices(mojom::UsbEnumerationOptionsPtr options,
                                   GetDevicesCallback callback) {
  usb_service_->GetDevices(base::BindOnce(
      &DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(),
      std::move(options), mojo::NullAssociatedRemote(), std::move(callback)));
}

void DeviceManagerImpl::GetDevice(
    const std::string& guid,
    const std::vector<uint8_t>& blocked_interface_classes,
    mojo::PendingReceiver<mojom::UsbDevice> device_receiver,
    mojo::PendingRemote<mojom::UsbDeviceClient> device_client) {
  return GetDeviceInternal(guid, std::move(device_receiver),
                           std::move(device_client), blocked_interface_classes,
                           /*allow_security_key_requests=*/false);
}

void DeviceManagerImpl::GetSecurityKeyDevice(
    const std::string& guid,
    mojo::PendingReceiver<mojom::UsbDevice> device_receiver,
    mojo::PendingRemote<mojom::UsbDeviceClient> device_client) {
  return GetDeviceInternal(guid, std::move(device_receiver),
                           std::move(device_client),
                           /*blocked_interface_classes=*/{},
                           /*allow_security_key_requests=*/true);
}

#if BUILDFLAG(IS_ANDROID)
void DeviceManagerImpl::RefreshDeviceInfo(const std::string& guid,
                                          RefreshDeviceInfoCallback callback) {
  scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
  if (!device) {
    std::move(callback).Run(nullptr);
    return;
  }

  if (device->permission_granted()) {
    std::move(callback).Run(device->device_info().Clone());
    return;
  }

  device->RequestPermission(
      base::BindOnce(&DeviceManagerImpl::OnPermissionGrantedToRefresh,
                     weak_factory_.GetWeakPtr(), device, std::move(callback)));
}

void DeviceManagerImpl::OnPermissionGrantedToRefresh(
    scoped_refptr<UsbDevice> device,
    RefreshDeviceInfoCallback callback,
    bool granted) {
  DCHECK_EQ(granted, device->permission_granted());
  if (!device->permission_granted()) {
    std::move(callback).Run(nullptr);
    return;
  }

  std::move(callback).Run(device->device_info().Clone());
}
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_CHROMEOS)
void DeviceManagerImpl::CheckAccess(const std::string& guid,
                                    CheckAccessCallback callback) {
  scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
  if (device) {
    device->CheckUsbAccess(std::move(callback));
  } else {
    LOG(ERROR) << "Was asked to check access to non-existent USB device: "
               << guid;
    std::move(callback).Run(false);
  }
}

void DeviceManagerImpl::OpenFileDescriptor(
    const std::string& guid,
    uint32_t drop_privileges_mask,
    mojo::PlatformHandle lifeline_fd,
    OpenFileDescriptorCallback callback) {
  scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
  if (!device) {
    LOG(ERROR) << "Was asked to open non-existent USB device: " << guid;
    std::move(callback).Run(base::File());
  } else {
    auto split_callback = base::SplitOnceCallback(std::move(callback));
    auto devpath =
        static_cast<device::UsbDeviceLinux*>(device.get())->device_path();

    // The |lifeline_fd| passed through D-Bus gets is duped, so we need to close
    // our original.
    chromeos::PermissionBrokerClient::Get()->ClaimDevicePath(
        devpath, drop_privileges_mask, lifeline_fd.GetFD().get(),
        base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptor,
                       weak_factory_.GetWeakPtr(),
                       std::move(split_callback.first)),
        base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptorError,
                       weak_factory_.GetWeakPtr(),
                       std::move(split_callback.second)));
  }
}

void DeviceManagerImpl::OnOpenFileDescriptor(
    OpenFileDescriptorCallback callback,
    base::ScopedFD fd) {
  std::move(callback).Run(base::File(std::move(fd)));
}

void DeviceManagerImpl::OnOpenFileDescriptorError(
    OpenFileDescriptorCallback callback,
    const std::string& error_name,
    const std::string& message) {
  LOG(ERROR) << "Failed to open USB device file: " << error_name << " "
             << message;
  std::move(callback).Run(base::File());
}
#endif  // BUILDFLAG(IS_CHROMEOS)

void DeviceManagerImpl::SetClient(
    mojo::PendingAssociatedRemote<mojom::UsbDeviceManagerClient> client) {
  DCHECK(client);
  clients_.Add(std::move(client));
}

void DeviceManagerImpl::OnGetDevices(
    mojom::UsbEnumerationOptionsPtr options,
    mojo::PendingAssociatedRemote<mojom::UsbDeviceManagerClient> client,
    GetDevicesCallback callback,
    const std::vector<scoped_refptr<UsbDevice>>& devices) {
  std::vector<mojom::UsbDeviceFilterPtr> filters;
  if (options)
    filters.swap(options->filters);

  std::vector<mojom::UsbDeviceInfoPtr> device_infos;
  for (const auto& device : devices) {
    if (UsbDeviceFilterMatchesAny(filters, device->device_info())) {
      device_infos.push_back(device->device_info().Clone());
    }
  }

  std::move(callback).Run(std::move(device_infos));

  if (client)
    SetClient(std::move(client));
}

void DeviceManagerImpl::OnDeviceAdded(scoped_refptr<UsbDevice> device) {
  for (auto& client : clients_)
    client->OnDeviceAdded(device->device_info().Clone());
}

void DeviceManagerImpl::OnDeviceRemoved(scoped_refptr<UsbDevice> device) {
  for (auto& client : clients_)
    client->OnDeviceRemoved(device->device_info().Clone());
}

void DeviceManagerImpl::WillDestroyUsbService() {
  observation_.Reset();
  usb_service_ = nullptr;

  // Close all the connections.
  receivers_.Clear();
  clients_.Clear();
}

void DeviceManagerImpl::GetDeviceInternal(
    const std::string& guid,
    mojo::PendingReceiver<mojom::UsbDevice> device_receiver,
    mojo::PendingRemote<mojom::UsbDeviceClient> device_client,
    base::span<const uint8_t> blocked_interface_classes,
    bool allow_security_key_requests) {
  scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
  if (!device)
    return;

  DeviceImpl::Create(std::move(device), std::move(device_receiver),
                     std::move(device_client), blocked_interface_classes,
                     allow_security_key_requests);
}

}  // namespace device::usb