Final implementation of all BluetoothAdapter methods

PiperOrigin-RevId: 393009194
This commit is contained in:
jfcarroll
2021-08-25 16:53:17 -07:00
committed by Copybara-Service
parent 62e7c01cd3
commit 81b72ab1bf
4 changed files with 172 additions and 37 deletions
+142 -21
View File
@@ -15,7 +15,6 @@
#include "platform/impl/windows/bluetooth_adapter.h"
#include <windows.h>
#include <stdio.h>
#include <winioctl.h>
#include <bthdef.h>
#include <bthioctl.h>
@@ -24,6 +23,7 @@
#include <initguid.h>
#include <objbase.h>
#include <setupapi.h>
#include <stdio.h>
#include <usbiodef.h>
#include <string>
@@ -38,6 +38,14 @@ typedef std::basic_string<TCHAR> tstring;
// IOCTL to get local radio information
#define BTH_GET_DEVICE_INFO_IOCTL 0x411008
#define BUFFER_SIZE 64
#define FILE_NAME_SIZE 1024
#define REGISTRY_QUERY_FORMAT \
"SYSTEM\\ControlSet001\\Enum\\%s\\Device Parameters"
#define BLUETOOTH_RADIO_REGISTRY_NAME_KEY "Local Name"
namespace location {
namespace nearby {
namespace windows {
@@ -92,7 +100,90 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
// Returns an empty string on error
// TODO(b/184975123): replace with real implementation.
std::string BluetoothAdapter::GetName() const { return "Un-implemented"; }
std::string BluetoothAdapter::GetName() const {
char *instanceID = GetGenericBluetoothAdapterInstanceID();
if (instanceID == NULL) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to get Generic Bluetooth Adapter InstanceID";
return std::string();
}
// Add 1 to length to get size (including null)
// Modify the InstanceID to the format that the Registry expects
char *instanceIDModified = new char[(strlen(instanceID) + 1) * sizeof(char)];
absl::SNPrintF(instanceIDModified,
size_t((strlen(instanceID) + 1) * sizeof(char)), "%s",
instanceID);
find_and_replace(instanceIDModified, "\\", "#");
// Change radio module local name in registry
HKEY hKey;
char rmLocalNameKey[FILE_NAME_SIZE] = {0};
LSTATUS ret;
absl::SNPrintF(rmLocalNameKey, sizeof(rmLocalNameKey), REGISTRY_QUERY_FORMAT,
instanceID);
// Opens the specified registry key.
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexa
ret = RegOpenKeyExA(
HKEY_LOCAL_MACHINE, // A handle to an open registry key, using
// predefined key for local machine
rmLocalNameKey, // The name of the registry subkey to be opened.
0L, // Specifies the option to apply when opening the key.
KEY_QUERY_VALUE, // A mask that specifies the desired access rights to
// the key to be opened.
&hKey); // A pointer to a variable that receives a handle to the opened
// key
if (ret == ERROR_SUCCESS) {
BYTE rmLocalName[FILE_NAME_SIZE] = {0};
DWORD rmLocalNameSize = FILE_NAME_SIZE;
DWORD valueType;
LSTATUS status =
// Retrieves the type and data for the specified value name associated
// with an open registry key.
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa
RegQueryValueExA(
hKey, // A handle to an open registry key.
BLUETOOTH_RADIO_REGISTRY_NAME_KEY, // The name of the registry
// value.
nullptr, // This parameter is reserved and must be NULL.
&valueType, // A pointer to a variable that receives a code
// indicating the type of data stored in the
// specified value.
&rmLocalName[0], // A pointer to a buffer that receives the
// value's data.
&rmLocalNameSize); // A pointer to a variable that specifies the
// size of the buffer pointed to by the lpData
// parameter, in bytes.
// Closes a handle to the specified registry key.
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey
RegCloseKey(hKey);
if (status == ERROR_SUCCESS) {
char str[FILE_NAME_SIZE]{0};
memcpy(str, rmLocalName, rmLocalNameSize);
return std::string(str);
}
}
// The local name is not in the registry, return the machine name
char localName[FILE_NAME_SIZE];
DWORD nameSize = FILE_NAME_SIZE;
// Retrieves the NetBIOS name of the local computer.
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcomputernamea
if (GetComputerNameA(localName, &nameSize)) {
return std::string(localName);
}
// If we're here, we couldn't get a local name, this should never happen
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get any radio name";
return std::string();
}
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#setName(java.lang.String)
bool BluetoothAdapter::SetName(absl::string_view name) {
@@ -114,16 +205,16 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
find_and_replace(instanceIDModified, "\\", "#");
HANDLE hDevice;
char fileName[1024] = {0};
char fileName[FILE_NAME_SIZE] = {0};
// defined in usbiodef.h
const GUID guid = GUID_DEVINTERFACE_USB_DEVICE;
OLECHAR guidOleStr[64];
int oleBufferLen = 64;
OLECHAR guidOleStr[BUFFER_SIZE];
int oleBufferLen = BUFFER_SIZE;
char guidStr[64];
int bufferLen = 64;
char guidStr[BUFFER_SIZE];
int bufferLen = BUFFER_SIZE;
BOOL defaultCharUsed;
// Converts a globally unique identifier (GUID) into a string of printable
@@ -172,8 +263,16 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// Creates or opens a file or I/O device.
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
hDevice =
CreateFileA(fileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
hDevice = CreateFileA(
fileName, // The name of the file or device to be created or opened.
GENERIC_WRITE, // The requested access to the file or device.
0, // The requested sharing mode of the file or device.
NULL, // A pointer to a SECURITY_ATTRIBUTES structure.
OPEN_EXISTING, // An action to take on a file or device that exists or
// does not exist.
0, // The file or device attributes and flags.
NULL); // A valid handle to a template file with the GENERIC_READ access
// right. This parameter can be NULL.
delete[] instanceIDModified;
@@ -185,18 +284,23 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// Change radio module local name in registry
HKEY hKey;
char rmLocalNameKey[1024] = {0};
char rmLocalNameKey[FILE_NAME_SIZE] = {0};
LSTATUS ret;
absl::SNPrintF(rmLocalNameKey, sizeof(rmLocalNameKey),
"SYSTEM\\ControlSet001\\Enum\\%s\\Device Parameters",
absl::SNPrintF(rmLocalNameKey, sizeof(rmLocalNameKey), REGISTRY_QUERY_FORMAT,
instanceID);
// Opens the specified registry key. Note that key names are not case
// sensitive.
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regopenkeyexa
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, rmLocalNameKey, 0L, KEY_SET_VALUE,
&hKey);
ret = RegOpenKeyExA(
HKEY_LOCAL_MACHINE, // A handle to an open registry key.
rmLocalNameKey, // The name of the registry subkey to be opened.
0L, // Specifies the option to apply when opening the key.
KEY_SET_VALUE, // A mask that specifies the desired access rights to the
// key to be opened.
&hKey); // A pointer to a variable that receives a handle to the opened
// key.
if (ret != ERROR_SUCCESS) {
NEARBY_LOGS(ERROR) << __func__
@@ -206,9 +310,15 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// Sets the data and type of a specified value under a registry key.
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regsetvalueexa
ret = RegSetValueExA(hKey, "Local Name", 0, REG_BINARY,
(LPBYTE)std::string(name).c_str(),
strlen(std::string(name).c_str()));
ret = RegSetValueExA(
hKey, // A handle to an open registry key
BLUETOOTH_RADIO_REGISTRY_NAME_KEY, // The name of the value to be set.
0, // This parameter is reserved and must be zero.
REG_BINARY, // The type of data pointed to by the lpData parameter.
(LPBYTE)std::string(name).c_str(), // The data to be stored.
strlen(
std::string(name).c_str())); // The size of the information pointed
// to by the lpData parameter, in bytes.
if (ret != ERROR_SUCCESS) {
NEARBY_LOGS(ERROR) << __func__
@@ -229,8 +339,19 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
// Sends a control code directly to a specified device driver, causing the
// corresponding device to perform the corresponding operation.
// https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol
if (!DeviceIoControl(hDevice, BTH_GET_DEVICE_INFO_IOCTL, &reload, 4, NULL, 0,
&bytes, NULL)) {
if (!DeviceIoControl(
hDevice, // A handle to the device on which the operation is to be
// performed.
BTH_GET_DEVICE_INFO_IOCTL, // The control code for the operation.
&reload, // A pointer to the input buffer that contains the data
// required to perform the operation.
sizeof(reload), // The size of the input buffer, in bytes.
NULL, // A pointer to the output buffer that is to receive the data
// returned by the operation.
0, // The size of the output buffer, in bytes.
&bytes, // A pointer to a variable that receives the size of the data
// stored in the output buffer, in bytes.
NULL)) { // A pointer to an OVERLAPPED structure.
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to update radio module local name. Error code: "
@@ -243,7 +364,7 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
}
void BluetoothAdapter::find_and_replace(char *source, const char *strFind,
const char *strReplace) {
const char *strReplace) const {
std::string s = std::string(source);
std::string f = std::string(strFind);
std::string r = std::string(strReplace);
@@ -256,7 +377,7 @@ void BluetoothAdapter::find_and_replace(char *source, const char *strFind,
memcpy(source, s.c_str(), s.size());
}
char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) {
char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) const {
unsigned i;
CONFIGRET r;
HDEVINFO hDevInfo;
@@ -75,9 +75,9 @@ class BluetoothAdapter : public api::BluetoothAdapter {
windows_bluetooth_adapter_;
IRadio windows_bluetooth_radio_;
char *GetGenericBluetoothAdapterInstanceID(void);
char *GetGenericBluetoothAdapterInstanceID(void) const;
void find_and_replace(char *source, const char *strFind,
const char *strReplace);
const char *strReplace) const;
ScanMode scan_mode_ = ScanMode::kNone;
};
@@ -85,12 +85,12 @@ void BluetoothClassicMedium::InitializeDeviceWatcher() {
nullptr, // additionalProperties
DeviceInformationKind::AssociationEndpoint); // kind
// An app must subscribe to all of the added, removed, and updated events to
// be notified when there are device additions, removals or updates. If an app
// handles only the added event, it will not receive an update if a device is
// added to the system after the initial device enumeration completes.
// register event handlers before starting the watcher
//
// An app must subscribe to all of the added, removed, and updated events to
// be notified when there are device additions, removals or updates. If an
// app handles only the added event, it will not receive an update if a
// device is added to the system after the initial device enumeration
// completes. register event handlers before starting the watcher
// Event that is raised when a device is added to the collection enumerated
// by the DeviceWatcher.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher.added?view=winrt-20348
@@ -19,11 +19,12 @@
#include <string>
#include "platform/impl/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
#include "absl/strings/str_format.h"
#include "platform/impl/windows/bluetooth_classic_device.h"
#include "gtest/gtest.h"
#include "absl/strings/str_format.h"
#include "platform/api/bluetooth_adapter.h"
#include "platform/impl/windows/bluetooth_adapter.h"
#include "platform/impl/windows/bluetooth_classic_device.h"
#include "platform/impl/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
// TODO(jfcarroll): Find a way to mock winrt components in order to properly
// unit test this. Once that's done, unit tests can be written, in a later C/L.
@@ -61,8 +62,17 @@ void device_lost_cb(location::nearby::api::BluetoothDevice& device) {
}
TEST(TestCaseName, TestName) {
auto bluetoothAdapter = location::nearby::windows::BluetoothAdapter();
std::string bluetoothAdapterName = bluetoothAdapter.GetName();
bluetoothAdapter.SetName("BluetoothTestName");
bluetoothAdapterName = bluetoothAdapter.GetName();
bluetoothAdapter.SetName("");
bluetoothAdapterName = bluetoothAdapter.GetName();
std::unique_ptr<location::nearby::windows::BluetoothClassicMedium> bcm =
std::make_unique<location::nearby::windows::BluetoothClassicMedium>();
std::make_unique<location::nearby::windows::BluetoothClassicMedium>(
bluetoothAdapter);
bcm->StartDiscovery(
location::nearby::api::BluetoothClassicMedium::DiscoveryCallback{
@@ -74,10 +84,14 @@ TEST(TestCaseName, TestName) {
Sleep(30000);
auto currentDevice = deviceList["DC:DC:E2:F2:B5:99"];
auto serviceUuid = winrt::Windows::Devices::Bluetooth::Rfcomm::
RfcommServiceId::GenericFileTransfer();
auto serviceUuid = winrt::to_string(
winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId::SerialPort()
.AsString());
location::nearby::CancellationFlag cancellationFlag;
bcm->ConnectToService(*currentDevice, "a82efa21-ae5c-3dde-9bbc-f16da7b16c5a",
bcm->ConnectToService(*currentDevice,
// "a82efa21-ae5c-3dde-9bbc-f16da7b16c5a",
"00001101-0000-1000-8000-00805F9B34FB",
&cancellationFlag);
EXPECT_EQ(1, 1);