// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module bluetooth.mojom;
import "device/bluetooth/public/mojom/device.mojom";
import "device/bluetooth/public/mojom/uuid.mojom";
import "device/bluetooth/public/mojom/gatt_characteristic_permissions.mojom";
import "device/bluetooth/public/mojom/gatt_characteristic_properties.mojom";
import "device/bluetooth/public/mojom/gatt_service_error_code.mojom";
// Possible errors sent as a response by Adapter.ConnectToDevice on a Device
// connection request.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused. This enum should be kept in sync
// with the NearbyConnectionsConnectResult enum in
// src/tools/metrics/histograms/metadata/nearby/enums.xml.
enum ConnectResult {
SUCCESS,
AUTH_CANCELED,
AUTH_FAILED,
AUTH_REJECTED,
AUTH_TIMEOUT,
FAILED,
INPROGRESS,
UNKNOWN,
UNSUPPORTED_DEVICE,
DEVICE_NO_LONGER_IN_RANGE,
NOT_READY,
ALREADY_CONNECTED,
ALREADY_EXISTS,
NOT_CONNECTED,
DOES_NOT_EXIST,
INVALID_ARGS,
NON_AUTH_TIMEOUT,
NO_MEMORY,
JNI_ENVIRONMENT,
JNI_THREAD_ATTACH,
WAKELOCK,
UNEXPECTED_STATE,
SOCKET,
};
union LocalCharacteristicReadResult {
GattServiceErrorCode error_code;
array<uint8> data;
};
// The results of a successful connection via ConnectToServiceInsecurely().
struct ConnectToServiceResult {
pending_remote<Socket> socket;
handle<data_pipe_consumer> receive_stream;
handle<data_pipe_producer> send_stream;
};
// The results of a successful connection via ServerSocket::Accept().
struct AcceptConnectionResult {
DeviceInfo device;
pending_remote<Socket> socket;
handle<data_pipe_consumer> receive_stream;
handle<data_pipe_producer> send_stream;
};
struct AdapterInfo {
// TODO(crbug.com/40709957): Use fixed-size array, not string, for address.
string address;
string name;
string system_name;
// Whether the new CrOS Bluetooth stack (aka floss) is in use. See
// go/project-floss for more info.
bool floss;
// Whether the adapter supports BLE extended advertisements, which were
// added in Bluetooth 5.
bool extended_advertisement_support;
bool initialized;
bool present;
bool powered;
bool discoverable;
bool discovering;
};
// Represents an ongoing BLE advertisement. Releasing it will release the
// underlying object and stop the advertisement, but callers should prefer to
// let a call to Unregister() to finish first.
// Note: Methods which are declared [Sync] are for use by
// //chrome/services/sharing/nearby; all other usage of their synchronous
// signatures is strongly discouraged.
interface Advertisement {
// Use to gracefully stop advertising before destroying the message pipe. The
// reply callback can be used to synchronize an attempt to re-register an
// advertisement; attempting to register an advertisement without first
// releasing limited advertisement slots in the hardware may fail with a
// busy error.
[Sync]
Unregister() => ();
};
// Represents a request to discover nearby devices.
// Note: Methods which are declared [Sync] are for use by
// //chrome/services/sharing/nearby; all other usage of their synchronous
// signatures is strongly discouraged.
interface DiscoverySession {
// Returns true if the session is active, false otherwise. If false, the
// adapter might still be discovering as there might still be other active
// sessions; this just means that this instance no longer has a say in
// whether or not discovery should continue. In this case, a new
// DiscoverySession should be started to make sure that device discovery
// continues.
[Sync]
IsActive() => (bool active);
// Requests this discovery session instance to stop. If this instance is
// active, the session will stop. After a successful invocation, the
// adapter may or may not stop device discovery, depending on whether or not
// other active discovery sessions are present. Users are highly encouraged
// to call this method to end a discovery session, instead of relying on
// disconnecting the message pipe, so that they can respond to the result.
// Returns true on success. Returns false if this session is inactive or an
// error occurs while stopping the session.
[Sync]
Stop() => (bool success);
};
// Represents an open connection to a remote device. Releasing it will destroy
// the underlying connection, but if callers want to try again soon, they should
// call Disconnect() first and wait for completion to ensure that the resource
// has been completely released.
// Note: Methods which are declared [Sync] are for use by
// //chrome/services/sharing/nearby; all other usage of their synchronous
// signatures is strongly discouraged.
interface Socket {
// Use to gracefully close the underlying connection before destroying. The
// reply callback can be used to synchronize a reconnection attempt;
// attempting to reconnect to the same service on this device may fail with a
// busy error until the reply callback is invoked.
[Sync]
Disconnect() => ();
};
// Represents a pending connecting from a remote device. Releasing it will
// stop listening for an incoming connection, but if callers want to start
// listening again soon, they should call Disconnect() first and wait for
// completion to ensure that the resource has been completely released.
// Note: Methods which are declared [Sync] are for use by
// //chrome/services/sharing/nearby; all other usage of their synchronous
// signatures is strongly discouraged.
interface ServerSocket {
// Accept the next incoming connection from a remote device. If something
// goes wrong, the returned |result| will be null.
[Sync]
Accept() => (AcceptConnectionResult? result);
// Use to gracefully close the underlying resource before destroying. The
// reply callback can be used to synchronize an attempt to re-initialize
// a server socket; attempting to listen on the same server socket on this
// device may fail with a busy error until the reply callback is invoked.
[Sync]
Disconnect() => ();
};
// Representation of a BLE GATT service. A `GattService` is created by
// `Adapter::CreateLocalGattService()`. To use this interface, first create all
// characteristics belonging to the service via `CreateCharacteristic()`. Then,
// when ready to publish the service and its characteristics on the local
// adapter's GATT database, call `Register()`. Requests from GATT clients to
// read/write values on the characteristics are executed via the
// `GattServiceObserver`. When finished with the `GattService`, callers should
// delete their Mojo remote, which triggers the underlying GATT service in
// the local adapter to be deleted.
interface GattService {
// Creates a characteristic and adds it to the GATT service under the given
// characteristic uuid, using the service UUID tied to the `GattService`.
// This method will fail if the characteristic already exists at
// `characteristic_uuid`; it is expected that callers will only call
// when they want to create a characteristic that does not already exist.
[Sync]
CreateCharacteristic(UUID characteristic_uuid,
GattCharacteristicPermissions permissions,
GattCharacteristicProperties properties) => (bool success);
// Registers this `GattService` with the local Bluetooth Adapter.
// Calling `Register()` will make this service and all of its associated
// attributes available on the local adapter's GATT database. This should be
// called once all the requested characteristics have been created, before
// advertising begins. No `error_code` indicates success.
Register() => (GattServiceErrorCode? error_code);
};
// Listener on `GattService` events.
// TODO(b/311430390): Implement additional methods that communicate write
// requests on GATT characteristics.
interface GattServiceObserver {
// Called when a remote peripheral is reading from the characteristic.
// On failures, |read_result| will be the error code. On success,
// |read_result| will be the read result value.
OnLocalCharacteristicRead(DeviceInfo remote_device,
UUID characteristic_uuid, UUID service_uuid, uint32 offset) =>
(LocalCharacteristicReadResult read_result);
};
// Handles requests to either query Bluetooth adapter capabilities or state, or
// find or connect to remote devices. Backed by //device/bluetooth.
// Note: Methods which are declared [Sync] are for use by
// //chrome/services/sharing/nearby; all other usage of their synchronous
// signatures is strongly discouraged.
interface Adapter {
// Creates a GATT connection to the device with |address| and returns a
// Device if the connection was succesful. The GATT connection is tied to the
// the lifetime of the Device message pipe.
// TODO(crbug.com/40709957): Use fixed-size array, not string, for address.
ConnectToDevice(string address) =>
(ConnectResult result, pending_remote<Device>? device);
// Retrieves the list of the devices known by the adapter including Connected
// Devices, GATT Connected Devices, Paired Devices and Devices discovered
// during a classic or low-energy scan.
GetDevices() => (array<DeviceInfo> devices);
// Gets basic information about the adapter.
[Sync]
GetInfo() => (AdapterInfo info);
// Adds an observer that listens for the adapter's events.
[Sync]
AddObserver(pending_remote<AdapterObserver> observer) => ();
// Requests the adapter to broadcast a BLE advertisement on |service_id| with
// the associated packet |service_data|. Returns null if advertisement is not
// registered successfully.
//
// When |use_scan_response| is true, the |service_data| is added to the scan
// response instead of the initial advertisement. When |connectable| is true,
// the advertisement is created as type PERIPHERAL; else it is type BROADCAST.
// A few assumptions are made:
//
// 1) The |service_id| provided is a valid 16-bit UUID in 128-bit format.
// The identifying 16-bits will be extracted for the short service id used
// in the scan response.
// 2) The Ad Type is assumed to be 0x16 as that is all that is supported by
// the Platform right now.
//
// Important notes:
// * Bluetooth chips generally can only broadcast a few advertisements,
// sometimes even only one, simultaneously. This can be mitigated by
// operating systems "rotating" advertisements in the higher software layer,
// as Chrome OS does. Non-Chrome OS clients of this API are responsible for
// understanding their host OS's and/or hardware's limitations.
[Sync]
RegisterAdvertisement(UUID service_id, array<uint8> service_data,
bool use_scan_response, bool connectable)
=> (pending_remote<Advertisement>? advertisement);
// Requests the local device to make itself discoverable to nearby remote
// devices.
[Sync]
SetDiscoverable(bool discoverable) => (bool success);
// Change the name of the local device as it appears to remote devices.
// TODO(crbug.com/40145221): Implement a mechanism to request this resource
// before being able to use it.
[Sync]
SetName(string name) => (bool success);
// Requests the adapter to start a new discovery session. Returns null if
// session not created successfully.
[Sync]
StartDiscoverySession(string client_name) => (pending_remote<DiscoverySession>? session);
// Attempts to initiate an insecure outgoing L2CAP or RFCOMM connection to the
// advertised service on this device matching |service_uuid|. This method is
// marked as "Insecurely" because the outgoing connection will not request
// bonding (pairing) to the remote device. If the connection attempt fails,
// the returned |result| will be null. See Socket for details on how to close
// the connection.
//
// If the local device is already bonded and the connection attempt fails,
// when |should_unbond_on_error| is true the local device will forget the
// remote device. (see b/204274786)
// TODO(crbug.com/40709957): Use fixed-size array, not string, for address.
[Sync]
ConnectToServiceInsecurely(string address, UUID service_uuid,
bool should_unbond_on_error) => (ConnectToServiceResult? result);
// Creates an RFCOMM service on this adapter advertised with |service_name|
// and |service_uuid|. This method is marked as "Insecurely" because the local
// device will not request bonding (pairing) with the remote device: clients
// are responsible for securing the connection at the application-level. If
// the service creation attempt fails, the returned |server_socket| will be
// null. See ServerSocket for details on how to stop listening.
[Sync]
CreateRfcommServiceInsecurely(string service_name, UUID service_uuid)
=> (pending_remote<ServerSocket>? server_socket);
// Creates a local GATT service corresponding to |service_id|, and
// communicates events to the |observer|. This call is only expected to be
// used to create a local GATT service that does not exist at |service_id|.
// Callers should first consult |IsLeScatternetDualRoleSupported()| before
// calling this method to determine if a GATT service can be safely started on
// the local device.
[Sync]
CreateLocalGattService(UUID service_id,
pending_remote<GattServiceObserver> observer)
=> (pending_remote<GattService> gatt_service);
// Retrieves the status of whether or not the LE Scatternet Dual Role
// (simultaneous use of the LE peripheral and central roles) is supported on
// the Adapter. If |is_supported| is true, then callers can call
// |CreateLocalGattService()| without being concerned about performance or
// stability issues.
[Sync]
IsLeScatternetDualRoleSupported() => (bool is_supported);
};
// Listener on Bluetooth events. Register as an observer via AddObserver().
interface AdapterObserver {
// Called when the presence of the adapter changes.
PresentChanged(bool present);
// Called when the radio power state of the adapter changes.
PoweredChanged(bool powered);
// Called when the discoverability state of the adapter changes.
DiscoverableChanged(bool discoverable);
// Called when the discovering state of the adapter changes.
DiscoveringChanged(bool discovering);
// Called the first time a device is discovered.
DeviceAdded(DeviceInfo device);
// Called when one of the following properties of a device changes:
// Address, appearance, Bluetooth class, Inquiry RSSI, Inquiry TX Power,
// Service UUIDs, Connectionable state, Connection state, Pairing state,
// Trustable state.
// Generally called for each advertisement packet recevied, but this is not
// guaranteed on ChromeOS or Linux. Because the RSSI is always changing,
// it's very likely this will be called for each advertising packet.
DeviceChanged(DeviceInfo device);
// Called after the device hasn't been seen for 3 minutes.
DeviceRemoved(DeviceInfo device);
};