summaryrefslogtreecommitdiffstats
path: root/device/usb/mojo/device_manager_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'device/usb/mojo/device_manager_impl.cc')
-rw-r--r--device/usb/mojo/device_manager_impl.cc228
1 files changed, 228 insertions, 0 deletions
diff --git a/device/usb/mojo/device_manager_impl.cc b/device/usb/mojo/device_manager_impl.cc
new file mode 100644
index 0000000..fdb4d5c
--- /dev/null
+++ b/device/usb/mojo/device_manager_impl.cc
@@ -0,0 +1,228 @@
+// Copyright 2015 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 "device/usb/mojo/device_manager_impl.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "device/core/device_client.h"
+#include "device/usb/mojo/device_impl.h"
+#include "device/usb/mojo/type_converters.h"
+#include "device/usb/public/interfaces/device.mojom.h"
+#include "device/usb/usb_device.h"
+#include "device/usb/usb_device_filter.h"
+#include "device/usb/usb_service.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+
+namespace device {
+namespace usb {
+
+namespace {
+
+using DeviceList = DeviceManagerImpl::DeviceList;
+using DeviceMap = DeviceManagerImpl::DeviceMap;
+
+void FilterAndConvertDevicesAndThen(
+ const DeviceMap& devices,
+ const DeviceManagerImpl::GetDevicesCallback& callback,
+ mojo::Array<mojo::String> allowed_guids) {
+ mojo::Array<DeviceInfoPtr> allowed_devices(allowed_guids.size());
+ for (size_t i = 0; i < allowed_guids.size(); ++i) {
+ const auto it = devices.find(allowed_guids[i]);
+ DCHECK(it != devices.end());
+ allowed_devices[i] = DeviceInfo::From(*it->second);
+ }
+
+ callback.Run(std::move(allowed_devices));
+}
+
+} // namespace
+
+// static
+void DeviceManagerImpl::Create(PermissionProviderPtr permission_provider,
+ mojo::InterfaceRequest<DeviceManager> request) {
+ // The created object is owned by its binding.
+ new DeviceManagerImpl(std::move(permission_provider), std::move(request));
+}
+
+DeviceManagerImpl::DeviceManagerImpl(
+ PermissionProviderPtr permission_provider,
+ mojo::InterfaceRequest<DeviceManager> request)
+ : permission_provider_(std::move(permission_provider)),
+ observer_(this),
+ binding_(this, std::move(request)),
+ weak_factory_(this) {
+ // This object owns itself and will be destroyed if either the message pipe
+ // it is bound to is closed or the PermissionProvider it depends on is
+ // unavailable.
+ binding_.set_connection_error_handler([this]() { delete this; });
+ permission_provider_.set_connection_error_handler([this]() { delete this; });
+
+ DCHECK(DeviceClient::Get());
+ usb_service_ = DeviceClient::Get()->GetUsbService();
+ if (usb_service_)
+ observer_.Add(usb_service_);
+}
+
+DeviceManagerImpl::~DeviceManagerImpl() {
+ connection_error_handler_.Run();
+}
+
+void DeviceManagerImpl::GetDevices(EnumerationOptionsPtr options,
+ const GetDevicesCallback& callback) {
+ if (!usb_service_) {
+ mojo::Array<DeviceInfoPtr> no_devices;
+ callback.Run(std::move(no_devices));
+ return;
+ }
+
+ usb_service_->GetDevices(base::Bind(&DeviceManagerImpl::OnGetDevices,
+ weak_factory_.GetWeakPtr(),
+ base::Passed(&options), callback));
+}
+
+void DeviceManagerImpl::GetDeviceChanges(
+ const GetDeviceChangesCallback& callback) {
+ device_change_callbacks_.push(callback);
+ MaybeRunDeviceChangesCallback();
+}
+
+void DeviceManagerImpl::GetDevice(
+ const mojo::String& guid,
+ mojo::InterfaceRequest<Device> device_request) {
+ if (!usb_service_)
+ return;
+
+ scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
+ if (!device)
+ return;
+
+ mojo::Array<DeviceInfoPtr> requested_devices(1);
+ requested_devices[0] = DeviceInfo::From(*device);
+ permission_provider_->HasDevicePermission(
+ std::move(requested_devices),
+ base::Bind(&DeviceManagerImpl::OnGetDevicePermissionCheckComplete,
+ base::Unretained(this), device,
+ base::Passed(&device_request)));
+}
+
+void DeviceManagerImpl::OnGetDevicePermissionCheckComplete(
+ scoped_refptr<UsbDevice> device,
+ mojo::InterfaceRequest<Device> device_request,
+ mojo::Array<mojo::String> allowed_guids) {
+ if (allowed_guids.size() == 0)
+ return;
+
+ DCHECK(allowed_guids.size() == 1);
+ PermissionProviderPtr permission_provider;
+ permission_provider_->Bind(mojo::GetProxy(&permission_provider));
+ new DeviceImpl(device, std::move(permission_provider),
+ std::move(device_request));
+}
+
+void DeviceManagerImpl::OnGetDevices(EnumerationOptionsPtr options,
+ const GetDevicesCallback& callback,
+ const DeviceList& devices) {
+ std::vector<UsbDeviceFilter> filters;
+ if (options)
+ filters = options->filters.To<std::vector<UsbDeviceFilter>>();
+
+ std::map<std::string, scoped_refptr<UsbDevice>> device_map;
+ mojo::Array<DeviceInfoPtr> requested_devices(0);
+ for (const auto& device : devices) {
+ if (filters.empty() || UsbDeviceFilter::MatchesAny(device, filters)) {
+ device_map[device->guid()] = device;
+ requested_devices.push_back(DeviceInfo::From(*device));
+ }
+ }
+
+ permission_provider_->HasDevicePermission(
+ std::move(requested_devices),
+ base::Bind(&FilterAndConvertDevicesAndThen, device_map, callback));
+}
+
+void DeviceManagerImpl::OnDeviceAdded(scoped_refptr<UsbDevice> device) {
+ DCHECK(!ContainsKey(devices_removed_, device->guid()));
+ devices_added_[device->guid()] = device;
+ MaybeRunDeviceChangesCallback();
+}
+
+void DeviceManagerImpl::OnDeviceRemoved(scoped_refptr<UsbDevice> device) {
+ if (devices_added_.erase(device->guid()) == 0)
+ devices_removed_[device->guid()] = device;
+ MaybeRunDeviceChangesCallback();
+}
+
+void DeviceManagerImpl::WillDestroyUsbService() {
+ observer_.RemoveAll();
+ usb_service_ = nullptr;
+}
+
+void DeviceManagerImpl::MaybeRunDeviceChangesCallback() {
+ if (!permission_request_pending_ && !device_change_callbacks_.empty()) {
+ DeviceMap devices_added;
+ devices_added.swap(devices_added_);
+ DeviceMap devices_removed;
+ devices_removed.swap(devices_removed_);
+
+ mojo::Array<DeviceInfoPtr> requested_devices(devices_added.size() +
+ devices_removed.size());
+ {
+ size_t i = 0;
+ for (const auto& map_entry : devices_added)
+ requested_devices[i++] = DeviceInfo::From(*map_entry.second);
+ for (const auto& map_entry : devices_removed)
+ requested_devices[i++] = DeviceInfo::From(*map_entry.second);
+ }
+
+ permission_request_pending_ = true;
+ permission_provider_->HasDevicePermission(
+ std::move(requested_devices),
+ base::Bind(&DeviceManagerImpl::OnEnumerationPermissionCheckComplete,
+ base::Unretained(this), devices_added, devices_removed));
+ }
+}
+
+void DeviceManagerImpl::OnEnumerationPermissionCheckComplete(
+ const DeviceMap& devices_added,
+ const DeviceMap& devices_removed,
+ mojo::Array<mojo::String> allowed_guids) {
+ permission_request_pending_ = false;
+
+ if (allowed_guids.size() > 0) {
+ DeviceChangeNotificationPtr notification = DeviceChangeNotification::New();
+ notification->devices_added.resize(0);
+ notification->devices_removed.resize(0);
+
+ for (size_t i = 0; i < allowed_guids.size(); ++i) {
+ const mojo::String& guid = allowed_guids[i];
+ auto it = devices_added.find(guid);
+ if (it != devices_added.end()) {
+ DCHECK(!ContainsKey(devices_removed, guid));
+ notification->devices_added.push_back(DeviceInfo::From(*it->second));
+ } else {
+ it = devices_removed.find(guid);
+ DCHECK(it != devices_removed.end());
+ notification->devices_removed.push_back(DeviceInfo::From(*it->second));
+ }
+ }
+
+ DCHECK(!device_change_callbacks_.empty());
+ const GetDeviceChangesCallback& callback = device_change_callbacks_.front();
+ callback.Run(std::move(notification));
+ device_change_callbacks_.pop();
+ }
+
+ if (devices_added_.size() > 0 || !devices_removed_.empty())
+ MaybeRunDeviceChangesCallback();
+}
+
+} // namespace usb
+} // namespace device