blob: 36dba7e12ddd1b4d9dce37fdfc7718089da94de9 [file] [log] [blame]
Donna Wu2fd87fc92018-07-27 01:32:191// Copyright 2018 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
Donna Wu838ac362018-08-10 10:36:335#include "chrome/browser/usb/web_usb_service_impl.h"
Donna Wu2fd87fc92018-07-27 01:32:196
7#include <utility>
8
9#include "base/bind.h"
Donna Wu50fe6b22018-08-30 06:27:4310#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/usb/usb_blocklist.h"
Donna Wu50fe6b22018-08-30 06:27:4312#include "chrome/browser/usb/usb_chooser_context_factory.h"
13#include "chrome/browser/usb/usb_tab_helper.h"
14#include "content/public/browser/browser_thread.h"
Donna Wu2fd87fc92018-07-27 01:32:1915#include "device/usb/mojo/type_converters.h"
Donna Wu2fd87fc92018-07-27 01:32:1916
Donna Wu838ac362018-08-10 10:36:3317WebUsbServiceImpl::WebUsbServiceImpl(
Donna Wu50fe6b22018-08-30 06:27:4318 content::RenderFrameHost* render_frame_host,
Donna Wuc98e12a2018-08-16 07:24:0219 base::WeakPtr<WebUsbChooser> usb_chooser)
Donna Wu50fe6b22018-08-30 06:27:4320 : render_frame_host_(render_frame_host),
Donna Wuc98e12a2018-08-16 07:24:0221 usb_chooser_(std::move(usb_chooser)),
Donna Wu2fd87fc92018-07-27 01:32:1922 observer_(this),
23 weak_factory_(this) {
Donna Wu35c12ea2018-09-20 06:08:1824 DCHECK(render_frame_host_);
25 content::WebContents* web_contents =
26 content::WebContents::FromRenderFrameHost(render_frame_host_);
27 Profile* profile =
28 Profile::FromBrowserContext(web_contents->GetBrowserContext());
29 chooser_context_ = UsbChooserContextFactory::GetForProfile(profile);
30 DCHECK(chooser_context_);
Donna Wu50fe6b22018-08-30 06:27:4331
32 bindings_.set_connection_error_handler(base::BindRepeating(
33 &WebUsbServiceImpl::OnBindingConnectionError, base::Unretained(this)));
34}
35
36WebUsbServiceImpl::~WebUsbServiceImpl() = default;
37
38void WebUsbServiceImpl::BindRequest(
39 blink::mojom::WebUsbServiceRequest request) {
40 bindings_.AddBinding(this, std::move(request));
41
Donna Wu35c12ea2018-09-20 06:08:1842 // Listen to UsbChooserContext for add/remove device events from UsbService.
Donna Wu838ac362018-08-10 10:36:3343 // We can't set WebUsbServiceImpl as a UsbDeviceManagerClient because
Donna Wu2fd87fc92018-07-27 01:32:1944 // the OnDeviceRemoved event will be delivered here after it is delivered
45 // to UsbChooserContext, meaning that all ephemeral permission checks in
46 // OnDeviceRemoved() will fail.
Donna Wu35c12ea2018-09-20 06:08:1847 if (!observer_.IsObservingSources())
48 observer_.Add(chooser_context_);
Donna Wu2fd87fc92018-07-27 01:32:1949}
50
Donna Wu50fe6b22018-08-30 06:27:4351bool WebUsbServiceImpl::HasDevicePermission(
52 const device::mojom::UsbDeviceInfo& device_info) const {
53 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
54 DCHECK(render_frame_host_);
Donna Wu35c12ea2018-09-20 06:08:1855 if (!chooser_context_)
56 return false;
Donna Wu50fe6b22018-08-30 06:27:4357
58 content::WebContents* web_contents =
59 content::WebContents::FromRenderFrameHost(render_frame_host_);
60 content::RenderFrameHost* main_frame = web_contents->GetMainFrame();
Donna Wu50fe6b22018-08-30 06:27:4361
Donna Wu35c12ea2018-09-20 06:08:1862 return chooser_context_->HasDevicePermission(
Donna Wu50fe6b22018-08-30 06:27:4363 render_frame_host_->GetLastCommittedURL().GetOrigin(),
64 main_frame->GetLastCommittedURL().GetOrigin(), device_info);
65}
Donna Wu2fd87fc92018-07-27 01:32:1966
Donna Wu838ac362018-08-10 10:36:3367void WebUsbServiceImpl::GetDevices(GetDevicesCallback callback) {
Donna Wu35c12ea2018-09-20 06:08:1868 if (!chooser_context_)
69 std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
70
71 chooser_context_->GetDevices(base::BindOnce(&WebUsbServiceImpl::OnGetDevices,
72 weak_factory_.GetWeakPtr(),
73 std::move(callback)));
Donna Wucaa44de2018-08-17 06:42:3974}
75
76void WebUsbServiceImpl::OnGetDevices(
77 GetDevicesCallback callback,
78 std::vector<device::mojom::UsbDeviceInfoPtr> device_info_list) {
79 std::vector<device::mojom::UsbDeviceInfoPtr> device_infos;
80 for (auto& device_info : device_info_list) {
Donna Wu50fe6b22018-08-30 06:27:4381 if (HasDevicePermission(*device_info))
Donna Wucaa44de2018-08-17 06:42:3982 device_infos.push_back(device_info.Clone());
Donna Wucaa44de2018-08-17 06:42:3983 }
84 std::move(callback).Run(std::move(device_infos));
Donna Wu2fd87fc92018-07-27 01:32:1985}
86
Donna Wu838ac362018-08-10 10:36:3387void WebUsbServiceImpl::GetDevice(
Donna Wu2fd87fc92018-07-27 01:32:1988 const std::string& guid,
89 device::mojom::UsbDeviceRequest device_request) {
Donna Wu35c12ea2018-09-20 06:08:1890 if (!chooser_context_)
91 return;
92
Donna Wu656439c2018-08-13 09:31:1693 // Try to bind with the new device to be created for DeviceOpened/Closed
Donna Wu35c12ea2018-09-20 06:08:1894 // events. It is safe to pass this request directly to UsbDeviceManager
Donna Wucaa44de2018-08-17 06:42:3995 // because |guid| is unguessable.
Donna Wu656439c2018-08-13 09:31:1696 device::mojom::UsbDeviceClientPtr device_client;
97 device_client_bindings_.AddBinding(this, mojo::MakeRequest(&device_client));
Donna Wu35c12ea2018-09-20 06:08:1898 chooser_context_->GetDevice(guid, std::move(device_request),
99 std::move(device_client));
Donna Wu2fd87fc92018-07-27 01:32:19100}
101
Donna Wuc98e12a2018-08-16 07:24:02102void WebUsbServiceImpl::GetPermission(
103 std::vector<device::mojom::UsbDeviceFilterPtr> device_filters,
104 GetPermissionCallback callback) {
105 if (!usb_chooser_)
106 std::move(callback).Run(nullptr);
107
108 usb_chooser_->GetPermission(std::move(device_filters), std::move(callback));
109}
110
Donna Wu838ac362018-08-10 10:36:33111void WebUsbServiceImpl::SetClient(
Donna Wu7205a852018-09-20 04:21:13112 device::mojom::UsbDeviceManagerClientAssociatedPtrInfo client) {
113 DCHECK(client);
114
115 device::mojom::UsbDeviceManagerClientAssociatedPtr client_ptr;
116 client_ptr.Bind(std::move(client));
117 clients_.AddPtr(std::move(client_ptr));
Donna Wu2fd87fc92018-07-27 01:32:19118}
119
Donna Wu35c12ea2018-09-20 06:08:18120void WebUsbServiceImpl::OnDeviceAdded(
121 device::mojom::UsbDeviceInfoPtr device_info) {
Donna Wucaa44de2018-08-17 06:42:39122 DCHECK(device_info);
Donna Wu50fe6b22018-08-30 06:27:43123 if (!HasDevicePermission(*device_info))
124 return;
125
126 clients_.ForAllPtrs(
127 [&device_info](device::mojom::UsbDeviceManagerClient* client) {
128 client->OnDeviceAdded(device_info->Clone());
129 });
Donna Wu2fd87fc92018-07-27 01:32:19130}
131
Donna Wu838ac362018-08-10 10:36:33132void WebUsbServiceImpl::OnDeviceRemoved(
Donna Wu35c12ea2018-09-20 06:08:18133 device::mojom::UsbDeviceInfoPtr device_info) {
Donna Wucaa44de2018-08-17 06:42:39134 DCHECK(device_info);
Donna Wu50fe6b22018-08-30 06:27:43135 if (!HasDevicePermission(*device_info))
136 return;
137
138 clients_.ForAllPtrs(
139 [&device_info](device::mojom::UsbDeviceManagerClient* client) {
140 client->OnDeviceRemoved(device_info->Clone());
141 });
Donna Wu2fd87fc92018-07-27 01:32:19142}
143
Donna Wu35c12ea2018-09-20 06:08:18144void WebUsbServiceImpl::OnDeviceManagerConnectionError() {
145 // Close the connection with blink.
146 clients_.CloseAll();
147 bindings_.CloseAllBindings();
148
149 // Remove itself from UsbChooserContext's ObserverList.
150 observer_.RemoveAll();
151}
152
Donna Wu656439c2018-08-13 09:31:16153// device::mojom::UsbDeviceClient implementation:
154void WebUsbServiceImpl::OnDeviceOpened() {
Donna Wu50fe6b22018-08-30 06:27:43155 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
156 content::WebContents* web_contents =
157 content::WebContents::FromRenderFrameHost(render_frame_host_);
158 UsbTabHelper* tab_helper = UsbTabHelper::FromWebContents(web_contents);
159 tab_helper->IncrementConnectionCount(render_frame_host_);
Donna Wu656439c2018-08-13 09:31:16160}
161
162void WebUsbServiceImpl::OnDeviceClosed() {
Donna Wu50fe6b22018-08-30 06:27:43163 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
164 content::WebContents* web_contents =
165 content::WebContents::FromRenderFrameHost(render_frame_host_);
166 UsbTabHelper* tab_helper = UsbTabHelper::FromWebContents(web_contents);
167 tab_helper->DecrementConnectionCount(render_frame_host_);
Donna Wu656439c2018-08-13 09:31:16168}
169
Donna Wu50fe6b22018-08-30 06:27:43170void WebUsbServiceImpl::OnBindingConnectionError() {
171 if (bindings_.empty())
172 observer_.RemoveAll();
Donna Wu2fd87fc92018-07-27 01:32:19173}