blob: 586a6c6f2b638ab48c448946c2488f281c05ddb9 [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
Donna Wuc7029872018-11-02 09:47:057#include <memory>
Donna Wu2fd87fc92018-07-27 01:32:198#include <utility>
9
10#include "base/bind.h"
Donna Wuc7029872018-11-02 09:47:0511#include "base/stl_util.h"
Donna Wu50fe6b22018-08-30 06:27:4312#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/usb/usb_blocklist.h"
Donna Wu50fe6b22018-08-30 06:27:4314#include "chrome/browser/usb/usb_chooser_context_factory.h"
15#include "chrome/browser/usb/usb_tab_helper.h"
16#include "content/public/browser/browser_thread.h"
Takuto Ikutaa6629ba62019-01-30 23:31:4117#include "device/usb/public/mojom/device_enumeration_options.mojom.h"
18#include "media/mojo/interfaces/remoting_common.mojom.h"
Donna Wu2fd87fc92018-07-27 01:32:1919
Donna Wu838ac362018-08-10 10:36:3320WebUsbServiceImpl::WebUsbServiceImpl(
Donna Wu50fe6b22018-08-30 06:27:4321 content::RenderFrameHost* render_frame_host,
Donna Wuc98e12a2018-08-16 07:24:0222 base::WeakPtr<WebUsbChooser> usb_chooser)
Donna Wu50fe6b22018-08-30 06:27:4323 : render_frame_host_(render_frame_host),
Donna Wuc98e12a2018-08-16 07:24:0224 usb_chooser_(std::move(usb_chooser)),
Ovidio Henriquez8b39653b2019-01-18 18:56:5325 device_observer_(this),
26 permission_observer_(this),
Donna Wu2fd87fc92018-07-27 01:32:1927 weak_factory_(this) {
Donna Wu35c12ea2018-09-20 06:08:1828 DCHECK(render_frame_host_);
29 content::WebContents* web_contents =
30 content::WebContents::FromRenderFrameHost(render_frame_host_);
Donna Wuc7029872018-11-02 09:47:0531 // This class is destroyed on cross-origin navigations and so it is safe to
32 // cache these values.
33 requesting_origin_ = render_frame_host_->GetLastCommittedURL().GetOrigin();
34 embedding_origin_ =
35 web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin();
Donna Wu35c12ea2018-09-20 06:08:1836 Profile* profile =
37 Profile::FromBrowserContext(web_contents->GetBrowserContext());
38 chooser_context_ = UsbChooserContextFactory::GetForProfile(profile);
39 DCHECK(chooser_context_);
Donna Wu50fe6b22018-08-30 06:27:4340
41 bindings_.set_connection_error_handler(base::BindRepeating(
42 &WebUsbServiceImpl::OnBindingConnectionError, base::Unretained(this)));
43}
44
45WebUsbServiceImpl::~WebUsbServiceImpl() = default;
46
47void WebUsbServiceImpl::BindRequest(
48 blink::mojom::WebUsbServiceRequest request) {
49 bindings_.AddBinding(this, std::move(request));
50
Donna Wu35c12ea2018-09-20 06:08:1851 // Listen to UsbChooserContext for add/remove device events from UsbService.
Donna Wu838ac362018-08-10 10:36:3352 // We can't set WebUsbServiceImpl as a UsbDeviceManagerClient because
Donna Wu2fd87fc92018-07-27 01:32:1953 // the OnDeviceRemoved event will be delivered here after it is delivered
54 // to UsbChooserContext, meaning that all ephemeral permission checks in
55 // OnDeviceRemoved() will fail.
Ovidio Henriquez8b39653b2019-01-18 18:56:5356 if (!device_observer_.IsObservingSources())
57 device_observer_.Add(chooser_context_);
58 if (!permission_observer_.IsObservingSources())
59 permission_observer_.Add(chooser_context_);
Donna Wu2fd87fc92018-07-27 01:32:1960}
61
Donna Wu50fe6b22018-08-30 06:27:4362bool WebUsbServiceImpl::HasDevicePermission(
63 const device::mojom::UsbDeviceInfo& device_info) const {
64 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
65 DCHECK(render_frame_host_);
Donna Wu35c12ea2018-09-20 06:08:1866 if (!chooser_context_)
67 return false;
Donna Wu50fe6b22018-08-30 06:27:4368
Donna Wuc7029872018-11-02 09:47:0569 return chooser_context_->HasDevicePermission(requesting_origin_,
70 embedding_origin_, device_info);
Donna Wu50fe6b22018-08-30 06:27:4371}
Donna Wu2fd87fc92018-07-27 01:32:1972
Donna Wu838ac362018-08-10 10:36:3373void WebUsbServiceImpl::GetDevices(GetDevicesCallback callback) {
Donna Wu35c12ea2018-09-20 06:08:1874 if (!chooser_context_)
75 std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
76
77 chooser_context_->GetDevices(base::BindOnce(&WebUsbServiceImpl::OnGetDevices,
78 weak_factory_.GetWeakPtr(),
79 std::move(callback)));
Donna Wucaa44de2018-08-17 06:42:3980}
81
82void WebUsbServiceImpl::OnGetDevices(
83 GetDevicesCallback callback,
84 std::vector<device::mojom::UsbDeviceInfoPtr> device_info_list) {
85 std::vector<device::mojom::UsbDeviceInfoPtr> device_infos;
86 for (auto& device_info : device_info_list) {
Donna Wu50fe6b22018-08-30 06:27:4387 if (HasDevicePermission(*device_info))
Donna Wucaa44de2018-08-17 06:42:3988 device_infos.push_back(device_info.Clone());
Donna Wucaa44de2018-08-17 06:42:3989 }
90 std::move(callback).Run(std::move(device_infos));
Donna Wu2fd87fc92018-07-27 01:32:1991}
92
Donna Wu838ac362018-08-10 10:36:3393void WebUsbServiceImpl::GetDevice(
Donna Wu2fd87fc92018-07-27 01:32:1994 const std::string& guid,
95 device::mojom::UsbDeviceRequest device_request) {
Donna Wu35c12ea2018-09-20 06:08:1896 if (!chooser_context_)
97 return;
98
Donna Wuc7029872018-11-02 09:47:0599 auto* device_info = chooser_context_->GetDeviceInfo(guid);
100 if (!device_info || !HasDevicePermission(*device_info))
101 return;
102
103 // Connect Blink to the native device and keep a binding to this for the
104 // UsbDeviceClient interface so we can receive DeviceOpened/Closed events.
105 // This binding will also be closed to notify the device service to close
106 // the connection if permission is revoked.
Donna Wu656439c2018-08-13 09:31:16107 device::mojom::UsbDeviceClientPtr device_client;
Donna Wuc7029872018-11-02 09:47:05108 device_client_bindings_[guid].AddBinding(this,
109 mojo::MakeRequest(&device_client));
Donna Wu35c12ea2018-09-20 06:08:18110 chooser_context_->GetDevice(guid, std::move(device_request),
111 std::move(device_client));
Donna Wu2fd87fc92018-07-27 01:32:19112}
113
Donna Wuc98e12a2018-08-16 07:24:02114void WebUsbServiceImpl::GetPermission(
115 std::vector<device::mojom::UsbDeviceFilterPtr> device_filters,
116 GetPermissionCallback callback) {
117 if (!usb_chooser_)
118 std::move(callback).Run(nullptr);
119
120 usb_chooser_->GetPermission(std::move(device_filters), std::move(callback));
121}
122
Donna Wu838ac362018-08-10 10:36:33123void WebUsbServiceImpl::SetClient(
Donna Wu7205a852018-09-20 04:21:13124 device::mojom::UsbDeviceManagerClientAssociatedPtrInfo client) {
125 DCHECK(client);
126
127 device::mojom::UsbDeviceManagerClientAssociatedPtr client_ptr;
128 client_ptr.Bind(std::move(client));
129 clients_.AddPtr(std::move(client_ptr));
Donna Wu2fd87fc92018-07-27 01:32:19130}
131
Ovidio Henriquez8b39653b2019-01-18 18:56:53132void WebUsbServiceImpl::OnPermissionRevoked(const GURL& requesting_origin,
133 const GURL& embedding_origin) {
134 if (requesting_origin_ != requesting_origin ||
135 embedding_origin_ != embedding_origin) {
136 return;
137 }
138
139 // Close the connection between Blink and the device if the device lost
140 // permission.
141 base::EraseIf(device_client_bindings_, [this](const auto& entry) {
142 auto* device_info = chooser_context_->GetDeviceInfo(entry.first);
143 if (!device_info)
144 return true;
145
146 return !HasDevicePermission(*device_info);
147 });
148}
149
Donna Wu35c12ea2018-09-20 06:08:18150void WebUsbServiceImpl::OnDeviceAdded(
Donna Wuc42ee16b2018-09-30 05:19:51151 const device::mojom::UsbDeviceInfo& device_info) {
152 if (!HasDevicePermission(device_info))
Donna Wu50fe6b22018-08-30 06:27:43153 return;
154
155 clients_.ForAllPtrs(
156 [&device_info](device::mojom::UsbDeviceManagerClient* client) {
Donna Wuc42ee16b2018-09-30 05:19:51157 client->OnDeviceAdded(device_info.Clone());
Donna Wu50fe6b22018-08-30 06:27:43158 });
Donna Wu2fd87fc92018-07-27 01:32:19159}
160
Donna Wu838ac362018-08-10 10:36:33161void WebUsbServiceImpl::OnDeviceRemoved(
Donna Wuc42ee16b2018-09-30 05:19:51162 const device::mojom::UsbDeviceInfo& device_info) {
Donna Wuc7029872018-11-02 09:47:05163 device_client_bindings_.erase(device_info.guid);
Donna Wuc42ee16b2018-09-30 05:19:51164 if (!HasDevicePermission(device_info))
Donna Wu50fe6b22018-08-30 06:27:43165 return;
166
167 clients_.ForAllPtrs(
168 [&device_info](device::mojom::UsbDeviceManagerClient* client) {
Donna Wuc42ee16b2018-09-30 05:19:51169 client->OnDeviceRemoved(device_info.Clone());
Donna Wu50fe6b22018-08-30 06:27:43170 });
Donna Wu2fd87fc92018-07-27 01:32:19171}
172
Donna Wu35c12ea2018-09-20 06:08:18173void WebUsbServiceImpl::OnDeviceManagerConnectionError() {
174 // Close the connection with blink.
175 clients_.CloseAll();
176 bindings_.CloseAllBindings();
177
178 // Remove itself from UsbChooserContext's ObserverList.
Ovidio Henriquez8b39653b2019-01-18 18:56:53179 device_observer_.RemoveAll();
180 permission_observer_.RemoveAll();
Donna Wu35c12ea2018-09-20 06:08:18181}
182
Donna Wu656439c2018-08-13 09:31:16183// device::mojom::UsbDeviceClient implementation:
184void WebUsbServiceImpl::OnDeviceOpened() {
Donna Wu50fe6b22018-08-30 06:27:43185 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
186 content::WebContents* web_contents =
187 content::WebContents::FromRenderFrameHost(render_frame_host_);
188 UsbTabHelper* tab_helper = UsbTabHelper::FromWebContents(web_contents);
189 tab_helper->IncrementConnectionCount(render_frame_host_);
Donna Wu656439c2018-08-13 09:31:16190}
191
192void WebUsbServiceImpl::OnDeviceClosed() {
Donna Wu50fe6b22018-08-30 06:27:43193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
194 content::WebContents* web_contents =
195 content::WebContents::FromRenderFrameHost(render_frame_host_);
196 UsbTabHelper* tab_helper = UsbTabHelper::FromWebContents(web_contents);
197 tab_helper->DecrementConnectionCount(render_frame_host_);
Donna Wu656439c2018-08-13 09:31:16198}
199
Donna Wu50fe6b22018-08-30 06:27:43200void WebUsbServiceImpl::OnBindingConnectionError() {
Ovidio Henriquez8b39653b2019-01-18 18:56:53201 if (bindings_.empty()) {
202 device_observer_.RemoveAll();
203 permission_observer_.RemoveAll();
204 }
Donna Wu2fd87fc92018-07-27 01:32:19205}