blob: 031b38419dfa24b2ee534c1d338b54845d216055 [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 "media/mojo/interfaces/remoting_common.mojom.h"
Donna Wu4dc9df32019-05-20 03:56:2118#include "services/device/public/mojom/usb_enumeration_options.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),
Jeremy Roman495db682019-07-12 16:03:2426 permission_observer_(this) {
Donna Wu35c12ea2018-09-20 06:08:1827 DCHECK(render_frame_host_);
28 content::WebContents* web_contents =
29 content::WebContents::FromRenderFrameHost(render_frame_host_);
Donna Wuc7029872018-11-02 09:47:0530 // This class is destroyed on cross-origin navigations and so it is safe to
31 // cache these values.
Reilly Grant392c6112019-04-23 19:12:1232 requesting_origin_ = render_frame_host_->GetLastCommittedOrigin();
33 embedding_origin_ = web_contents->GetMainFrame()->GetLastCommittedOrigin();
Donna Wu35c12ea2018-09-20 06:08:1834 Profile* profile =
35 Profile::FromBrowserContext(web_contents->GetBrowserContext());
36 chooser_context_ = UsbChooserContextFactory::GetForProfile(profile);
37 DCHECK(chooser_context_);
Donna Wu50fe6b22018-08-30 06:27:4338
39 bindings_.set_connection_error_handler(base::BindRepeating(
40 &WebUsbServiceImpl::OnBindingConnectionError, base::Unretained(this)));
41}
42
43WebUsbServiceImpl::~WebUsbServiceImpl() = default;
44
45void WebUsbServiceImpl::BindRequest(
46 blink::mojom::WebUsbServiceRequest request) {
47 bindings_.AddBinding(this, std::move(request));
48
Donna Wu35c12ea2018-09-20 06:08:1849 // Listen to UsbChooserContext for add/remove device events from UsbService.
Donna Wu838ac362018-08-10 10:36:3350 // We can't set WebUsbServiceImpl as a UsbDeviceManagerClient because
Donna Wu2fd87fc92018-07-27 01:32:1951 // the OnDeviceRemoved event will be delivered here after it is delivered
52 // to UsbChooserContext, meaning that all ephemeral permission checks in
53 // OnDeviceRemoved() will fail.
Ovidio Henriquez8b39653b2019-01-18 18:56:5354 if (!device_observer_.IsObservingSources())
55 device_observer_.Add(chooser_context_);
56 if (!permission_observer_.IsObservingSources())
57 permission_observer_.Add(chooser_context_);
Donna Wu2fd87fc92018-07-27 01:32:1958}
59
Donna Wu50fe6b22018-08-30 06:27:4360bool WebUsbServiceImpl::HasDevicePermission(
61 const device::mojom::UsbDeviceInfo& device_info) const {
62 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
63 DCHECK(render_frame_host_);
Donna Wu35c12ea2018-09-20 06:08:1864 if (!chooser_context_)
65 return false;
Donna Wu50fe6b22018-08-30 06:27:4366
Donna Wuc7029872018-11-02 09:47:0567 return chooser_context_->HasDevicePermission(requesting_origin_,
68 embedding_origin_, device_info);
Donna Wu50fe6b22018-08-30 06:27:4369}
Donna Wu2fd87fc92018-07-27 01:32:1970
Donna Wu838ac362018-08-10 10:36:3371void WebUsbServiceImpl::GetDevices(GetDevicesCallback callback) {
Donna Wu35c12ea2018-09-20 06:08:1872 if (!chooser_context_)
73 std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
74
75 chooser_context_->GetDevices(base::BindOnce(&WebUsbServiceImpl::OnGetDevices,
76 weak_factory_.GetWeakPtr(),
77 std::move(callback)));
Donna Wucaa44de2018-08-17 06:42:3978}
79
80void WebUsbServiceImpl::OnGetDevices(
81 GetDevicesCallback callback,
82 std::vector<device::mojom::UsbDeviceInfoPtr> device_info_list) {
83 std::vector<device::mojom::UsbDeviceInfoPtr> device_infos;
84 for (auto& device_info : device_info_list) {
Donna Wu50fe6b22018-08-30 06:27:4385 if (HasDevicePermission(*device_info))
Donna Wucaa44de2018-08-17 06:42:3986 device_infos.push_back(device_info.Clone());
Donna Wucaa44de2018-08-17 06:42:3987 }
88 std::move(callback).Run(std::move(device_infos));
Donna Wu2fd87fc92018-07-27 01:32:1989}
90
Donna Wu838ac362018-08-10 10:36:3391void WebUsbServiceImpl::GetDevice(
Donna Wu2fd87fc92018-07-27 01:32:1992 const std::string& guid,
93 device::mojom::UsbDeviceRequest device_request) {
Donna Wu35c12ea2018-09-20 06:08:1894 if (!chooser_context_)
95 return;
96
Donna Wuc7029872018-11-02 09:47:0597 auto* device_info = chooser_context_->GetDeviceInfo(guid);
98 if (!device_info || !HasDevicePermission(*device_info))
99 return;
100
101 // Connect Blink to the native device and keep a binding to this for the
102 // UsbDeviceClient interface so we can receive DeviceOpened/Closed events.
103 // This binding will also be closed to notify the device service to close
104 // the connection if permission is revoked.
Donna Wu656439c2018-08-13 09:31:16105 device::mojom::UsbDeviceClientPtr device_client;
Donna Wuc7029872018-11-02 09:47:05106 device_client_bindings_[guid].AddBinding(this,
107 mojo::MakeRequest(&device_client));
Donna Wu35c12ea2018-09-20 06:08:18108 chooser_context_->GetDevice(guid, std::move(device_request),
109 std::move(device_client));
Donna Wu2fd87fc92018-07-27 01:32:19110}
111
Donna Wuc98e12a2018-08-16 07:24:02112void WebUsbServiceImpl::GetPermission(
113 std::vector<device::mojom::UsbDeviceFilterPtr> device_filters,
114 GetPermissionCallback callback) {
115 if (!usb_chooser_)
116 std::move(callback).Run(nullptr);
117
118 usb_chooser_->GetPermission(std::move(device_filters), std::move(callback));
119}
120
Donna Wu838ac362018-08-10 10:36:33121void WebUsbServiceImpl::SetClient(
Donna Wu7205a852018-09-20 04:21:13122 device::mojom::UsbDeviceManagerClientAssociatedPtrInfo client) {
123 DCHECK(client);
124
125 device::mojom::UsbDeviceManagerClientAssociatedPtr client_ptr;
126 client_ptr.Bind(std::move(client));
127 clients_.AddPtr(std::move(client_ptr));
Donna Wu2fd87fc92018-07-27 01:32:19128}
129
Reilly Grantbcdeddb2019-05-06 22:37:24130void WebUsbServiceImpl::OnPermissionRevoked(
131 const url::Origin& requesting_origin,
132 const url::Origin& embedding_origin) {
133 if (requesting_origin_ != requesting_origin ||
134 embedding_origin_ != embedding_origin) {
Ovidio Henriquez8b39653b2019-01-18 18:56:53135 return;
136 }
137
138 // Close the connection between Blink and the device if the device lost
139 // permission.
140 base::EraseIf(device_client_bindings_, [this](const auto& entry) {
141 auto* device_info = chooser_context_->GetDeviceInfo(entry.first);
142 if (!device_info)
143 return true;
144
145 return !HasDevicePermission(*device_info);
146 });
147}
148
Donna Wu35c12ea2018-09-20 06:08:18149void WebUsbServiceImpl::OnDeviceAdded(
Donna Wuc42ee16b2018-09-30 05:19:51150 const device::mojom::UsbDeviceInfo& device_info) {
151 if (!HasDevicePermission(device_info))
Donna Wu50fe6b22018-08-30 06:27:43152 return;
153
154 clients_.ForAllPtrs(
155 [&device_info](device::mojom::UsbDeviceManagerClient* client) {
Donna Wuc42ee16b2018-09-30 05:19:51156 client->OnDeviceAdded(device_info.Clone());
Donna Wu50fe6b22018-08-30 06:27:43157 });
Donna Wu2fd87fc92018-07-27 01:32:19158}
159
Donna Wu838ac362018-08-10 10:36:33160void WebUsbServiceImpl::OnDeviceRemoved(
Donna Wuc42ee16b2018-09-30 05:19:51161 const device::mojom::UsbDeviceInfo& device_info) {
Donna Wuc7029872018-11-02 09:47:05162 device_client_bindings_.erase(device_info.guid);
Donna Wuc42ee16b2018-09-30 05:19:51163 if (!HasDevicePermission(device_info))
Donna Wu50fe6b22018-08-30 06:27:43164 return;
165
166 clients_.ForAllPtrs(
167 [&device_info](device::mojom::UsbDeviceManagerClient* client) {
Donna Wuc42ee16b2018-09-30 05:19:51168 client->OnDeviceRemoved(device_info.Clone());
Donna Wu50fe6b22018-08-30 06:27:43169 });
Donna Wu2fd87fc92018-07-27 01:32:19170}
171
Donna Wu35c12ea2018-09-20 06:08:18172void WebUsbServiceImpl::OnDeviceManagerConnectionError() {
173 // Close the connection with blink.
174 clients_.CloseAll();
175 bindings_.CloseAllBindings();
176
177 // Remove itself from UsbChooserContext's ObserverList.
Ovidio Henriquez8b39653b2019-01-18 18:56:53178 device_observer_.RemoveAll();
179 permission_observer_.RemoveAll();
Donna Wu35c12ea2018-09-20 06:08:18180}
181
Donna Wu656439c2018-08-13 09:31:16182// device::mojom::UsbDeviceClient implementation:
183void WebUsbServiceImpl::OnDeviceOpened() {
Donna Wu50fe6b22018-08-30 06:27:43184 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
185 content::WebContents* web_contents =
186 content::WebContents::FromRenderFrameHost(render_frame_host_);
187 UsbTabHelper* tab_helper = UsbTabHelper::FromWebContents(web_contents);
188 tab_helper->IncrementConnectionCount(render_frame_host_);
Donna Wu656439c2018-08-13 09:31:16189}
190
191void WebUsbServiceImpl::OnDeviceClosed() {
Donna Wu50fe6b22018-08-30 06:27:43192 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
193 content::WebContents* web_contents =
194 content::WebContents::FromRenderFrameHost(render_frame_host_);
195 UsbTabHelper* tab_helper = UsbTabHelper::FromWebContents(web_contents);
196 tab_helper->DecrementConnectionCount(render_frame_host_);
Donna Wu656439c2018-08-13 09:31:16197}
198
Donna Wu50fe6b22018-08-30 06:27:43199void WebUsbServiceImpl::OnBindingConnectionError() {
Ovidio Henriquez8b39653b2019-01-18 18:56:53200 if (bindings_.empty()) {
201 device_observer_.RemoveAll();
202 permission_observer_.RemoveAll();
203 }
Donna Wu2fd87fc92018-07-27 01:32:19204}