Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(serial): allow Bluetooth ports to be requested by service class ID #41735

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions BUILD.gn
Expand Up @@ -473,6 +473,7 @@ source_set("electron_lib") {
"//net:extras",
"//net:net_resources",
"//printing/buildflags",
"//services/device/public/cpp/bluetooth:bluetooth",
"//services/device/public/cpp/geolocation",
"//services/device/public/cpp/hid",
"//services/device/public/mojom",
Expand Down
10 changes: 7 additions & 3 deletions shell/browser/serial/electron_serial_delegate.cc
Expand Up @@ -35,7 +35,9 @@ std::unique_ptr<content::SerialChooser> ElectronSerialDelegate::RunChooser(
if (controller) {
DeleteControllerForFrame(frame);
}
AddControllerForFrame(frame, std::move(filters), std::move(callback));
AddControllerForFrame(frame, std::move(filters),
std::move(allowed_bluetooth_service_class_ids),
std::move(callback));

// Return a nullptr because the return value isn't used for anything, eg
// there is no mechanism to cancel navigator.serial.requestPort(). The return
Expand Down Expand Up @@ -106,12 +108,14 @@ SerialChooserController* ElectronSerialDelegate::ControllerForFrame(
SerialChooserController* ElectronSerialDelegate::AddControllerForFrame(
content::RenderFrameHost* render_frame_host,
std::vector<blink::mojom::SerialPortFilterPtr> filters,
std::vector<device::BluetoothUUID> allowed_bluetooth_service_class_ids,
content::SerialChooser::Callback callback) {
auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
auto controller = std::make_unique<SerialChooserController>(
render_frame_host, std::move(filters), std::move(callback), web_contents,
weak_factory_.GetWeakPtr());
render_frame_host, std::move(filters),
std::move(allowed_bluetooth_service_class_ids), std::move(callback),
web_contents, weak_factory_.GetWeakPtr());
controller_map_.insert(
std::make_pair(render_frame_host, std::move(controller)));
return ControllerForFrame(render_frame_host);
Expand Down
1 change: 1 addition & 0 deletions shell/browser/serial/electron_serial_delegate.h
Expand Up @@ -65,6 +65,7 @@ class ElectronSerialDelegate : public content::SerialDelegate,
SerialChooserController* AddControllerForFrame(
content::RenderFrameHost* render_frame_host,
std::vector<blink::mojom::SerialPortFilterPtr> filters,
std::vector<device::BluetoothUUID> allowed_bluetooth_service_class_ids,
content::SerialChooser::Callback callback);

base::ScopedObservation<SerialChooserContext,
Expand Down
74 changes: 58 additions & 16 deletions shell/browser/serial/serial_chooser_controller.cc
Expand Up @@ -11,6 +11,9 @@
#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "services/device/public/cpp/bluetooth/bluetooth_utils.h"
#include "services/device/public/mojom/serial.mojom.h"
#include "shell/browser/api/electron_api_session.h"
#include "shell/browser/serial/serial_chooser_context.h"
#include "shell/browser/serial/serial_chooser_context_factory.h"
Expand Down Expand Up @@ -58,14 +61,57 @@ struct Converter<device::mojom::SerialPortInfoPtr> {

namespace electron {

namespace {

using ::device::mojom::SerialPortType;

bool FilterMatchesPort(const blink::mojom::SerialPortFilter& filter,
const device::mojom::SerialPortInfo& port) {
if (filter.bluetooth_service_class_id) {
if (!port.bluetooth_service_class_id) {
return false;
}
return device::BluetoothUUID(*port.bluetooth_service_class_id) ==
device::BluetoothUUID(*filter.bluetooth_service_class_id);
}
if (!filter.has_vendor_id) {
return true;
}
if (!port.has_vendor_id || port.vendor_id != filter.vendor_id) {
return false;
}
if (!filter.has_product_id) {
return true;
}
return port.has_product_id && port.product_id == filter.product_id;
}

bool BluetoothPortIsAllowed(
const std::vector<::device::BluetoothUUID>& allowed_ids,
const device::mojom::SerialPortInfo& port) {
if (!port.bluetooth_service_class_id) {
return true;
}
// Serial Port Profile is allowed by default.
if (*port.bluetooth_service_class_id == device::GetSerialPortProfileUUID()) {
return true;
}
return base::Contains(allowed_ids, port.bluetooth_service_class_id.value());
}

} // namespace

SerialChooserController::SerialChooserController(
content::RenderFrameHost* render_frame_host,
std::vector<blink::mojom::SerialPortFilterPtr> filters,
std::vector<::device::BluetoothUUID> allowed_bluetooth_service_class_ids,
content::SerialChooser::Callback callback,
content::WebContents* web_contents,
base::WeakPtr<ElectronSerialDelegate> serial_delegate)
: WebContentsObserver(web_contents),
filters_(std::move(filters)),
allowed_bluetooth_service_class_ids_(
std::move(allowed_bluetooth_service_class_ids)),
callback_(std::move(callback)),
serial_delegate_(serial_delegate),
render_frame_host_id_(render_frame_host->GetGlobalId()) {
Expand Down Expand Up @@ -93,10 +139,11 @@ api::Session* SerialChooserController::GetSession() {

void SerialChooserController::OnPortAdded(
const device::mojom::SerialPortInfo& port) {
if (!FilterMatchesAny(port))
if (!DisplayDevice(port))
return;

ports_.push_back(port.Clone());

api::Session* session = GetSession();
if (session) {
session->Emit("serial-port-added", port.Clone(), web_contents());
Expand All @@ -105,9 +152,8 @@ void SerialChooserController::OnPortAdded(

void SerialChooserController::OnPortRemoved(
const device::mojom::SerialPortInfo& port) {
const auto it = std::find_if(
ports_.begin(), ports_.end(),
[&port](const auto& ptr) { return ptr->token == port.token; });
const auto it = base::ranges::find(ports_, port.token,
&device::mojom::SerialPortInfo::token);
if (it != ports_.end()) {
api::Session* session = GetSession();
if (session) {
Expand Down Expand Up @@ -152,7 +198,7 @@ void SerialChooserController::OnGetDevices(
});

for (auto& port : ports) {
if (FilterMatchesAny(*port))
if (DisplayDevice(*port))
ports_.push_back(std::move(port));
}

Expand All @@ -169,21 +215,17 @@ void SerialChooserController::OnGetDevices(
}
}

bool SerialChooserController::FilterMatchesAny(
bool SerialChooserController::DisplayDevice(
const device::mojom::SerialPortInfo& port) const {
if (filters_.empty())
return true;
if (filters_.empty()) {
return BluetoothPortIsAllowed(allowed_bluetooth_service_class_ids_, port);
}

for (const auto& filter : filters_) {
if (filter->has_vendor_id &&
(!port.has_vendor_id || filter->vendor_id != port.vendor_id)) {
continue;
}
if (filter->has_product_id &&
(!port.has_product_id || filter->product_id != port.product_id)) {
continue;
if (FilterMatchesPort(*filter, port) &&
BluetoothPortIsAllowed(allowed_bluetooth_service_class_ids_, port)) {
return true;
}
return true;
}

return false;
Expand Down
4 changes: 3 additions & 1 deletion shell/browser/serial/serial_chooser_controller.h
Expand Up @@ -34,6 +34,7 @@ class SerialChooserController final : public SerialChooserContext::PortObserver,
SerialChooserController(
content::RenderFrameHost* render_frame_host,
std::vector<blink::mojom::SerialPortFilterPtr> filters,
std::vector<::device::BluetoothUUID> allowed_bluetooth_service_class_ids,
content::SerialChooser::Callback callback,
content::WebContents* web_contents,
base::WeakPtr<ElectronSerialDelegate> serial_delegate);
Expand All @@ -53,11 +54,12 @@ class SerialChooserController final : public SerialChooserContext::PortObserver,
private:
api::Session* GetSession();
void OnGetDevices(std::vector<device::mojom::SerialPortInfoPtr> ports);
bool FilterMatchesAny(const device::mojom::SerialPortInfo& port) const;
bool DisplayDevice(const device::mojom::SerialPortInfo& port) const;
void RunCallback(device::mojom::SerialPortInfoPtr port);
void OnDeviceChosen(const std::string& port_id);

std::vector<blink::mojom::SerialPortFilterPtr> filters_;
std::vector<::device::BluetoothUUID> allowed_bluetooth_service_class_ids_;
content::SerialChooser::Callback callback_;
url::Origin origin_;

Expand Down