Try to fix Bluetooth issue to get service

PiperOrigin-RevId: 570475245
This commit is contained in:
Guogang Li
2023-10-03 13:12:31 -07:00
committed by Copybara-Service
parent 3fdcbe4ddc
commit 7dea977b74
6 changed files with 166 additions and 182 deletions
@@ -89,6 +89,7 @@ using ::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEScanningMode;
using ::winrt::Windows::Foundation::TimeSpan;
using ::winrt::Windows::Storage::Streams::Buffer;
using ::winrt::Windows::Storage::Streams::DataReader;
using ::winrt::Windows::Storage::Streams::DataWriter;
template <typename T>
@@ -16,12 +16,15 @@
#include <winstring.h>
#include <chrono> // NOLINT(build/c++11)
#include <codecvt>
#include <exception>
#include <locale>
#include <string>
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h"
@@ -34,9 +37,11 @@
namespace nearby {
namespace windows {
namespace {
constexpr int kBluetoothTimeoutInSeconds = 10;
using ::winrt::Windows::Foundation::TimeSpan;
constexpr int kBluetoothTimeoutInSeconds = 10;
constexpr int kCheckBluetoothServiceMaxTimes = 3;
constexpr absl::Duration kCheckBluetoothServiceInterval = absl::Seconds(1);
} // namespace
BluetoothDevice::~BluetoothDevice() {}
@@ -72,67 +77,74 @@ std::string BluetoothDevice::GetMacAddress() const { return mac_address_; }
// Checks cache first, will check uncached if no result.
RfcommDeviceService BluetoothDevice::GetRfcommServiceForIdAsync(
const RfcommServiceId serviceId) {
try {
NEARBY_LOGS(INFO) << __func__ << ": Get RF services for service id:"
<< winrt::to_string(serviceId.AsString());
int check_service_count = 0;
while (check_service_count < kCheckBluetoothServiceMaxTimes) {
try {
NEARBY_LOGS(INFO) << __func__ << ": Get RF services for service id:"
<< winrt::to_string(serviceId.AsString());
RfcommDeviceServicesResult rfcomm_device_services = nullptr;
// Try to get service from un cached mode.
auto rfcomm_device_services_async =
windows_bluetooth_device_.GetRfcommServicesForIdAsync(
serviceId, BluetoothCacheMode::Uncached);
RfcommDeviceServicesResult rfcomm_device_services = nullptr;
// Try to get service from un cached mode.
auto rfcomm_device_services_async =
windows_bluetooth_device_.GetRfcommServicesForIdAsync(
serviceId, BluetoothCacheMode::Uncached);
switch (rfcomm_device_services_async.wait_for(
TimeSpan(std::chrono::seconds(kBluetoothTimeoutInSeconds)))) {
case winrt::Windows::Foundation::AsyncStatus::Completed:
rfcomm_device_services = rfcomm_device_services_async.GetResults();
break;
case winrt::Windows::Foundation::AsyncStatus::Started:
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to timeout.";
rfcomm_device_services_async.Cancel();
return nullptr;
default:
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to unknown reasons.";
return nullptr;
}
switch (rfcomm_device_services_async.wait_for(
TimeSpan(std::chrono::seconds(kBluetoothTimeoutInSeconds)))) {
case winrt::Windows::Foundation::AsyncStatus::Completed:
rfcomm_device_services = rfcomm_device_services_async.GetResults();
break;
case winrt::Windows::Foundation::AsyncStatus::Started:
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to timeout.";
rfcomm_device_services_async.Cancel();
return nullptr;
default:
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to unknown reasons.";
return nullptr;
}
if (rfcomm_device_services != nullptr &&
rfcomm_device_services.Services().Size() > 0) {
NEARBY_LOGS(INFO) << __func__ << ": Get "
<< rfcomm_device_services.Services().Size()
<< " services without cache.";
// found the matched service.
for (auto rfcomm_device_service : rfcomm_device_services.Services()) {
if (rfcomm_device_service.Device() != nullptr &&
winrt::to_string(rfcomm_device_service.Device().DeviceId()) ==
id_) {
NEARBY_LOGS(INFO)
<< __func__ << ": Found service from no-cache mode.";
return rfcomm_device_service;
if (rfcomm_device_services != nullptr &&
rfcomm_device_services.Services().Size() > 0) {
NEARBY_LOGS(INFO) << __func__ << ": Get "
<< rfcomm_device_services.Services().Size()
<< " services without cache.";
// found the matched service.
for (auto rfcomm_device_service : rfcomm_device_services.Services()) {
if (rfcomm_device_service.Device() != nullptr &&
winrt::to_string(rfcomm_device_service.Device().DeviceId()) ==
id_) {
NEARBY_LOGS(INFO)
<< __func__ << ": Found service from no-cache mode.";
return rfcomm_device_service;
}
}
}
}
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to no any services.";
return nullptr;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get RfcommDeviceService: "
<< exception.what();
return nullptr;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__ << ": RfcommDeviceService: " << ex.code()
<< ", error message: " << winrt::to_string(ex.message());
return nullptr;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
return nullptr;
++check_service_count;
absl::SleepFor(kCheckBluetoothServiceInterval);
NEARBY_LOGS(ERROR) << __func__ << ": No any services at "
<< check_service_count << "th check.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get RfcommDeviceService: "
<< exception.what();
return nullptr;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__ << ": RfcommDeviceService: " << ex.code()
<< ", error message: "
<< winrt::to_string(ex.message());
return nullptr;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
return nullptr;
}
}
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get RfcommDeviceService.";
return nullptr;
}
} // namespace windows
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2020-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -26,6 +26,14 @@
namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Networking::Sockets::StreamSocket;
using ::winrt::Windows::Networking::Sockets::SocketProtectionLevel;
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
using ::winrt::Windows::Networking::Sockets::StreamSocketListener;
using ::winrt::Windows::Networking::Sockets::
StreamSocketListenerConnectionReceivedEventArgs;
} // namespace
BluetoothServerSocket::BluetoothServerSocket(absl::string_view service_name)
: service_name_(service_name) {}
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2020-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
#include "internal/platform/implementation/windows/generated/winrt/base.h"
@@ -30,28 +31,9 @@
namespace nearby {
namespace windows {
// Supports listening for an incoming network connection using Bluetooth RFCOMM.
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocketlistener?view=winrt-20348
using winrt::Windows::Networking::Sockets::StreamSocketListener;
// Provides data for a ConnectionReceived event on a StreamSocketListener
// object.
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocketlistenerconnectionreceivedeventargs?view=winrt-20348
using winrt::Windows::Networking::Sockets::
StreamSocketListenerConnectionReceivedEventArgs;
// Specifies the quality of service for a StreamSocket object.
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.socketqualityofservice?view=winrt-20348
using winrt::Windows::Networking::Sockets::SocketQualityOfService;
// Specifies the level of encryption to use on a StreamSocket object.
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.socketprotectionlevel?view=winrt-22000
using winrt::Windows::Networking::Sockets::SocketProtectionLevel;
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html.
class BluetoothServerSocket : public api::BluetoothServerSocket {
public:
BluetoothServerSocket(absl::string_view service_name);
explicit BluetoothServerSocket(absl::string_view service_name);
~BluetoothServerSocket() override;
@@ -77,24 +59,28 @@ class BluetoothServerSocket : public api::BluetoothServerSocket {
bool listen();
const StreamSocketListener& stream_socket_listener() const {
const ::winrt::Windows::Networking::Sockets::StreamSocketListener&
stream_socket_listener() const {
return stream_socket_listener_;
}
private:
// The listener is accepting incoming connections
::winrt::fire_and_forget Listener_ConnectionReceived(
StreamSocketListener listener,
StreamSocketListenerConnectionReceivedEventArgs const& args);
::winrt::Windows::Networking::Sockets::StreamSocketListener listener,
::winrt::Windows::Networking::Sockets::
StreamSocketListenerConnectionReceivedEventArgs const& args);
// Retrieves IP addresses from local machine
std::vector<std::string> GetIpAddresses() const;
mutable absl::Mutex mutex_;
absl::CondVar cond_;
std::deque<StreamSocket> pending_sockets_ ABSL_GUARDED_BY(mutex_);
StreamSocketListener stream_socket_listener_{nullptr};
winrt::event_token listener_event_token_{};
std::deque<::winrt::Windows::Networking::Sockets::StreamSocket>
pending_sockets_ ABSL_GUARDED_BY(mutex_);
::winrt::Windows::Networking::Sockets::StreamSocketListener
stream_socket_listener_{nullptr};
::winrt::event_token listener_event_token_{};
// Close notifier
absl::AnyInvocable<void()> close_notifier_ = nullptr;
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2020-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,32 +14,41 @@
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
#include <cstdint>
#include <cstring>
#include <exception>
#include <memory>
#include <utility>
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
#include "internal/platform/implementation/windows/generated/winrt/base.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/Windows.Networking.Sockets.h"
#include "winrt/base.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Devices::Bluetooth::BluetoothConnectionStatus;
constexpr int kMaxConnectRetryCount = 3;
constexpr absl::Duration kConnectInterval = absl::Seconds(3);
using ::winrt::Windows::Networking::HostName;
using ::winrt::Windows::Networking::Sockets::StreamSocket;
using ::winrt::Windows::Storage::Streams::Buffer;
using ::winrt::Windows::Storage::Streams::IInputStream;
using ::winrt::Windows::Storage::Streams::InputStreamOptions;
using ::winrt::Windows::Storage::Streams::IOutputStream;
} // namespace
BluetoothSocket::BluetoothSocket(StreamSocket streamSocket)
: windows_socket_(streamSocket) {
BluetoothSocket::BluetoothSocket(StreamSocket stream_socket)
: windows_socket_(stream_socket) {
NEARBY_LOGS(INFO) << __func__ << ": Initialize bluetooth socket.";
native_bluetooth_device_ =
winrt::Windows::Devices::Bluetooth::BluetoothDevice::FromHostNameAsync(
::winrt::Windows::Devices::Bluetooth::BluetoothDevice::FromHostNameAsync(
windows_socket_.Information().RemoteHostName())
.get();
if (FeatureFlags::GetInstance()
@@ -125,26 +134,18 @@ api::BluetoothDevice* BluetoothSocket::GetRemoteDevice() {
// Starts an asynchronous operation on a StreamSocket object to connect to a
// remote network destination specified by a remote hostname and a remote
// service name.
bool BluetoothSocket::Connect(HostName connectionHostName,
winrt::hstring connectionServiceName) {
bool BluetoothSocket::Connect(HostName connection_host_name,
::winrt::hstring connection_service_name) {
NEARBY_LOGS(INFO) << __func__ << ": start to connect to bluetooth service:"
<< winrt::to_string(connectionServiceName);
<< winrt::to_string(connection_service_name);
connect_called_count_ = 0;
while (connect_called_count_ < kMaxConnectRetryCount) {
connect_called_count_ += 1;
bool connect_result =
InternalConnect(connectionHostName, connectionServiceName);
if (connect_result) {
return connect_result;
}
NEARBY_LOGS(WARNING) << __func__ << ": Failed to connect bluetooth at the "
<< connect_called_count_ << "th call.";
absl::SleepFor(kConnectInterval);
bool connect_result =
InternalConnect(connection_host_name, connection_service_name);
if (connect_result) {
return connect_result;
}
NEARBY_LOGS(WARNING) << __func__ << ": Failed to connect bluetooth";
return false;
}
@@ -164,7 +165,8 @@ ExceptionOr<ByteArray> BluetoothSocket::BluetoothInputStream::Read(
if (size > read_buffer_.Capacity()) {
NEARBY_LOGS(WARNING) << __func__
<< ": resize receive buffer to packet size: " << size;
<< ": resize receive buffer to packet size: "
<< size;
read_buffer_ = Buffer(size);
}
@@ -225,8 +227,8 @@ Exception BluetoothSocket::BluetoothOutputStream::Write(const ByteArray& data) {
try {
if (data.size() > write_buffer_.Capacity()) {
NEARBY_LOGS(WARNING) << __func__
<< ": resize write buffer to packet size: "
<< data.size();
<< ": resize write buffer to packet size: "
<< data.size();
write_buffer_ = Buffer(data.size());
}
@@ -290,10 +292,10 @@ Exception BluetoothSocket::BluetoothOutputStream::Close() {
}
}
bool BluetoothSocket::InternalConnect(HostName connectionHostName,
winrt::hstring connectionServiceName) {
bool BluetoothSocket::InternalConnect(HostName connection_host_name,
winrt::hstring connection_service_name) {
try {
if (connectionHostName == nullptr || connectionServiceName.empty()) {
if (connection_host_name == nullptr || connection_service_name.empty()) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Bluetooth socket connection failed. Attempting to "
@@ -303,14 +305,14 @@ bool BluetoothSocket::InternalConnect(HostName connectionHostName,
NEARBY_LOGS(INFO) << __func__
<< ": Bluetooth socket connection to host name:"
<< winrt::to_string(connectionHostName.DisplayName())
<< winrt::to_string(connection_host_name.DisplayName())
<< ", service name:"
<< winrt::to_string(connectionServiceName);
<< winrt::to_string(connection_service_name);
windows_socket_ = winrt::Windows::Networking::Sockets::StreamSocket();
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocket.connectasync?view=winrt-20348
windows_socket_.ConnectAsync(connectionHostName, connectionServiceName)
windows_socket_.ConnectAsync(connection_host_name, connection_service_name)
.get();
auto info = windows_socket_.Information();
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2020-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,60 +15,29 @@
#ifndef PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_SOCKET_H_
#define PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_SOCKET_H_
#include <windows.h>
#include <cstdint>
#include <memory>
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
#include "winrt/Windows.Foundation.h"
#include "winrt/Windows.Networking.Sockets.h"
#include "winrt/Windows.Storage.Streams.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Storage.Streams.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace windows {
// Provides data for a hostname or an IP address.
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.hostname?view=winrt-20348
using winrt::Windows::Networking::HostName;
// Supports network communication using a stream socket over Bluetooth RFCOMM.
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocket?view=winrt-20348
using winrt::Windows::Networking::Sockets::IStreamSocket;
using winrt::Windows::Networking::Sockets::StreamSocket;
// Provides a default implementation of the IBuffer interface and its related
// interfaces.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.buffer?view=winrt-20348
using winrt::Windows::Storage::Streams::Buffer;
// Represents a sequential stream of bytes to be read.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.iinputstream?view=winrt-20348
using winrt::Windows::Storage::Streams::IInputStream;
// Represents a sequential stream of bytes to be written.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.ioutputstream?view=winrt-20348
using winrt::Windows::Storage::Streams::IOutputStream;
// Specifies the read options for an input stream.
// This enumeration has a FlagsAttribute attribute that allows a bitwise
// combination of its member values.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.inputstreamoptions?view=winrt-20348
using winrt::Windows::Storage::Streams::InputStreamOptions;
// Reads data from an input stream.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.datareader?view=winrt-20348
using winrt::Windows::Storage::Streams::DataReader;
// Represents an asynchronous action.
// https://docs.microsoft.com/en-us/uwp/api/windows.foundation.iasyncaction?view=winrt-20348
using winrt::Windows::Foundation::IAsyncAction;
// https://developer.android.com/reference/android/bluetooth/BluetoothSocket.html.
class BluetoothSocket : public api::BluetoothSocket {
public:
BluetoothSocket();
explicit BluetoothSocket(StreamSocket streamSocket);
explicit BluetoothSocket(
::winrt::Windows::Networking::Sockets::StreamSocket stream_socket);
~BluetoothSocket() override;
// NOTE:
@@ -95,28 +64,32 @@ class BluetoothSocket : public api::BluetoothSocket {
// Connect asynchronously to the target remote device
// Returns true if successful, false otherwise
bool Connect(HostName connectionHostName,
winrt::hstring connectionServiceName);
bool Connect(::winrt::Windows::Networking::HostName connection_host_name,
::winrt::hstring connection_service_name);
private:
static constexpr int kInitialTransmitPacketSize = 4096;
class BluetoothInputStream : public InputStream {
public:
explicit BluetoothInputStream(IInputStream stream);
explicit BluetoothInputStream(
::winrt::Windows::Storage::Streams::IInputStream stream);
~BluetoothInputStream() override = default;
ExceptionOr<ByteArray> Read(std::int64_t size) override;
Exception Close() override;
private:
IInputStream winrt_input_stream_{nullptr};
Buffer read_buffer_{kInitialTransmitPacketSize};
::winrt::Windows::Storage::Streams::IInputStream winrt_input_stream_{
nullptr};
::winrt::Windows::Storage::Streams::Buffer read_buffer_{
kInitialTransmitPacketSize};
};
class BluetoothOutputStream : public OutputStream {
public:
explicit BluetoothOutputStream(IOutputStream stream);
explicit BluetoothOutputStream(
::winrt::Windows::Storage::Streams::IOutputStream stream);
~BluetoothOutputStream() override = default;
Exception Write(const ByteArray& data) override;
@@ -125,26 +98,28 @@ class BluetoothSocket : public api::BluetoothSocket {
Exception Close() override;
private:
IOutputStream winrt_output_stream_{nullptr};
Buffer write_buffer_{kInitialTransmitPacketSize};
::winrt::Windows::Storage::Streams::IOutputStream winrt_output_stream_{
nullptr};
::winrt::Windows::Storage::Streams::Buffer write_buffer_{
kInitialTransmitPacketSize};
};
bool InternalConnect(HostName connectionHostName,
winrt::hstring connectionServiceName);
bool InternalConnect(
::winrt::Windows::Networking::HostName connection_host_name,
::winrt::hstring connection_service_name);
winrt::fire_and_forget Listener_ConnectionStatusChanged(
winrt::Windows::Devices::Bluetooth::BluetoothDevice device,
winrt::Windows::Foundation::IInspectable const& args);
::winrt::fire_and_forget Listener_ConnectionStatusChanged(
::winrt::Windows::Devices::Bluetooth::BluetoothDevice device,
::winrt::Windows::Foundation::IInspectable const& args);
StreamSocket windows_socket_{nullptr};
::winrt::Windows::Networking::Sockets::StreamSocket windows_socket_{nullptr};
bool is_bluetooth_socket_closed_ = false;
BluetoothInputStream input_stream_{nullptr};
BluetoothOutputStream output_stream_{nullptr};
std::unique_ptr<BluetoothDevice> bluetooth_device_ = nullptr;
winrt::Windows::Devices::Bluetooth::BluetoothDevice native_bluetooth_device_{
nullptr};
winrt::event_token connection_status_changed_token_{};
int connect_called_count_ = 0;
::winrt::Windows::Devices::Bluetooth::BluetoothDevice
native_bluetooth_device_{nullptr};
::winrt::event_token connection_status_changed_token_{};
};
} // namespace windows