Merged from google/nearby main

This commit is contained in:
lasan
2024-10-22 11:27:36 +05:30
988 changed files with 175061 additions and 15634 deletions
+57 -4
View File
@@ -13,6 +13,25 @@
# limitations under the License.
licenses(["notice"])
cc_library(
name = "account_manager",
hdrs = ["account_manager.h"],
visibility = [
"//fastpair:__subpackages__",
"//internal/account:__pkg__",
"//internal/platform/implementation:__subpackages__",
"//internal/test:__subpackages__",
"//location/nearby/cpp/sharing/clients/cpp:__subpackages__",
"//location/nearby/sharing/sdk/quick_share_server:__pkg__",
"//sharing:__subpackages__",
],
deps = [
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:string_view",
],
)
cc_library(
name = "types",
hdrs = [
@@ -39,6 +58,7 @@ cc_library(
"timer.h",
],
visibility = [
"//connections/implementation:__subpackages__",
"//connections/implementation/analytics:__subpackages__",
"//fastpair:__subpackages__",
"//internal/crypto_cros:__pkg__",
@@ -47,14 +67,14 @@ cc_library(
"//internal/preferences:__subpackages__",
"//internal/test:__subpackages__",
"//location/nearby/analytics/cpp:__subpackages__",
"//location/nearby/cpp/common:__subpackages__",
"//location/nearby/cpp/sharing:__subpackages__",
"//presence:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
"//sharing:__subpackages__",
],
deps = [
"//internal/crypto_cros",
"//internal/platform:base",
"//internal/platform/implementation/shared:crypto", # Non-chromium impl
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/strings",
@@ -64,6 +84,24 @@ cc_library(
],
)
cc_library(
name = "wifi_utils",
srcs = [
"wifi_utils.cc",
],
hdrs = [
"wifi.h",
"wifi_utils.h",
],
visibility = [
"//:__subpackages__",
],
deps = [
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)
cc_library(
name = "comm",
hdrs = [
@@ -84,11 +122,11 @@ cc_library(
copts = ["-DNO_WEBRTC"],
visibility = [
"//connections/implementation:__subpackages__",
"//fastpair/internal:__pkg__",
"//fastpair/internal/mediums:__pkg__",
"//internal/network:__subpackages__",
"//internal/platform:__pkg__",
"//internal/platform/implementation:__subpackages__",
"//presence:__subpackages__",
"//presence/implementation:__subpackages__",
],
deps = [
@@ -121,8 +159,9 @@ cc_library(
"//internal/platform:__pkg__",
"//internal/platform/implementation:__subpackages__",
"//location/nearby/analytics/cpp:__subpackages__",
"//location/nearby/apps/better_together/plugins/preferences_native:__subpackages__",
"//location/nearby/cpp/sharing:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
"//sharing:__subpackages__",
],
deps = [
":comm",
@@ -132,3 +171,17 @@ cc_library(
"@com_google_absl//absl/strings",
],
)
cc_test(
name = "wifi_utils_test",
size = "small",
timeout = "moderate",
srcs = ["wifi_utils_test.cc"],
shard_count = 8,
deps = [
":wifi_utils",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,104 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_API_ACCOUNT_MANAGER_H_
#define PLATFORM_API_ACCOUNT_MANAGER_H_
#include <optional>
#include <string>
#include <utility>
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
namespace nearby {
// AccountManager manages the accounts are used to access Nearby backend.
// In current design, AccountManager only support one active account.
class AccountManager {
public:
// Describes a Nearby account. The account class will have more properties
// and methods in the future based on the new feature added.
struct Account {
std::string id; // The unique identify of the account.
std::string display_name;
std::string family_name;
std::string given_name;
std::string picture_url;
std::string email;
};
// Observes the activity of the account manager.
class Observer {
public:
virtual ~Observer() = default;
virtual void OnLoginSucceeded(absl::string_view account_id) = 0;
// |credential_error| is true if the logout is due to critical auth error.
virtual void OnLogoutSucceeded(absl::string_view account_id,
bool credential_error) = 0;
};
virtual ~AccountManager() = default;
// Gets current active account. If no login user, return std::nullopt.
virtual std::optional<Account> GetCurrentAccount() = 0;
// Initializes the login process for a Google account from 1P client.
// |login_success_callback| is called when the login succeeded. Account
// information is passed to callback.
// |login_failure_callback| is called when the login fails.
virtual void Login(
absl::AnyInvocable<void(Account)> login_success_callback,
absl::AnyInvocable<void(absl::Status)> login_failure_callback) = 0;
// Initializes the login process for a Google account from an oauth client.
// |client_id| GCP client_id of the client
// |client_secret| GCP client_secret of the client
// |login_success_callback| is called when the login succeeded. Account
// information is passed to callback.
// |login_failure_callback| is called when the login fails.
virtual void Login(
absl::string_view client_id, absl::string_view client_secret,
absl::AnyInvocable<void(Account)> login_success_callback,
absl::AnyInvocable<void(absl::Status)> login_failure_callback) = 0;
// Logs out current active account. |logout_callback| is called when logout is
// completed.
virtual void Logout(
absl::AnyInvocable<void(absl::Status)> logout_callback) = 0;
// Gets access token for the active account.
// |success_callback| is called when an access token is fetched successfully.
// |failure_callback| is called when fetching an access token failed.
//
// Returns false if account_id is empty or callback is null.
virtual bool GetAccessToken(
absl::string_view account_id,
absl::AnyInvocable<void(absl::string_view)> success_callback,
absl::AnyInvocable<void(absl::Status)> failure_callback) = 0;
// Returns a pair containing the client id and client secret used in the most
// recent Login request.
// If no current user is logged in, returns empty string for both.
virtual std::pair<std::string, std::string> GetOAuthClientCredential() = 0;
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
};
} // namespace nearby
#endif // PLATFORM_API_ACCOUNT_MANAGER_H_
+16 -13
View File
@@ -17,7 +17,7 @@ package(default_visibility = [
"//connections:__subpackages__",
"//internal/platform/implementation/apple:__subpackages__",
"//location/nearby:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
"//sharing:__subpackages__",
])
objc_library(
@@ -25,7 +25,6 @@ objc_library(
srcs = [
"crypto.mm",
"device_info.mm",
"log_message.mm",
"multi_thread_executor.mm",
"platform.mm",
"preferences_manager.mm",
@@ -35,7 +34,6 @@ objc_library(
],
hdrs = [
"device_info.h",
"log_message.h",
"multi_thread_executor.h",
"preferences_manager.h",
"scheduled_executor.h",
@@ -50,23 +48,25 @@ objc_library(
":Platform_cc",
":Shared",
":ble_v2",
"//internal/platform:base",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation/apple/Mediums",
"//internal/platform/implementation/shared:file",
"//third_party/apple_frameworks:CoreBluetooth",
"//third_party/apple_frameworks:Foundation",
"//third_party/apple_frameworks:Network",
"//third_party/objective_c/google_toolbox_for_mac:GTM_Logger",
# Required Reason API File: third_party/nearby/internal/platform/implementation/apple/preferences_manager.mm
"//releasetools/apple/privacy/privacymanifests/requiredreasonsapi:user_defaults-user_defaults-read_write_app_data_ca92_1",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
"//third_party/apple_frameworks:CoreBluetooth",
"//third_party/apple_frameworks:Foundation",
"//third_party/apple_frameworks:Network",
"@nlohmann_json//:json",
"//internal/platform:base",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation/apple/Mediums",
"//internal/platform/implementation/shared:file",
"//third_party/objective_c/google_toolbox_for_mac:GTM_Logger",
] + select({
"@platforms//os:platform_ios": [
"//third_party/apple_frameworks:UIKit",
@@ -148,8 +148,10 @@ cc_library(
"mutex.h",
],
deps = [
"//internal/platform:base",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
@@ -168,6 +170,7 @@ cc_test(
shard_count = 16,
deps = [
":Platform_cc",
"//internal/platform/implementation/g3:crypto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
@@ -49,6 +49,14 @@ typedef void (^GNCGetCharacteristicCompletionHandler)(
typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable value,
NSError *_Nullable error);
/**
* A block to be invoked after a call to @c disconnect, requesting that the local connection to the
* remote peripheral be cancelled.
*
* @param peripheral The remote peripheral to disconnect from.
*/
typedef void (^GNCRequestDisconnectionHandler)(id<GNCPeripheral> peripheral);
/**
* An object that can be used to discover, explore, and interact with GATT services and
* characteristics available on a remote peripheral.
@@ -64,8 +72,11 @@ typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable va
* Initializes the GATT client with a specified peripheral.
*
* @param peripheral The peripheral instance.
* @param requestDisconnectionHandler Called on a private queue with @c peripheral when the
* connection to the peripheral should be cancelled.
*/
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral;
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler;
/**
* Discovers the specified characteristics of a service.
@@ -112,6 +123,9 @@ typedef void (^GNCReadCharacteristicValueCompletionHandler)(NSData *_Nullable va
completionHandler:
(nullable GNCReadCharacteristicValueCompletionHandler)completionHandler;
/** Cancels an active or pending local connection to a peripheral. */
- (void)disconnect;
@end
NS_ASSUME_NONNULL_END
@@ -49,6 +49,7 @@ static NSError *AlreadyReadingCharacteristicError() {
@implementation GNCBLEGATTClient {
dispatch_queue_t _queue;
id<GNCPeripheral> _peripheral;
GNCRequestDisconnectionHandler _requestDisconnectionHandler;
/**
* A map of service UUIDs with each service holding a map of a list of characterisitcs to a
@@ -70,15 +71,18 @@ static NSError *AlreadyReadingCharacteristicError() {
*_readCharacteristicValueCompletionHandlers;
}
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral {
return [self
initWithPeripheral:peripheral
queue:dispatch_queue_create(kGNCBLEGATTClientQueueLabel, DISPATCH_QUEUE_SERIAL)];
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler {
return [self initWithPeripheral:peripheral
queue:dispatch_queue_create(kGNCBLEGATTClientQueueLabel,
DISPATCH_QUEUE_SERIAL)
requestDisconnectionHandler:requestDisconnectionHandler];
};
// Private.
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
queue:(nullable dispatch_queue_t)queue {
queue:(nullable dispatch_queue_t)queue
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler {
self = [super init];
if (self) {
_queue = queue ?: dispatch_get_main_queue();
@@ -86,6 +90,7 @@ static NSError *AlreadyReadingCharacteristicError() {
_peripheral.peripheralDelegate = self;
_discoverCharacteristicsCompletionHandlers = [[NSMutableDictionary alloc] init];
_readCharacteristicValueCompletionHandlers = [[NSMutableDictionary alloc] init];
_requestDisconnectionHandler = requestDisconnectionHandler;
}
return self;
};
@@ -173,6 +178,12 @@ static NSError *AlreadyReadingCharacteristicError() {
});
}
- (void)disconnect {
dispatch_async(_queue, ^{
_requestDisconnectionHandler(_peripheral);
});
}
#pragma mark - Internal
- (CBCharacteristic *)synchronousCharacteristicWithUUID:(CBUUID *)characteristicUUID
@@ -245,7 +245,13 @@ static NSError *AlreadyScanningError() {
GNCGATTConnectionCompletionHandler handler = _connectionCompletionHandlers[peripheral.identifier];
_connectionCompletionHandlers[peripheral.identifier] = nil;
if (handler) {
GNCBLEGATTClient *client = [[GNCBLEGATTClient alloc] initWithPeripheral:peripheral];
GNCBLEGATTClient *client =
[[GNCBLEGATTClient alloc] initWithPeripheral:peripheral
requestDisconnectionHandler:^(id<GNCPeripheral> peripheral) {
dispatch_async(_queue, ^{
[_centralManager cancelPeripheralConnection:peripheral];
});
}];
handler(client, nil);
}
}
@@ -79,6 +79,21 @@ NS_ASSUME_NONNULL_BEGIN
- (void)connectPeripheral:(id<GNCPeripheral>)peripheral
options:(nullable NSDictionary<NSString *, id> *)options;
/**
* Cancels an active or pending local connection to a peripheral.
*
* This method is nonblocking, and any @c CBPeripheral class commands that are still pending to
* @c peripheral may not complete. Because other apps may still have a connection to the peripheral,
* canceling a local connection doesnt guarantee that the underlying physical link is immediately
* disconnected. From the apps perspective, however, the peripheral is effectively disconnected,
* and the central manager object calls the @c centralManager:didDisconnectPeripheral:error: method
* of its delegate object.
*
* @param peripheral The peripheral to which the central manager is either trying to connect or has
* already connected.
*/
- (void)cancelPeripheralConnection:(id<GNCPeripheral>)peripheral;
/** Asks the central manager to stop scanning for peripherals. */
- (void)stopScan;
@@ -50,7 +50,7 @@ NSData *GNCMGenerateBLEFramesIntroductionPacket(NSData *serviceIDHash) {
return packet;
}
NSData *GNCMParseBLEFramesIntroductionPacket(NSData *data) {
NSData *_Nullable GNCMParseBLEFramesIntroductionPacket(NSData *data) {
::location::nearby::mediums::SocketControlFrame socket_control_frame;
NSUInteger prefixLength = sizeof(kGNCMControlPacketServiceIDHash);
NSData *packet = [data subdataWithRange:NSMakeRange(prefixLength, data.length - prefixLength)];
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test")
load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS")
load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test")
licenses(["notice"])
@@ -32,9 +32,7 @@ objc_library(
deps = [
":Shared",
"//third_party/apple_frameworks:CoreBluetooth",
"//third_party/apple_frameworks:CoreFoundation",
"//third_party/apple_frameworks:Foundation",
"//third_party/apple_frameworks:QuartzCore",
"//third_party/objective_c/google_toolbox_for_mac:GTM_Logger",
],
)
@@ -728,7 +728,11 @@ static NSString *PeripheralStateString(CBPeripheralState state) {
packet.version);
[_connectionConfirmTimer invalidate];
_connectionConfirmTimer = nil;
_socket.packetSize = packet.packetSize;
// Weave is using `CBCharacteristicWriteWithResponse` for writes, so we must query max value since
// it can have a smaller value than the `GNSWeaveConnectionConfirmPacket` size.
NSUInteger maxWriteLength =
[_socket.peerAsPeripheral maximumWriteValueLengthForType:CBCharacteristicWriteWithResponse];
_socket.packetSize = MIN(packet.packetSize, maxWriteLength);
[_socket didConnect];
if (packet.data) {
// According to the Weave BLE protocol the data received during the connection handshake should
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("//tools/build_defs/apple:ios.bzl", "ios_unit_test")
load("//third_party/nearby:minimum_os.bzl", "IOS_LATEST_TEST_RUNNER", "IOS_MINIMUM_OS")
load("//tools/build_defs/apple:ios.bzl", "ios_unit_test")
licenses(["notice"])
@@ -31,9 +31,12 @@ NS_ASSUME_NONNULL_BEGIN
* @param peripheral The peripheral instance.
* @param queue The queue to run on, this must match the queue that the peripheral's delegate is
* running on. Defaults to the main queue when @c nil.
* @param requestDisconnectionHandler Called on a private queue with @c peripheral when the
* connection to the peripheral should be cancelled.
*/
- (instancetype)initWithPeripheral:(id<GNCPeripheral>)peripheral
queue:(nullable dispatch_queue_t)queue;
queue:(nullable dispatch_queue_t)queue
requestDisconnectionHandler:(GNCRequestDisconnectionHandler)requestDisconnectionHandler;
@end
@@ -19,6 +19,7 @@
#import <XCTest/XCTest.h>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h"
#import "internal/platform/implementation/apple/Tests/GNCBLEGATTClient+Testing.h"
#import "internal/platform/implementation/apple/Tests/GNCFakePeripheral.h"
@@ -37,8 +38,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testDiscoverCharacteristics {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -64,8 +68,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
fakePeripheral.discoverServicesError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -97,8 +104,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
code:0
userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -123,8 +133,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testDuplicateDiscoverCharacteristics {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -163,8 +176,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testDiscoverCharacteristicsMultipleCallsWithDifferentServices {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID1 = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *serviceUUID2 = [CBUUID UUIDWithString:kServiceUUID2];
@@ -209,8 +225,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testDiscoverCharacteristicsMultipleCallsWithDifferentCharacteristics {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -256,8 +275,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testGetCharacteristic {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -287,8 +309,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
fakePeripheral.discoverServicesError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -324,8 +349,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
code:0
userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -353,8 +381,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testDuplicateGetCharacteristic {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -400,8 +431,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testGetNonExistentCharacteristic {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -425,8 +459,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testReadValueForCharacteristic {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -461,8 +498,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
fakePeripheral.discoverServicesError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -503,8 +543,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
code:0
userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -541,8 +584,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
code:0
userInfo:nil];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -576,8 +622,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testDuplicateReadValueForCharacteristic {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -630,8 +679,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testReadValueForMultipleCharacteristics {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID1 = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -691,8 +743,11 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
- (void)testReadValueForUndiscoveredCharacteristic {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -714,13 +769,33 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000
[self waitForExpectations:@[ expectation ] timeout:3];
}
- (void)testDisconnect {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Disconnect."];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> peripheral) {
XCTAssertNotNil(peripheral);
[expectation fulfill];
}];
[gattClient disconnect];
[self waitForExpectations:@[ expectation ] timeout:3];
}
#pragma mark - Delegate Calls
- (void)testUnexpectedDelegateCalls {
GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init];
GNCBLEGATTClient *gattClient = [[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil];
GNCBLEGATTClient *gattClient =
[[GNCBLEGATTClient alloc] initWithPeripheral:fakePeripheral
queue:nil
requestDisconnectionHandler:^(id<GNCPeripheral> __unused peripheral){
}];
CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1];
@@ -18,6 +18,7 @@
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h"
#import "internal/platform/implementation/apple/Tests/GNCBLEMedium+Testing.h"
@@ -313,8 +314,6 @@ static NSString *const kServiceUUID = @"0000FEF3-0000-1000-8000-00805F9B34FB";
- (void)testDisconnect {
GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init];
GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil];
XCTestExpectation *connectExpectation =
[[XCTestExpectation alloc] initWithDescription:@"Connect."];
XCTestExpectation *disconnectExpectation =
[[XCTestExpectation alloc] initWithDescription:@"Disconnect."];
@@ -327,13 +326,9 @@ static NSString *const kServiceUUID = @"0000FEF3-0000-1000-8000-00805F9B34FB";
completionHandler:^(GNCBLEGATTClient *client, NSError *error) {
XCTAssertNotNil(client);
XCTAssertNil(error);
[connectExpectation fulfill];
[client disconnect];
}];
[self waitForExpectations:@[ connectExpectation ] timeout:3];
[fakeCentralManager simulateCentralManagerDidDisconnectPeripheral:peripheral];
[self waitForExpectations:@[ disconnectExpectation ] timeout:3];
}
@@ -56,6 +56,10 @@
[centralDelegate gnc_centralManager:self didConnectPeripheral:peripheral];
}
- (void)cancelPeripheralConnection:(id<GNCPeripheral>)peripheral {
[centralDelegate gnc_centralManager:self didDisconnectPeripheral:peripheral error:nil];
}
- (void)stopScan {
}
@@ -127,8 +127,9 @@ bool GattClient::SetCharacteristicSubscription(
return false;
}
// TODO(b/290385712): Implement.
void GattClient::Disconnect() {}
void GattClient::Disconnect() {
[gatt_client_ disconnect];
}
} // namespace apple
} // namespace nearby
@@ -145,9 +145,15 @@ void BleMedium::HandleAdvertisementFound(id<GNCPeripheral> peripheral,
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> BleMedium::StartScanning(
const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanningCallback callback) {
absl::MutexLock lock(&peripherals_mutex_);
CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid);
scanning_cb_ = std::move(callback);
// Clear the map of discovered peripherals only when we are starting a new scan. If we cleared the
// map every time we stopped a scan, we would not be able to connect to peripherals that we
// discovered in that scan session.
peripherals_.clear();
socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID];
[socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]];
@@ -171,9 +177,15 @@ std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> BleMedium::StartScannin
bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanCallback callback) {
absl::MutexLock lock(&peripherals_mutex_);
CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid);
scan_cb_ = std::move(callback);
// Clear the map of discovered peripherals only when we are starting a new scan. If we cleared the
// map every time we stopped a scan, we would not be able to connect to peripherals that we
// discovered in that scan session.
peripherals_.clear();
socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID];
[socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]];
@@ -13,6 +13,9 @@
// limitations under the License.
#include "internal/platform/implementation/apple/count_down_latch.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "internal/platform/exception.h"
namespace nearby {
namespace apple {
@@ -15,7 +15,10 @@
#ifndef PLATFORM_IMPL_APPLE_COUNT_DOWN_LATCH_H_
#define PLATFORM_IMPL_APPLE_COUNT_DOWN_LATCH_H_
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/count_down_latch.h"
namespace nearby {
@@ -14,7 +14,10 @@
#include "internal/platform/implementation/apple/count_down_latch.h"
#include <atomic>
#include "gtest/gtest.h"
#include "absl/time/time.h"
#include "thread/fiber/fiber.h"
namespace nearby {
@@ -56,11 +59,11 @@ TEST(CountDownLatchTest, LatchAwaitWithTimeoutCanExpire) {
auto response = latch.Await(absl::Milliseconds(100));
EXPECT_TRUE(response.ok());
EXPECT_FALSE(response.ok());
EXPECT_FALSE(response.result());
}
TEST(CountDownLatchTest, InitialCountZero_AwaitDoesNotBlock) {
TEST(CountDownLatchTest, InitialCountZeroAwaitDoesNotBlock) {
CountDownLatch latch(0);
auto response = latch.Await();
@@ -68,7 +71,7 @@ TEST(CountDownLatchTest, InitialCountZero_AwaitDoesNotBlock) {
EXPECT_TRUE(response.Ok());
}
TEST(CountDownLatchTest, InitialCountNegative_AwaitDoesNotBlock) {
TEST(CountDownLatchTest, InitialCountNegativeAwaitDoesNotBlock) {
CountDownLatch latch(-1);
auto response = latch.Await();
@@ -28,16 +28,13 @@ namespace apple {
class DeviceInfo : public api::DeviceInfo {
public:
std::optional<std::u16string> GetOsDeviceName() const override;
std::optional<std::string> GetOsDeviceName() const override;
api::DeviceInfo::DeviceType GetDeviceType() const override;
api::DeviceInfo::OsType GetOsType() const override;
std::optional<std::u16string> GetFullName() const override;
std::optional<std::u16string> GetGivenName() const override;
std::optional<std::u16string> GetLastName() const override;
std::optional<std::string> GetProfileUserName() const override;
std::optional<std::string> GetGivenName() const override;
std::optional<std::filesystem::path> GetDownloadPath() const override;
@@ -33,15 +33,15 @@
namespace nearby {
namespace apple {
std::optional<std::u16string> DeviceInfo::GetOsDeviceName() const {
std::optional<std::string> DeviceInfo::GetOsDeviceName() const {
#if TARGET_OS_IPHONE
NSString *name = UIDevice.currentDevice.name;
const char16_t *cName = (const char16_t *)[name cStringUsingEncoding:NSUTF16StringEncoding];
return std::u16string(cName);
const char *cName = (const char *)[name cStringUsingEncoding:NSUTF8StringEncoding];
return std::string(cName);
#elif TARGET_OS_OSX
NSString *name = NSHost.currentHost.localizedName;
const char16_t *cName = (const char16_t *)[name cStringUsingEncoding:NSUTF16StringEncoding];
return std::u16string(cName);
const char *cName = (const char *)[name cStringUsingEncoding:NSUTF8StringEncoding];
return std::string(cName);
#else
return std::nullopt;
#endif
@@ -78,10 +78,7 @@ api::DeviceInfo::OsType DeviceInfo::GetOsType() const {
#endif
}
std::optional<std::u16string> DeviceInfo::GetFullName() const { return std::nullopt; }
std::optional<std::u16string> DeviceInfo::GetGivenName() const { return std::nullopt; }
std::optional<std::u16string> DeviceInfo::GetLastName() const { return std::nullopt; }
std::optional<std::string> DeviceInfo::GetProfileUserName() const { return std::nullopt; }
std::optional<std::string> DeviceInfo::GetGivenName() const { return std::nullopt; }
std::optional<std::filesystem::path> DeviceInfo::GetDownloadPath() const {
NSFileManager *manager = [NSFileManager defaultManager];
@@ -1,65 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_APPLE_LOG_MESSAGE_H_
#define PLATFORM_IMPL_APPLE_LOG_MESSAGE_H_
#include <ostream>
#include <sstream>
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/log_message.h"
#include "GoogleToolboxForMac/GTMLogger.h"
namespace nearby {
namespace apple {
class LogStreamer final {
public:
explicit LogStreamer(GTMLoggerLevel severity, absl::string_view func);
~LogStreamer();
std::ostream& stream() { return stream_; }
private:
GTMLoggerLevel severity_;
std::string func_;
std::ostringstream stream_;
};
// Concrete LogMessage implementation
class LogMessage : public api::LogMessage {
public:
LogMessage(const char* file, int line, Severity severity);
~LogMessage() override = default;
LogMessage(const LogMessage&) = delete;
LogMessage& operator=(const LogMessage&) = delete;
void Print(const char* format, ...) override;
std::ostream& Stream() override;
private:
LogStreamer log_streamer_;
GTMLoggerLevel severity_;
std::string func_;
};
} // namespace apple
} // namespace nearby
#endif // PLATFORM_IMPL_APPLE_LOG_MESSAGE_H_
@@ -1,117 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/apple/log_message.h"
#include <ostream>
#include <string>
#include "internal/platform/implementation/log_message.h"
namespace nearby {
namespace apple {
api::LogMessage::Severity gMinLogSeverity = api::LogMessage::Severity::kInfo;
GTMLoggerLevel ConvertSeverity(api::LogMessage::Severity severity) {
switch (severity) {
case api::LogMessage::Severity::kVerbose:
return kGTMLoggerLevelDebug;
case api::LogMessage::Severity::kInfo:
return kGTMLoggerLevelInfo;
case api::LogMessage::Severity::kWarning:
return kGTMLoggerLevelInfo;
case api::LogMessage::Severity::kError:
return kGTMLoggerLevelError;
case api::LogMessage::Severity::kFatal:
return kGTMLoggerLevelAssert;
}
}
// GTMLogger expects a function name, but we only have file and line. So format the info as
// {basename(file)}:{line} and use that as the function name.
std::string ConvertFileAndLine(absl::string_view filepath, int line) {
size_t path = filepath.find_last_of('/');
if (path != filepath.npos) filepath.remove_prefix(path + 1);
return std::string(filepath) + ":" + std::to_string(line);
}
LogStreamer::LogStreamer(GTMLoggerLevel severity, absl::string_view func)
: severity_(severity), func_(func) {}
LogStreamer::~LogStreamer() {
switch (severity_) {
case kGTMLoggerLevelDebug:
[[GTMLogger sharedLogger] logFuncDebug:func_.c_str() msg:@"%@", @(stream_.str().c_str())];
break;
case kGTMLoggerLevelInfo:
[[GTMLogger sharedLogger] logFuncInfo:func_.c_str() msg:@"%@", @(stream_.str().c_str())];
break;
case kGTMLoggerLevelError:
[[GTMLogger sharedLogger] logFuncError:func_.c_str() msg:@"%@", @(stream_.str().c_str())];
break;
case kGTMLoggerLevelAssert:
[[GTMLogger sharedLogger] logFuncAssert:func_.c_str() msg:@"%@", @(stream_.str().c_str())];
break;
case kGTMLoggerLevelUnknown:
// no-op
break;
}
}
LogMessage::LogMessage(const char* file, int line, Severity severity)
: log_streamer_(ConvertSeverity(severity), ConvertFileAndLine(file, line)),
severity_(ConvertSeverity(severity)),
func_(ConvertFileAndLine(file, line)) {}
void LogMessage::Print(const char* format, ...) {
va_list ap;
va_start(ap, format);
NSString *msg = [[NSString alloc] initWithFormat:@(format) arguments:ap];
switch (severity_) {
case kGTMLoggerLevelDebug:
[[GTMLogger sharedLogger] logFuncDebug:func_.c_str() msg:@"%@", msg];
break;
case kGTMLoggerLevelInfo:
[[GTMLogger sharedLogger] logFuncInfo:func_.c_str() msg:@"%@", msg];
break;
case kGTMLoggerLevelError:
[[GTMLogger sharedLogger] logFuncError:func_.c_str() msg:@"%@", msg];
break;
case kGTMLoggerLevelAssert:
[[GTMLogger sharedLogger] logFuncAssert:func_.c_str() msg:@"%@", msg];
break;
case kGTMLoggerLevelUnknown:
// no-op
break;
}
va_end(ap);
}
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
} // namespace apple
namespace api {
// static
void LogMessage::SetMinLogSeverity(Severity severity) { apple::gMinLogSeverity = severity; }
// static
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
return severity >= apple::gMinLogSeverity;
}
} // namespace api
} // namespace nearby
@@ -26,7 +26,6 @@
#include "internal/platform/implementation/apple/condition_variable.h"
#include "internal/platform/implementation/apple/count_down_latch.h"
#include "internal/platform/implementation/apple/device_info.h"
#import "internal/platform/implementation/apple/log_message.h"
#import "internal/platform/implementation/apple/multi_thread_executor.h"
#include "internal/platform/implementation/apple/mutex.h"
#include "internal/platform/implementation/apple/preferences_manager.h"
@@ -135,11 +134,6 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(const std::
return shared::IOFile::CreateOutputFile(file_path);
}
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
const char* file, int line, LogMessage::Severity severity) {
return std::make_unique<apple::LogMessage>(file, line, severity);
}
// Java-like Executors
std::unique_ptr<SubmittableExecutor> ImplementationPlatform::CreateSingleThreadExecutor() {
return std::make_unique<apple::SingleThreadExecutor>();
@@ -228,7 +222,7 @@ absl::StatusOr<WebResponse> ImplementationPlatform::SendRequest(const WebRequest
[condition unlock];
if (blockResponse == nil) {
return absl::UnknownError([[blockError localizedDescription] UTF8String]);
return absl::FailedPreconditionError([[blockError localizedDescription] UTF8String]);
}
WebResponse webResponse;
+5 -3
View File
@@ -460,12 +460,14 @@ class BleMedium {
absl::AnyInvocable<void(BlePeripheral& peripheral,
BleAdvertisementData advertisement_data)>
advertisement_found_cb = [](BlePeripheral&, BleAdvertisementData) {};
absl::AnyInvocable<void(BlePeripheral& peripheral)>
advertisement_lost_cb = [](BlePeripheral&) {};
};
// Async interface for StartScanning.
// Result status will be passed to start_advertising_result callback.
// To stop advertising, invoke the stop_advertising callback in
// AdvertisingSession.
// Result status will be passed to start_scanning_result callback.
// To stop scanning, invoke the stop_scanning callback in
// ScanningSession.
virtual std::unique_ptr<ScanningSession> StartScanning(
const Uuid& service_uuid, TxPowerLevel tx_power_level,
ScanningCallback callback) = 0;
+16 -6
View File
@@ -15,12 +15,11 @@
#ifndef PLATFORM_API_CRYPTO_H_
#define PLATFORM_API_CRYPTO_H_
#include <stddef.h>
#include <stdint.h>
#include "absl/strings/string_view.h"
#ifdef NEARBY_CHROMIUM
#include "crypto/random.h"
#else
#include "internal/crypto_cros/random.h"
#endif
#include "absl/types/span.h"
#include "internal/platform/byte_array.h"
namespace nearby {
@@ -36,12 +35,23 @@ class Crypto {
static ByteArray Sha256(absl::string_view input);
};
// Fills the given buffer with |length| random bytes of cryptographically
// secure random numbers.
// |length| must be positive.
//
// TODO(crbug.com/40284755): Convert all callers in Nearby to use spans
// and remove this RandBytes overload.
void RandBytes(void *bytes, size_t length);
// Fills |bytes| with cryptographically-secure random bits.
void RandBytes(absl::Span<uint8_t> bytes);
// Creates an object of type T initialized with random data.
// This template should be used for simple data types: int, char, etc.
template <typename T>
T RandData() {
T data;
::crypto::RandBytes(&data, sizeof(data));
RandBytes(&data, sizeof(data));
return data;
}
@@ -41,15 +41,12 @@ class DeviceInfo {
virtual ~DeviceInfo() = default;
// Gets device name.
virtual std::optional<std::u16string> GetOsDeviceName() const = 0;
virtual std::optional<std::string> GetOsDeviceName() const = 0;
virtual DeviceType GetDeviceType() const = 0;
virtual OsType GetOsType() const = 0;
// Gets basic information of current user.
virtual std::optional<std::u16string> GetFullName() const = 0;
virtual std::optional<std::u16string> GetGivenName() const = 0;
virtual std::optional<std::u16string> GetLastName() const = 0;
virtual std::optional<std::string> GetProfileUserName() const = 0;
virtual std::optional<std::string> GetGivenName() const = 0;
// Gets known paths of current user.
virtual std::optional<std::filesystem::path> GetDownloadPath() const = 0;
+23 -25
View File
@@ -17,7 +17,6 @@ cc_library(
name = "types",
testonly = True,
srcs = [
"log_message.cc",
"preferences_manager.cc",
"scheduled_executor.cc",
"system_clock.cc",
@@ -27,7 +26,6 @@ cc_library(
"atomic_reference.h",
"condition_variable.h",
"device_info.h",
"log_message.h",
"multi_thread_executor.h",
"mutex.h",
"preferences_manager.h",
@@ -35,17 +33,12 @@ cc_library(
"single_thread_executor.h",
"timer.h",
],
visibility = [
"//internal/test:__subpackages__",
"//location/nearby/cpp:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
],
visibility = ["//visibility:private"],
deps = [
":preferences_repository",
"//internal/platform:base",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform:util",
"//internal/platform/implementation:types",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:posix_mutex",
@@ -53,11 +46,12 @@ cc_library(
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:btree",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/log:log_streamer",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
"@com_google_absl//absl/types:span",
"@com_google_glog//:glog",
"@com_google_nisaba//nisaba/port:thread_pool",
"@nlohmann_json//:json",
],
@@ -73,7 +67,6 @@ cc_library(
"bluetooth_adapter.cc",
"bluetooth_classic.cc",
"credential_storage_impl.cc",
"webrtc.cc",
"wifi_direct.cc",
"wifi_hotspot.cc",
"wifi_lan.cc",
@@ -85,7 +78,6 @@ cc_library(
"bluetooth_classic.h",
"credential_storage_impl.h",
"socket_base.h",
"webrtc.h",
"wifi.h",
"wifi_direct.h",
"wifi_hotspot.h",
@@ -94,6 +86,16 @@ cc_library(
visibility = ["//visibility:private"],
deps = [
":types",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform:uuid",
"//internal/platform/implementation:comm",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/proto:credential_cc_proto",
# TODO: Support WebRTC
"//third_party/webrtc/files/stable/webrtc/api:scoped_refptr",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
@@ -104,17 +106,7 @@ cc_library(
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:test_util",
"//internal/platform:types",
"//internal/platform:uuid",
"//internal/platform/implementation:comm",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/proto:credential_cc_proto",
# TODO: Support WebRTC
"//third_party/webrtc/files/stable/webrtc/api/task_queue:default_task_queue_factory",
"//third_party/webrtc/files/stable/webrtc/rtc_base:checks",
"@com_google_absl//absl/time",
],
)
@@ -124,7 +116,7 @@ cc_library(
srcs = [
"crypto.cc",
],
visibility = ["//visibility:private"],
visibility = ["//internal/platform/implementation:__subpackages__"],
deps = [
"//internal/platform:base",
"//internal/platform/implementation:types",
@@ -140,11 +132,13 @@ cc_library(
srcs = [
"platform.cc",
],
defines = ["NO_WEBRTC"],
visibility = [
"//connections:__subpackages__",
"//fastpair:__subpackages__",
"//internal/account:__subpackages__",
"//internal/auth:__subpackages__",
"//internal/crypto:__subpackages__",
"//internal/data:__subpackages__",
"//internal/flags:__subpackages__",
"//internal/network:__subpackages__",
@@ -154,24 +148,28 @@ cc_library(
"//internal/test:__subpackages__",
"//internal/weave:__subpackages__",
"//location/nearby/cpp:__subpackages__",
"//location/nearby/sharing/sdk:__subpackages__",
"//presence:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
"//sharing:__subpackages__",
],
deps = [
":comm",
":crypto", # build_cleaner: keep
":types",
"//file/base:path",
"//internal/platform:base",
"//internal/platform:test_util",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:file",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/time",
"@com_google_nisaba//nisaba/port:thread_pool",
],
)
+25 -25
View File
@@ -21,6 +21,7 @@
#include "absl/functional/any_invocable.h"
#include "absl/log/check.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
@@ -64,8 +65,8 @@ bool BleServerSocket::Connect(BleSocket& socket) {
absl::MutexLock lock(&mutex_);
if (closed_) return false;
if (socket.IsConnected()) {
NEARBY_LOG(ERROR,
"Failed to connect to Ble server socket: already connected");
NEARBY_LOGS(ERROR)
<< "Failed to connect to Ble server socket: already connected";
return true; // already connected.
}
// add client socket to the pending list
@@ -126,8 +127,8 @@ BleMedium::~BleMedium() {
StopScanning(scanning_info_.service_id);
accept_loops_runner_.Shutdown();
NEARBY_LOG(INFO, "BleMedium dtor advertising_accept_thread_running_ = %d",
acceptance_thread_running_.load());
NEARBY_LOGS(INFO) << "BleMedium dtor advertising_accept_thread_running_ = "
<< acceptance_thread_running_.load();
// If acceptance thread is still running, wait to finish.
if (acceptance_thread_running_) {
while (acceptance_thread_running_) {
@@ -142,10 +143,11 @@ bool BleMedium::StartAdvertising(
const std::string& service_id, const ByteArray& advertisement_bytes,
const std::string& fast_advertisement_service_uuid) {
NEARBY_LOGS(INFO) << "G3 Ble StartAdvertising: service_id=" << service_id
<< ", advertisement bytes=" << advertisement_bytes.data()
<< ", advertisement bytes="
<< absl::BytesToHexString(std::string(advertisement_bytes))
<< "(" << advertisement_bytes.size() << "),"
<< " fast advertisement service uuid="
<< fast_advertisement_service_uuid;
<< ", fast advertisement service uuid="
<< absl::BytesToHexString(fast_advertisement_service_uuid);
auto& env = MediumEnvironment::Instance();
auto& peripheral = adapter_->GetPeripheral();
peripheral.SetAdvertisementBytes(service_id, advertisement_bytes);
@@ -159,14 +161,13 @@ bool BleMedium::StartAdvertising(
acceptance_thread_running_.exchange(true);
accept_loops_runner_.Execute([&env, this, service_id]() mutable {
if (!accept_loops_runner_.InShutdown()) {
while (true) {
auto client_socket =
server_socket_->Accept(&(this->adapter_->GetPeripheral()));
if (client_socket == nullptr) break;
env.CallBleAcceptedConnectionCallback(*this, *(client_socket.release()),
service_id);
}
while (true) {
if (accept_loops_runner_.InShutdown()) break;
auto client_socket =
server_socket_->Accept(&(this->adapter_->GetPeripheral()));
if (client_socket == nullptr) break;
env.CallBleAcceptedConnectionCallback(*this, *(client_socket.release()),
service_id);
}
acceptance_thread_running_.exchange(false);
});
@@ -262,11 +263,10 @@ bool BleMedium::StopAcceptingConnections(const std::string& service_id) {
std::unique_ptr<api::BleSocket> BleMedium::Connect(
api::BlePeripheral& remote_peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) {
NEARBY_LOG(INFO,
"G3 Ble Connect [self]: medium=%p, adapter=%p, peripheral=%p, "
"service_id=%s",
this, &GetAdapter(), &GetAdapter().GetPeripheral(),
service_id.c_str());
NEARBY_LOGS(INFO) << "G3 Ble Connect [self]: medium=" << this
<< ", adapter=" << &GetAdapter()
<< ", peripheral=" << &GetAdapter().GetPeripheral()
<< ", service_id=" << service_id;
// First, find an instance of remote medium, that exposed this peripheral.
auto& adapter = static_cast<BlePeripheral&>(remote_peripheral).GetAdapter();
auto* medium = static_cast<BleMedium*>(adapter.GetBleMedium());
@@ -274,10 +274,10 @@ std::unique_ptr<api::BleSocket> BleMedium::Connect(
if (!medium) return {}; // Can't find medium. Bail out.
BleServerSocket* remote_server_socket = nullptr;
NEARBY_LOG(INFO,
"G3 Ble Connect [peer]: medium=%p, adapter=%p, peripheral=%p, "
"service_id=%s",
medium, &adapter, &remote_peripheral, service_id.c_str());
NEARBY_LOGS(INFO) << "G3 Ble Connect [peer]: medium=" << medium
<< ", adapter=" << &adapter
<< ", peripheral=" << &remote_peripheral
<< ", service_id=" << service_id;
// Then, find our server socket context in this medium.
{
absl::MutexLock medium_lock(&medium->mutex_);
@@ -312,7 +312,7 @@ std::unique_ptr<api::BleSocket> BleMedium::Connect(
return {};
}
NEARBY_LOG(INFO, "G3 Ble Connect: connected: socket=%p", socket.get());
NEARBY_LOGS(INFO) << "G3 Ble Connect: connected: socket=" << socket.get();
return socket;
}
+1 -1
View File
@@ -184,7 +184,7 @@ class BleMedium : public api::BleMedium {
std::atomic_bool acceptance_thread_running_ = false;
// A thread pool dedicated to wait to complete the accept_loops_runner_.
MultiThreadExecutor close_accept_loops_runner_{kMaxConcurrentAcceptLoops};
MultiThreadExecutor close_accept_loops_runner_{1};
// A server socket is established when start advertising.
std::unique_ptr<BleServerSocket> server_socket_;
@@ -160,6 +160,8 @@ Exception BleV2ServerSocket::DoClose() {
BleV2Medium::BleV2Medium(api::BluetoothAdapter& adapter)
: adapter_(static_cast<BluetoothAdapter*>(&adapter)) {
adapter_->SetBleV2Medium(this);
is_extended_advertisements_available_ =
MediumEnvironment::Instance().IsBleExtendedAdvertisementsAvailable();
MediumEnvironment::Instance().RegisterBleV2Medium(*this, &peripheral_);
}
@@ -180,7 +182,7 @@ bool BleV2Medium::StartAdvertising(
<< TxPowerLevelToName(advertise_parameters.tx_power_level)
<< ", is_connectable=" << advertise_parameters.is_connectable;
if (advertising_data.is_extended_advertisement &&
!is_support_extended_advertisement_) {
!IsExtendedAdvertisementsAvailable()) {
NEARBY_LOGS(INFO)
<< "G3 Ble StartAdvertising does not support extended advertisement";
return false;
@@ -215,7 +217,7 @@ std::unique_ptr<BleV2Medium::AdvertisingSession> BleV2Medium::StartAdvertising(
<< TxPowerLevelToName(advertise_parameters.tx_power_level)
<< ", is_connectable=" << advertise_parameters.is_connectable;
if (advertising_data.is_extended_advertisement &&
!is_support_extended_advertisement_) {
!IsExtendedAdvertisementsAvailable()) {
NEARBY_LOGS(INFO)
<< "G3 Ble StartAdvertising does not support extended advertisement";
return nullptr;
@@ -326,7 +328,7 @@ std::unique_ptr<api::ble_v2::GattClient> BleV2Medium::ConnectToGattServer(
}
bool BleV2Medium::IsExtendedAdvertisementsAvailable() {
return is_support_extended_advertisement_;
return is_extended_advertisements_available_;
}
bool BleV2Medium::GetRemotePeripheral(const std::string& mac_address,
+12 -4
View File
@@ -23,15 +23,24 @@
#include <utility>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/borrowable.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/g3/bluetooth_adapter.h"
#include "internal/platform/implementation/g3/socket_base.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/prng.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/uuid.h"
namespace nearby {
@@ -323,8 +332,7 @@ class BleV2Medium : public api::ble_v2::BleMedium {
ABSL_GUARDED_BY(mutex_);
absl::flat_hash_set<std::pair<Uuid, std::uint32_t>>
scanning_internal_session_ids_ ABSL_GUARDED_BY(mutex_);
// TODO(edwinwu): Adds extended advertisement for testing.
bool is_support_extended_advertisement_ = false;
bool is_extended_advertisements_available_ = false;
};
} // namespace g3
@@ -217,6 +217,16 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
<< service_uuid;
return {};
}
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(ERROR)
<< "G3 Bluetooth Connect: Has been cancelled after connected: "
"service_uuid="
<< service_uuid;
socket->Close();
return {};
}
NEARBY_LOGS(INFO) << "G3 ConnectToService: connected: socket="
<< socket.get();
return socket;
@@ -70,7 +70,6 @@ void CredentialStorageImpl::SaveCredentials(
NEARBY_LOGS(INFO) << "G3 Save Private Credentials for account: ["
<< account_name << "], manager app ID:[" << manager_app_id
<< "]";
absl::MutexLock lock(&private_mutex_);
SaveLocalCredentialsLocked(manager_app_id, account_name,
private_credentials);
}
@@ -83,7 +82,6 @@ void CredentialStorageImpl::SaveCredentials(
NEARBY_LOGS(INFO) << "G3 Save Public Credentials for account: ["
<< account_name << "], manager app ID:[" << manager_app_id
<< "]";
absl::MutexLock lock(&public_mutex_);
PublicCredentialKey key = CreatePublicCredentialKey(
manager_app_id, account_name, public_credential_type);
auto public_result =
@@ -116,7 +114,6 @@ void CredentialStorageImpl::UpdateLocalCredential(
NEARBY_LOGS(INFO) << "G3 Update Private Credential for for account: ["
<< account_name << "], manager app ID:[" << manager_app_id
<< "]";
absl::MutexLock lock(&private_mutex_);
absl::StatusOr<std::vector<LocalCredential>> credentials =
GetLocalCredentialsLocked(CredentialSelector{
.manager_app_id = std::string(manager_app_id),
@@ -126,10 +123,9 @@ void CredentialStorageImpl::UpdateLocalCredential(
NEARBY_LOGS(WARNING) << credentials.status();
credentials = std::vector<LocalCredential>();
}
auto it = std::find_if(credentials->begin(), credentials->end(),
[&](const LocalCredential& a) {
return a.secret_id() == credential.secret_id();
});
auto it = std::find_if(
credentials->begin(), credentials->end(),
[&](const LocalCredential& a) { return a.id() == credential.id(); });
if (it == credentials->end()) {
credentials->push_back(std::move(credential));
} else {
@@ -143,7 +139,6 @@ void CredentialStorageImpl::GetLocalCredentials(
const CredentialSelector& credential_selector,
GetLocalCredentialsResultCallback callback) {
NEARBY_LOGS(INFO) << "G3 Get Private Credentials for " << credential_selector;
absl::MutexLock lock(&private_mutex_);
std::move(callback.credentials_fetched_cb)(
GetLocalCredentialsLocked(credential_selector));
}
@@ -174,7 +169,6 @@ void CredentialStorageImpl::GetPublicCredentials(
PublicCredentialType public_credential_type,
GetPublicCredentialsResultCallback callback) {
NEARBY_LOGS(INFO) << "G3 Get Public Credentials for " << credential_selector;
absl::MutexLock lock(&public_mutex_);
PublicCredentialKey key = CreatePublicCredentialKey(
credential_selector.manager_app_id, credential_selector.account_name,
public_credential_type);
@@ -30,8 +30,8 @@ namespace g3 {
class DeviceInfo : public api::DeviceInfo {
public:
std::optional<std::u16string> GetOsDeviceName() const override {
return u"Windows";
std::optional<std::string> GetOsDeviceName() const override {
return "Windows";
}
api::DeviceInfo::DeviceType GetDeviceType() const override {
@@ -42,16 +42,7 @@ class DeviceInfo : public api::DeviceInfo {
return api::DeviceInfo::OsType::kChromeOs;
}
std::optional<std::u16string> GetFullName() const override {
return u"nearby";
}
std::optional<std::u16string> GetGivenName() const override {
return u"nearby";
}
std::optional<std::u16string> GetLastName() const override {
return u"nearby";
}
std::optional<std::string> GetProfileUserName() const override {
std::optional<std::string> GetGivenName() const override {
return "nearby";
}
@@ -1,84 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/g3/log_message.h"
#include <algorithm>
#include <cstdio>
namespace nearby {
namespace g3 {
namespace {
// This is a partial copy of base::StringAppendV for OSS compilation.
void NearbyStringAppendV(std::string* dst, const char* format, va_list ap) {
// Fixed size buffer 1024 should be big enough.
static const int kSpaceLength = 1024;
char space[kSpaceLength];
int result = vsnprintf(space, kSpaceLength, format, ap);
va_end(ap);
dst->append(space, result);
}
} // namespace
api::LogMessage::Severity g_min_log_severity = api::LogMessage::Severity::kInfo;
inline absl::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) {
switch (severity) {
// api::LogMessage::Severity kVerbose and kInfo is mapped to
// absl::LogSeverity kInfo since absl::LogSeverity doesn't have kVerbose
// level.
case api::LogMessage::Severity::kVerbose:
case api::LogMessage::Severity::kInfo:
return absl::LogSeverity::kInfo;
case api::LogMessage::Severity::kWarning:
return absl::LogSeverity::kWarning;
case api::LogMessage::Severity::kError:
return absl::LogSeverity::kError;
case api::LogMessage::Severity::kFatal:
return absl::LogSeverity::kFatal;
}
}
LogMessage::LogMessage(const char* file, int line, Severity severity)
: log_streamer_(ConvertSeverity(severity), file, line) {}
LogMessage::~LogMessage() = default;
void LogMessage::Print(const char* format, ...) {
va_list ap;
va_start(ap, format);
std::string result;
NearbyStringAppendV(&result, format, ap);
log_streamer_.stream() << result;
va_end(ap);
}
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
} // namespace g3
namespace api {
void LogMessage::SetMinLogSeverity(Severity severity) {
g3::g_min_log_severity = severity;
}
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
return severity >= g3::g_min_log_severity;
}
} // namespace api
} // namespace nearby
@@ -15,28 +15,45 @@
#include "internal/platform/implementation/platform.h"
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include "file/base/path.h"
#include "absl/base/attributes.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/atomic_boolean.h"
#include "internal/platform/implementation/atomic_reference.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/condition_variable.h"
#include "internal/platform/implementation/count_down_latch.h"
#include "internal/platform/implementation/credential_storage.h"
#include "internal/platform/implementation/device_info.h"
#include "internal/platform/implementation/http_loader.h"
#include "internal/platform/implementation/input_file.h"
#include "internal/platform/implementation/log_message.h"
#include "internal/platform/implementation/mutex.h"
#include "internal/platform/implementation/output_file.h"
#include "internal/platform/implementation/preferences_manager.h"
#include "internal/platform/implementation/scheduled_executor.h"
#include "internal/platform/implementation/server_sync.h"
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "internal/platform/implementation/submittable_executor.h"
#include "internal/platform/implementation/timer.h"
#include "internal/platform/implementation/wifi_direct.h"
#include "internal/platform/implementation/wifi_hotspot.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/os_name.h"
#include "internal/platform/payload_id.h"
#include "thread/thread.h"
#ifndef NO_WEBRTC
#include "internal/platform/implementation/g3/webrtc.h"
#include "internal/platform/implementation/webrtc.h"
@@ -50,7 +67,6 @@
#include "internal/platform/implementation/g3/condition_variable.h"
#include "internal/platform/implementation/g3/credential_storage_impl.h"
#include "internal/platform/implementation/g3/device_info.h"
#include "internal/platform/implementation/g3/log_message.h"
#include "internal/platform/implementation/g3/multi_thread_executor.h"
#include "internal/platform/implementation/g3/mutex.h"
#include "internal/platform/implementation/g3/preferences_manager.h"
@@ -70,14 +86,12 @@ namespace api {
std::string ImplementationPlatform::GetCustomSavePath(
const std::string& parent_folder, const std::string& file_name) {
return file::JoinPath(parent_folder, file_name);
return absl::StrCat(parent_folder, file_name);
}
std::string ImplementationPlatform::GetDownloadPath(
const std::string& parent_folder, const std::string& file_name) {
std::string fullPath("/tmp");
return file::JoinPath("/tmp", file_name);
return absl::StrCat("/tmp/", file_name);
}
OSName ImplementationPlatform::GetCurrentOS() { return OSName::kLinux; }
@@ -153,7 +167,7 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
const char* file, int line, LogMessage::Severity severity) {
return std::make_unique<g3::LogMessage>(file, line, severity);
return nullptr;
}
std::unique_ptr<BluetoothClassicMedium>
@@ -16,8 +16,12 @@
#include <atomic>
#include <memory>
#include <optional>
#include <utility>
#include "absl/strings/str_format.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/cancelable.h"
#include "internal/platform/medium_environment.h"
#include "internal/platform/runnable.h"
@@ -32,13 +36,14 @@ class ScheduledCancelable : public api::Cancelable {
public:
bool Cancel() override {
Status expected = kNotRun;
while (expected == kNotRun) {
if (status_.compare_exchange_strong(expected, kCanceled)) {
return true;
}
if (status_.compare_exchange_strong(expected, kCanceled)) {
return true;
}
return false;
}
bool IsCanceled() const { return status_ == kCanceled; }
bool MarkExecuted() {
Status expected = kNotRun;
while (expected == kNotRun) {
@@ -61,7 +66,7 @@ class ScheduledCancelable : public api::Cancelable {
} // namespace
ScheduledExecutor::ScheduledExecutor() {
absl::optional<FakeClock*> fake_clock =
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
if (fake_clock.has_value()) {
name_ = absl::StrFormat("G3 scheduled executor %p", this);
@@ -70,7 +75,7 @@ ScheduledExecutor::ScheduledExecutor() {
}
ScheduledExecutor::~ScheduledExecutor() {
absl::optional<FakeClock*> fake_clock =
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
if (fake_clock.has_value()) {
(*fake_clock)->RemoveObserver(name_);
@@ -86,11 +91,12 @@ std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(
}
Runnable task = [this, scheduled_cancelable,
runnable = std::move(runnable)]() mutable {
if (!executor_.InShutdown() && scheduled_cancelable->MarkExecuted()) {
if (!executor_.InShutdown() && !scheduled_cancelable->IsCanceled() &&
scheduled_cancelable->MarkExecuted()) {
runnable();
}
};
absl::optional<FakeClock*> fake_clock =
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
if (fake_clock.has_value()) {
absl::Time trigger_time = (*fake_clock)->Now() + delay;
@@ -104,7 +110,7 @@ std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(
}
void ScheduledExecutor::RunReadyTasks() {
absl::optional<FakeClock*> fake_clock =
std::optional<FakeClock*> fake_clock =
MediumEnvironment::Instance().GetSimulatedClock();
if (executor_.InShutdown()) {
return;
+24 -3
View File
@@ -15,9 +15,17 @@
#include "internal/platform/implementation/g3/webrtc.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/webrtc.h"
#include "internal/platform/medium_environment.h"
#include "webrtc/api/peer_connection_interface.h"
#include "webrtc/api/scoped_refptr.h"
#include "webrtc/api/task_queue/default_task_queue_factory.h"
#include "webrtc/rtc_base/checks.h"
@@ -56,6 +64,12 @@ const std::string WebRtcMedium::GetDefaultCountryCode() { return "US"; }
void WebRtcMedium::CreatePeerConnection(
webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) {
CreatePeerConnection(std::nullopt, observer, std::move(callback));
}
void WebRtcMedium::CreatePeerConnection(
std::optional<webrtc::PeerConnectionFactoryInterface::Options> options,
webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) {
auto& env = MediumEnvironment::Instance();
if (!env.GetUseValidPeerConnection()) {
callback(nullptr);
@@ -75,10 +89,17 @@ void WebRtcMedium::CreatePeerConnection(
webrtc::CreateDefaultTaskQueueFactory();
factory_dependencies.signaling_thread = signaling_thread.release();
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
peer_connection_factory = webrtc::CreateModularPeerConnectionFactory(
std::move(factory_dependencies));
RTC_CHECK(peer_connection_factory != nullptr)
<< "Failed to create peer connection factory";
if (options.has_value()) {
peer_connection_factory->SetOptions(options.value());
}
auto peer_connection_or_error =
webrtc::CreateModularPeerConnectionFactory(
std::move(factory_dependencies))
->CreatePeerConnectionOrError(rtc_config, std::move(dependencies));
peer_connection_factory->CreatePeerConnectionOrError(
rtc_config, std::move(dependencies));
RTC_CHECK(peer_connection_or_error.ok())
<< "Failed to create peer connection";
@@ -16,8 +16,11 @@
#define PLATFORM_IMPL_G3_WEBRTC_H_
#include <memory>
#include <optional>
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/webrtc.h"
#include "internal/platform/implementation/g3/single_thread_executor.h"
#include "webrtc/api/peer_connection_interface.h"
@@ -63,6 +66,13 @@ class WebRtcMedium : public api::WebRtcMedium {
void CreatePeerConnection(webrtc::PeerConnectionObserver* observer,
PeerConnectionCallback callback) override;
// Creates and returns a new webrtc::PeerConnectionInterface object via
// |callback| with |PeerConnectionFactoryInterface::Options|.
void CreatePeerConnection(
std::optional<webrtc::PeerConnectionFactoryInterface::Options> options,
webrtc::PeerConnectionObserver* observer,
PeerConnectionCallback callback) override;
// Returns a signaling messenger for sending WebRTC signaling messages.
std::unique_ptr<api::WebRtcSignalingMessenger> GetSignalingMessenger(
absl::string_view self_id,
+13 -4
View File
@@ -13,6 +13,18 @@
# limitations under the License.
licenses(["notice"])
cc_library(
name = "crypto",
srcs = [
"crypto.cc",
],
visibility = ["//internal/platform/implementation:__subpackages__"],
deps = [
"@boringssl//:crypto",
"@com_google_absl//absl/types:span",
],
)
cc_library(
name = "posix_mutex",
srcs = [
@@ -45,10 +57,7 @@ cc_library(
name = "file",
srcs = ["file.cc"],
hdrs = ["file.h"],
visibility = [
"//connections/implementation:__subpackages__",
"//internal/platform/implementation:__subpackages__",
],
visibility = ["//internal/platform/implementation:__subpackages__"],
deps = [
"//internal/platform:base",
"//internal/platform/implementation:types",
@@ -1,4 +1,4 @@
// Copyright 2020 Google LLC
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,31 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#define PLATFORM_IMPL_G3_LOG_MESSAGE_H_
#include <stddef.h>
#include <stdint.h>
#include "glog/logging.h"
#include "internal/platform/implementation/log_message.h"
#include "absl/types/span.h"
#include <openssl/rand.h>
namespace nearby {
namespace g3 {
// See documentation in
// cpp/platform/api/log_message.h
class LogMessage : public api::LogMessage {
public:
LogMessage(const char* file, int line, Severity severity);
~LogMessage() override;
void RandBytes(void* bytes, size_t length) {
RAND_bytes(reinterpret_cast<uint8_t*>(bytes), length);
}
void Print(const char* format, ...) override;
void RandBytes(absl::Span<uint8_t> bytes) {
RAND_bytes(bytes.data(), bytes.size());
}
std::ostream& Stream() override;
private:
google::LogMessage log_streamer_;
};
} // namespace g3
} // namespace nearby
#endif // PLATFORM_IMPL_G3_LOG_MESSAGE_H_
@@ -14,7 +14,6 @@
#include "internal/platform/implementation/shared/file.h"
#include <algorithm>
#include <cstddef>
#include <ios>
#include <memory>
@@ -37,7 +36,7 @@ IOFile::IOFile(const absl::string_view file_path, size_t size)
: file_(std::string(file_path.data(), file_path.size()),
std::ios::binary | std::ios::in | std::ios::ate),
path_(file_path),
total_size_(file_.tellg()) {
total_size_(size) {
file_.seekg(0);
}
@@ -18,8 +18,10 @@
#ifndef NO_WEBRTC
#include <memory>
#include <optional>
#include <string>
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "internal/platform/byte_array.h"
@@ -60,6 +62,13 @@ class WebRtcMedium {
virtual void CreatePeerConnection(webrtc::PeerConnectionObserver* observer,
PeerConnectionCallback callback) = 0;
// Creates and returns a new webrtc::PeerConnectionInterface object via
// |callback| with |PeerConnectionFactoryInterface::Options|.
virtual void CreatePeerConnection(
std::optional<webrtc::PeerConnectionFactoryInterface::Options> options,
webrtc::PeerConnectionObserver* observer,
PeerConnectionCallback callback) = 0;
// Returns a signaling messenger for sending WebRTC signaling messages.
virtual std::unique_ptr<WebRtcSignalingMessenger> GetSignalingMessenger(
absl::string_view self_id,
+5 -4
View File
@@ -17,6 +17,7 @@
#include <string>
#include "absl/functional/any_invocable.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/listeners.h"
@@ -99,10 +100,10 @@ class WifiLanMedium {
// Callback that is invoked when a discovered service is found or lost.
struct DiscoveredServiceCallback {
absl::AnyInvocable<void(NsdServiceInfo service_info)>
service_discovered_cb = DefaultCallback<NsdServiceInfo>();
absl::AnyInvocable<void(NsdServiceInfo service_info)> service_lost_cb =
DefaultCallback<NsdServiceInfo>();
absl::AnyInvocable<void(const NsdServiceInfo& service_info)>
service_discovered_cb = DefaultCallback<const NsdServiceInfo&>();
absl::AnyInvocable<void(const NsdServiceInfo& service_info)>
service_lost_cb = DefaultCallback<const NsdServiceInfo&>();
};
// Starts the discovery of nearby WifiLan services.
@@ -0,0 +1,130 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/wifi_utils.h"
#include <string>
#include <vector>
#include "absl/strings/numbers.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
namespace nearby {
// Utility function to convert channel number to frequency in MHz
// @param channel to convert
// @return center frequency in Mhz of the channel, return "kUnspecified" if no
// match
// Add band support later
int WifiUtils::ConvertChannelToFrequencyMhz(int channel, WifiBandType band) {
if (band == WifiBandType::kUnknown || band == WifiBandType::kBand24Ghz ||
band == WifiBandType::kBand5Ghz) {
if (channel == 14) {
return 2484;
} else if (channel >= kBand24GhzFirstChNum &&
channel <= kBand24GhzLastChNum) {
return ((channel - kBand24GhzFirstChNum) * 5) + kBand24GhzStartFreqMhz;
} else if (channel >= kBand5GhzFirstChNum &&
channel <= kBand5GhzLastChNum) {
return ((channel - kBand5GhzFirstChNum) * 5) + kBand5GhzStartFreqMhz;
} else {
return kUnspecified;
}
}
if (band == WifiBandType::kBand6Ghz) {
if (channel >= kBand6GhzFirstChNum && channel <= kBand6GhzLastChNum) {
if (channel == 2) {
return kBand6GhzOpClass136Ch2FreqMhz;
}
return ((channel - kBand6GhzFirstChNum) * 5) + kBand6GhzStartFreqMhz;
} else {
return kUnspecified;
}
}
if (band == WifiBandType::kBand60Ghz) {
if (channel >= kBand60GhzFirstChNum && channel <= kBand60GhzLastChNum) {
return ((channel - kBand60GhzFirstChNum) * 2160) + kBand60GhzStartFreqMhz;
} else {
return kUnspecified;
}
}
return kUnspecified;
}
// Utility function to convert frequency in MHz to channel number
// @param freqMhz frequency in MHz
// @return channel number associated with given frequency, return "kUnspecified"
// if no match
int WifiUtils::ConvertFrequencyMhzToChannel(int freq_mhz) {
// Special case
if (freq_mhz == kBand24GhzEndFreqMhz) {
return 14;
} else if (freq_mhz >= kBand24GhzStartFreqMhz &&
freq_mhz <= kBand24GhzEndFreqMhz) {
return (freq_mhz - kBand24GhzStartFreqMhz) / 5 + kBand24GhzFirstChNum;
} else if (freq_mhz >= kBand5GhzStartFreqMhz &&
freq_mhz <= kBand5GhzEndFreqMhz) {
return (freq_mhz - kBand5GhzStartFreqMhz) / 5 + kBand5GhzFirstChNum;
} else if (freq_mhz >= kBand6GhzStartFreqMhz &&
freq_mhz <= kBand6GhzEndFreqMhz) {
if (freq_mhz == kBand6GhzOpClass136Ch2FreqMhz) {
return 2;
}
return (freq_mhz - kBand6GhzStartFreqMhz) / 5 + kBand6GhzFirstChNum;
} else if (freq_mhz >= kBand60GhzStartFreqMhz &&
freq_mhz <= kBand60GhzEndFreqMhz) {
return (freq_mhz - kBand60GhzStartFreqMhz) / 2160 + kBand60GhzFirstChNum;
}
return kUnspecified;
}
// Function to validate an IP address
bool WifiUtils::ValidateIPV4(std::string ipv4) {
int result;
// split the string into tokens
std::vector<absl::string_view> list = absl::StrSplit(ipv4, '.');
// if the token size is not equal to four
if (list.size() != 4) {
return false;
}
// validate each token
for (absl::string_view str : list) {
// verify that the string is a number or not, and the numbers are in the
// valid range
if (!absl::SimpleAtoi(str, &result)) return false;
if (result > 255 || result < 0) return false;
}
return true;
}
std::string WifiUtils::GetHumanReadableIpAddress(
absl::string_view binary_address) {
std::vector<std::string> parts;
for (unsigned int b : binary_address) {
parts.push_back(absl::StrFormat("%d", b));
}
return absl::StrJoin(parts, ".");
}
} // namespace nearby
@@ -0,0 +1,61 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_PUBLIC_WIFI_UTILS_H_
#define PLATFORM_PUBLIC_WIFI_UTILS_H_
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/wifi.h"
namespace nearby {
using ::nearby::api::WifiBandType;
class WifiUtils {
public:
static constexpr int kUnspecified = -1;
static constexpr int kBand24GhzFirstChNum = 1;
static constexpr int kBand24GhzLastChNum = 14;
static constexpr int kBand24GhzStartFreqMhz = 2412;
static constexpr int kBand24GhzEndFreqMhz = 2484;
static constexpr int kBand5GhzFirstChNum = 32;
static constexpr int kBand5GhzLastChNum = 177;
static constexpr int kBand5GhzStartFreqMhz = 5160;
static constexpr int kBand5GhzEndFreqMhz = 5885;
static constexpr int kBand6GhzFirstChNum = 1;
static constexpr int kBand6GhzLastChNum = 233;
static constexpr int kBand6GhzStartFreqMhz = 5955;
static constexpr int kBand6GhzEndFreqMhz = 7115;
static constexpr int kBand6GhzPscStartMhz = 5975;
static constexpr int kBand6GhzPscStepSizeMhz = 80;
static constexpr int kBand6GhzOpClass136Ch2FreqMhz = 5935;
static constexpr int kBand60GhzFirstChNum = 1;
static constexpr int kBand60GhzLastChNum = 6;
static constexpr int kBand60GhzStartFreqMhz = 58320;
static constexpr int kBand60GhzEndFreqMhz = 70200;
static int ConvertChannelToFrequencyMhz(int channel, WifiBandType band_type);
static int ConvertFrequencyMhzToChannel(int freq_mhz);
static bool ValidateIPV4(std::string ipv4);
// Converts an IP address from binary format for human readable.
static std::string GetHumanReadableIpAddress(
absl::string_view binary_address);
};
} // namespace nearby
#endif // PLATFORM_PUBLIC_WIFI_UTILS_H_
@@ -0,0 +1,102 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/wifi_utils.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/strings/escaping.h"
namespace nearby {
namespace {
constexpr int kChan6Num_2G = 9;
constexpr int kChan6NumFreq_2G = 2452;
constexpr int kChan48Num_5G = 48;
constexpr int kChan48NumFreq_5G = 5240;
constexpr int kChan69Num_6G = 69;
constexpr int kChan69NumFreq_6G = 6295;
constexpr int kChan4Num_60G = 4;
constexpr int kChan4NumFreq_60G = 64800;
constexpr int kChan20Num_2G_NotExist = 20;
constexpr int kChan180Num_5G_NotExist = 180;
constexpr int kChan0Num_6G_NotExist = 0;
constexpr int kChan30Num_60G_NotExist = 30;
constexpr int kFreqNotExist = 1002;
TEST(WifiUtilsTest, ConvertChannelToFrequency) {
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan6Num_2G,
WifiBandType::kUnknown),
kChan6NumFreq_2G);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan6Num_2G,
WifiBandType::kBand24Ghz),
kChan6NumFreq_2G);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan48Num_5G,
WifiBandType::kBand5Ghz),
kChan48NumFreq_5G);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan69Num_6G,
WifiBandType::kBand6Ghz),
kChan69NumFreq_6G);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan4Num_60G,
WifiBandType::kBand60Ghz),
kChan4NumFreq_60G);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan20Num_2G_NotExist,
WifiBandType::kBand24Ghz),
WifiUtils::kUnspecified);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan180Num_5G_NotExist,
WifiBandType::kBand5Ghz),
WifiUtils::kUnspecified);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan0Num_6G_NotExist,
WifiBandType::kBand6Ghz),
WifiUtils::kUnspecified);
EXPECT_EQ(WifiUtils::ConvertChannelToFrequencyMhz(kChan30Num_60G_NotExist,
WifiBandType::kBand60Ghz),
WifiUtils::kUnspecified);
}
TEST(WifiUtilsTest, ConvertFrequencyToChannel) {
EXPECT_EQ(WifiUtils::ConvertFrequencyMhzToChannel(kChan6NumFreq_2G),
kChan6Num_2G);
EXPECT_EQ(WifiUtils::ConvertFrequencyMhzToChannel(kChan48NumFreq_5G),
kChan48Num_5G);
EXPECT_EQ(WifiUtils::ConvertFrequencyMhzToChannel(kChan69NumFreq_6G),
kChan69Num_6G);
EXPECT_EQ(WifiUtils::ConvertFrequencyMhzToChannel(kChan4NumFreq_60G),
kChan4Num_60G);
EXPECT_EQ(WifiUtils::ConvertFrequencyMhzToChannel(kFreqNotExist),
WifiUtils::kUnspecified);
}
TEST(WifiUtilsTest, Ipv4Validation) {
EXPECT_FALSE(WifiUtils::ValidateIPV4("12.34.212.46.37"));
EXPECT_FALSE(WifiUtils::ValidateIPV4("12.gt.212.46"));
EXPECT_FALSE(WifiUtils::ValidateIPV4("192.168.358.46"));
EXPECT_FALSE(WifiUtils::ValidateIPV4("192.-168.1.46"));
EXPECT_TRUE(WifiUtils::ValidateIPV4("192.168.1.46"));
}
TEST(WifiUtilsTest, GetHumanReadableIpAddress) {
EXPECT_EQ(
WifiUtils::GetHumanReadableIpAddress(absl::HexStringToBytes("000AFEFF")),
"0.10.254.255");
}
} // namespace
} // namespace nearby
+72 -22
View File
@@ -18,7 +18,6 @@ cc_library(
name = "types",
srcs = [
"device_info.cc",
"log_message.cc",
"timer.cc",
],
hdrs = [
@@ -31,30 +30,30 @@ cc_library(
"future.h",
"input_file.h",
"listenable_future.h",
"log_message.h",
"mutex.h",
"output_file.h",
"preferences_manager.h",
"scheduled_executor.h",
"settable_future.h",
"submittable_executor.h",
"task_scheduler.h",
"timer.h",
"utils.h",
],
copts = ["-Ithird_party/nearby/internal/platform/implementation/windows/generated"],
defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"],
visibility = ["//third_party/nearby/sharing/internal/impl/windows:__pkg__"],
visibility = [
"//sharing/internal/impl/windows:__pkg__",
],
deps = [
":comm",
"//base",
"//base:stringprintf",
"//internal/base:bluetooth_address",
"//internal/base:files",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:types",
"//internal/platform:logging",
"//internal/platform:uuid",
"//internal/platform/implementation:types",
"//internal/platform/implementation/windows/generated:types",
"//strings:strappendv",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:any_invocable",
@@ -102,16 +101,21 @@ cc_library(
"wifi.h",
"wifi_direct.h",
"wifi_hotspot.h",
"wifi_intel.h",
"wifi_lan.h",
],
copts = ["-DNO_INTEL_PIE"],
visibility = ["//visibility:private"],
deps = [
"//connections/implementation/flags:connections_flags",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:comm",
"//internal/platform:types",
"//internal/platform:uuid",
"//internal/platform/flags:platform_flags",
"//internal/platform/implementation:account_manager",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:types",
"//internal/platform/implementation:wifi_utils",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/windows/generated:types",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
@@ -141,6 +145,26 @@ cc_library(
],
)
cc_library(
name = "string_utils",
srcs = [
"string_utils.cc",
],
hdrs = [
"string_utils.h",
],
compatible_with = ["//buildenv/target:non_prod"],
visibility = [
"//internal/platform:__subpackages__",
"//location/nearby:__subpackages__",
],
deps = [
"//internal/platform:logging",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)
cc_library(
name = "windows",
srcs = [
@@ -170,6 +194,7 @@ cc_library(
"session_manager.cc",
"submittable_executor.cc",
"system_clock.cc",
"task_scheduler.cc",
"thread_pool.cc",
"utils.cc",
"webrtc.cc",
@@ -179,6 +204,7 @@ cc_library(
"wifi_hotspot_medium.cc",
"wifi_hotspot_server_socket.cc",
"wifi_hotspot_socket.cc",
"wifi_intel.cc",
"wifi_lan_medium.cc",
"wifi_lan_server_socket.cc",
"wifi_lan_socket.cc",
@@ -186,30 +212,40 @@ cc_library(
],
# This is the temporary solution to solve compilation error of Win32 WFDxxx() related API.
# WFD API is only support after _WIN32_WINNT_WIN8, but the current lexan _WIN32_WINNT is set to _WIN32_WINNT_WIN7
copts = ["-Ithird_party/nearby/internal/platform/implementation/windows/generated -D_WIN32_WINNT=_WIN32_WINNT_WIN10 -DWINVER=_WIN32_WINNT_WIN10"],
copts = [
"-DNO_INTEL_PIE",
"-D_WIN32_WINNT=_WIN32_WINNT_WIN10 -DWINVER=_WIN32_WINNT_WIN10",
"-Wno-unused-variable",
"-Wno-unused-value",
],
defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"],
visibility = [
"//chrome/chromeos/assistant/data_migration/lib:__pkg__",
"//connections:__subpackages__",
"//fastpair:__subpackages__",
"//internal/platform:__subpackages__",
"//location/nearby:__subpackages__",
"//presence:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
"//sharing:__subpackages__",
],
deps = [
":comm",
":crypto", # build_cleaner: keep
":string_utils",
":types",
"//connections/implementation/flags:connections_flags",
"//internal/account",
"//internal/base:files",
"//internal/flags:nearby_flags",
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:comm",
"//internal/platform:types",
"//internal/platform:logging",
"//internal/platform:uuid",
"//internal/platform/flags:platform_flags",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
"//internal/platform/implementation:wifi_utils",
"//internal/platform/implementation/shared:count_down_latch",
"//internal/platform/implementation/shared:file",
"//internal/platform/implementation/windows/generated:types",
@@ -218,7 +254,6 @@ cc_library(
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
@@ -240,9 +275,7 @@ cc_library(
"test_data.h",
"test_utils.h",
],
visibility = [
"//visibility:private", # Only private by automation, not intent. Owner may accept CLs adding visibility. See go/scheuklappen#explicit-private.
],
visibility = ["//visibility:private"],
deps = [
"//internal/platform:base",
"@nlohmann_json//:json",
@@ -270,13 +303,16 @@ cc_test(
"preferences_repository_test.cc",
"scheduled_executor_test.cc",
"submittable_executor_test.cc",
"task_scheduler_test.cc",
"thread_pool_test.cc",
"timer_test.cc",
"utils_test.cc",
"webrtc_test.cc",
"wifi_hotspot_test.cc",
"wifi_medium_test.cc",
],
copts = ["-Ithird_party/nearby/internal/platform/implementation/windows/generated -DCORE_ADAPTER_DLL"],
tags = ["notap"],
copts = ["-DCORE_ADAPTER_DLL"],
tags = ["nozapfhahn"],
deps = [
":comm",
":crypto",
@@ -284,7 +320,7 @@ cc_test(
":types",
":windows",
"//internal/platform:base",
"//internal/platform:types",
"//internal/platform:logging",
"//internal/platform/implementation:comm",
"//internal/platform/implementation:platform",
"//internal/platform/implementation:types",
@@ -300,3 +336,17 @@ cc_test(
"@nlohmann_json//:json",
],
)
cc_test(
name = "string_utils_test",
size = "small",
timeout = "short",
srcs = [
"string_utils_test.cc",
],
deps = [
":string_utils",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
@@ -25,6 +25,7 @@ namespace windows {
// A boolean value that may be updated atomically.
class AtomicBoolean : public api::AtomicBoolean {
public:
explicit AtomicBoolean(bool value = false) : atomic_boolean_(value) {}
~AtomicBoolean() override = default;
// Atomically read and return current value.
@@ -16,6 +16,7 @@
#define PLATFORM_IMPL_WINDOWS_ATOMIC_REFERENCE_H_
#include <atomic>
#include <cstdint>
#include "internal/platform/implementation/atomic_reference.h"
@@ -25,6 +26,7 @@ namespace windows {
// Type that allows 32-bit atomic reads and writes.
class AtomicUint32 : public api::AtomicUint32 {
public:
explicit AtomicUint32(std::uint32_t value = 0) : atomic_uint32_(value) {}
~AtomicUint32() override = default;
// Atomically reads and returns stored value.
@@ -37,6 +37,7 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/flags/nearby_platform_feature_flags.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/logging.h"
#include "internal/platform/uuid.h"
@@ -101,31 +102,42 @@ std::string GattCommunicationStatusToString(GattCommunicationStatus status) {
BleGattClient::BleGattClient(BluetoothLEDevice ble_device)
: ble_device_(ble_device) {
NEARBY_LOGS(VERBOSE) << __func__ << ": GATT client is created.";
if (ble_device_ == nullptr) {
LOG(WARNING) << __func__ << ": ble_device is null.";
} else {
LOG(INFO) << __func__ << ": GATT client is created, address: "
<< uint64_to_mac_address_string(ble_device_.BluetoothAddress());
}
}
BleGattClient::~BleGattClient() {
NEARBY_LOGS(VERBOSE) << __func__ << ": GATT client is released.";
LOG(INFO) << __func__ << ": GATT client is released.";
Disconnect();
}
bool BleGattClient::DiscoverServiceAndCharacteristics(
const Uuid& service_uuid, const std::vector<Uuid>& characteristic_uuids) {
absl::MutexLock lock(&mutex_);
if (!NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableBleV2Gatt)) {
auto windows_bluetooth_adapter_ = ::winrt::Windows::Devices::Bluetooth::
BluetoothAdapter::GetDefaultAsync()
.get();
if (windows_bluetooth_adapter_.IsExtendedAdvertisingSupported()) {
NEARBY_LOGS(WARNING) << __func__ << ": GATT is disabled.";
BluetoothAdapter bluetooth_adapter;
if (bluetooth_adapter.IsExtendedAdvertisingSupported()) {
LOG(WARNING) << __func__ << ": GATT is disabled.";
return false;
}
if (!bluetooth_adapter.IsCentralRoleSupported()) {
LOG(ERROR) << __func__
<< ": Bluetooth Hardware does not support Central "
"Role, which is required to start GATT client.";
return false;
}
if (!NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableBleV2GattOnNonExtendedDevice)) {
NEARBY_LOGS(WARNING) << __func__ << ": GATT is disabled.";
LOG(WARNING) << __func__ << ": GATT is disabled.";
return false;
}
}
@@ -135,13 +147,12 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
absl::StrAppend(out, std::string(uuid));
});
NEARBY_LOGS(VERBOSE) << __func__ << ": Discover service_uuid="
<< std::string(service_uuid)
<< " with characteristic_uuids=" << flat_characteristics;
VLOG(1) << __func__ << ": Discover service_uuid=" << std::string(service_uuid)
<< " with characteristic_uuids=" << flat_characteristics;
try {
if (ble_device_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": BLE device is disconnected.";
LOG(ERROR) << __func__ << ": BLE device is disconnected.";
return false;
}
@@ -155,23 +166,21 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
gatt_devices_services_result_ = get_gatt_services_async.GetResults();
break;
case winrt::Windows::Foundation::AsyncStatus::Started:
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get GATT services due to timeout.";
LOG(ERROR) << __func__
<< ": Failed to get GATT services due to timeout.";
get_gatt_services_async.Cancel();
return false;
default:
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get GATT services due to unknown reasons.";
LOG(ERROR) << __func__
<< ": Failed to get GATT services due to unknown reasons.";
return false;
}
if (gatt_devices_services_result_.Status() !=
GattCommunicationStatus::Success) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get gatt service with error: "
<< GattCommunicationStatusToString(
gatt_devices_services_result_.Status());
LOG(ERROR) << __func__ << ": Failed to get gatt service with error: "
<< GattCommunicationStatusToString(
gatt_devices_services_result_.Status());
gatt_devices_services_result_ = nullptr;
return false;
}
@@ -185,9 +194,8 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
winrt::to_string(winrt::to_hstring(service.Uuid())));
});
NEARBY_LOGS(VERBOSE) << __func__
<< ": Found GATT services=" << flat_services
<< " from BLE device.";
LOG(INFO) << __func__ << ": Found GATT services=" << flat_services
<< " from BLE device.";
// Needs to check each service to make sure it includes all characteristic
// uuids. Services may include duplicate service UUID, but each of them may
@@ -196,27 +204,25 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
winrt::guid uuid = service.Uuid();
std::string uuid_string = winrt::to_string(winrt::to_hstring(uuid));
NEARBY_LOGS(VERBOSE) << __func__
<< ": Found service UUID=" << uuid_string;
VLOG(1) << __func__ << ": Found service UUID=" << uuid_string;
if (!is_nearby_uuid_equal_to_winrt_guid(service_uuid, uuid)) {
NEARBY_LOGS(WARNING)
LOG(WARNING)
<< __func__
<< ": Service uuid not match, continue check other services.";
continue;
}
NEARBY_LOGS(INFO) << __func__
<< ": Found the discovery service UUID=" << uuid_string;
LOG(INFO) << __func__
<< ": Found the discovery service UUID=" << uuid_string;
// Try to check the characteristic uuids.
GattCharacteristicsResult gatt_characteristics_result =
service.GetCharacteristicsAsync(BluetoothCacheMode::Uncached).get();
if (gatt_characteristics_result.Status() !=
GattCommunicationStatus::Success) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get characteristics with error: "
<< GattCommunicationStatusToString(
gatt_characteristics_result.Status());
LOG(ERROR) << __func__ << ": Failed to get characteristics with error: "
<< GattCommunicationStatusToString(
gatt_characteristics_result.Status());
continue;
}
@@ -227,8 +233,8 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
gatt_characteristic.Uuid())));
});
NEARBY_LOGS(VERBOSE) << __func__ << ": Found GATT characteristics="
<< flat_characteristics;
VLOG(1) << __func__
<< ": Found GATT characteristics=" << flat_characteristics;
bool found_all = true;
@@ -246,8 +252,8 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
}
}
if (found == false) {
NEARBY_LOGS(WARNING) << __func__ << ": Cannot find characteristic: "
<< std::string(characteristic_uuid);
LOG(WARNING) << __func__ << ": Cannot find characteristic: "
<< std::string(characteristic_uuid);
found_all = false;
break;
}
@@ -258,21 +264,18 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
}
// found all characteristics.
NEARBY_LOGS(VERBOSE) << __func__ << ": Found all characteristics.";
VLOG(1) << __func__ << ": Found all characteristics.";
return true;
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Failed to find service and all characteristics.";
LOG(ERROR) << __func__
<< ": Failed to find service and all characteristics.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get GATT services. exception: "
<< exception.what();
LOG(ERROR) << __func__ << ": Failed to get GATT services. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get GATT services. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": Failed to get GATT services. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
return false;
@@ -281,17 +284,16 @@ bool BleGattClient::DiscoverServiceAndCharacteristics(
absl::optional<api::ble_v2::GattCharacteristic>
BleGattClient::GetCharacteristic(const Uuid& service_uuid,
const Uuid& characteristic_uuid) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Stared to get characteristic UUID="
<< std::string(characteristic_uuid)
<< " in service UUID=" << std::string(service_uuid);
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__ << ": Stared to get characteristic UUID="
<< std::string(characteristic_uuid)
<< " in service UUID=" << std::string(service_uuid);
try {
std::optional<GattCharacteristic> gatt_characteristic =
GetNativeCharacteristic(service_uuid, characteristic_uuid);
if (!gatt_characteristic.has_value()) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get native GATT characteristic.";
LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic.";
return absl::nullopt;
}
@@ -329,18 +331,17 @@ BleGattClient::GetCharacteristic(const Uuid& service_uuid,
native_characteristic_map_[result].native_characteristic =
gatt_characteristic;
NEARBY_LOGS(VERBOSE) << __func__ << ": Return Characteristic. uuid="
<< std::string(characteristic_uuid);
VLOG(1) << __func__ << ": Return Characteristic. uuid="
<< std::string(characteristic_uuid);
return result;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get GATT characteristic. exception: "
<< exception.what();
LOG(ERROR) << __func__ << ": Failed to get GATT characteristic. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to get GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to get GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
return absl::nullopt;
@@ -348,33 +349,33 @@ BleGattClient::GetCharacteristic(const Uuid& service_uuid,
absl::optional<std::string> BleGattClient::ReadCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Read characteristic="
<< std::string(characteristic.uuid);
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__
<< ": Read characteristic=" << std::string(characteristic.uuid);
try {
std::optional<GattCharacteristic> gatt_characteristic =
GetNativeCharacteristic(characteristic.service_uuid,
characteristic.uuid);
if (!gatt_characteristic.has_value()) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get native GATT characteristic.";
LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic.";
return absl::nullopt;
}
GattReadResult result =
gatt_characteristic->ReadValueAsync(BluetoothCacheMode::Uncached).get();
if (result.Status() != GattCommunicationStatus::Success) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to read GATT characteristic with error: "
<< GattCommunicationStatusToString(result.Status());
LOG(ERROR) << __func__
<< ": Failed to read GATT characteristic with error: "
<< GattCommunicationStatusToString(result.Status());
return absl::nullopt;
}
IBuffer buffer = result.Value();
int size = buffer.Length();
if (size == 0) {
NEARBY_LOGS(WARNING) << __func__ << ": No characteristic value.";
return absl::nullopt;
VLOG(1) << __func__ << ": No characteristic value.";
return "";
}
DataReader data_reader = DataReader::FromBuffer(buffer);
@@ -384,18 +385,17 @@ absl::optional<std::string> BleGattClient::ReadCharacteristic(
data.push_back(static_cast<char>(data_reader.ReadByte()));
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Got characteristic value length=" << data.size();
VLOG(1) << __func__ << ": Got characteristic value length=" << data.size();
return data;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to read GATT characteristic. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to read GATT characteristic. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to read GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to read GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
return absl::nullopt;
@@ -404,16 +404,15 @@ absl::optional<std::string> BleGattClient::ReadCharacteristic(
bool BleGattClient::WriteCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic,
absl::string_view value, api::ble_v2::GattClient::WriteType write_type) {
NEARBY_LOGS(VERBOSE) << __func__ << ": write characteristic: "
<< std::string(characteristic.uuid);
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__
<< ": write characteristic: " << std::string(characteristic.uuid);
try {
std::optional<GattCharacteristic> gatt_characteristic =
native_characteristic_map_[characteristic].native_characteristic;
if (!gatt_characteristic.has_value()) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get native GATT characteristic.";
LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic.";
return false;
}
@@ -430,27 +429,25 @@ bool BleGattClient::WriteCharacteristic(
gatt_characteristic->WriteValueAsync(buffer, write_option).get();
if (status != GattCommunicationStatus::Success) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to write data to GATT characteristic: "
<< std::string(characteristic.uuid) << "with error: "
<< GattCommunicationStatusToString(status);
LOG(ERROR) << __func__
<< ": Failed to write data to GATT characteristic: "
<< std::string(characteristic.uuid)
<< "with error: " << GattCommunicationStatusToString(status);
return false;
} else {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Write data to GATT characteristic: "
<< std::string(characteristic.uuid)
<< ", bytes count: " << value.size();
VLOG(1) << __func__ << ": Write data to GATT characteristic: "
<< std::string(characteristic.uuid)
<< ", bytes count: " << value.size();
return true;
}
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to write GATT characteristic. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to write GATT characteristic. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to write GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to write GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
return false;
}
@@ -459,8 +456,8 @@ bool BleGattClient::SetCharacteristicSubscription(
const api::ble_v2::GattCharacteristic& characteristic, bool enable,
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Started to set Characteristic Subscription.";
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__ << ": Started to set Characteristic Subscription.";
GattClientCharacteristicConfigurationDescriptorValue gcccd_value =
GattClientCharacteristicConfigurationDescriptorValue::None;
if ((characteristic.property & Property::kNotify) != Property::kNone) {
@@ -470,22 +467,18 @@ bool BleGattClient::SetCharacteristicSubscription(
gcccd_value =
GattClientCharacteristicConfigurationDescriptorValue::Indicate;
} else {
NEARBY_LOGS(WARNING) << "Characeristic: "
<< std::string(characteristic.uuid)
<< " supports neither notifications nor indications.";
LOG(WARNING) << "Characeristic: " << std::string(characteristic.uuid)
<< " supports neither notifications nor indications.";
return false;
}
std::optional<GattCharacteristic> gatt_characteristic;
{
absl::MutexLock lock(&mutex_);
gatt_characteristic =
native_characteristic_map_[characteristic].native_characteristic;
}
gatt_characteristic =
native_characteristic_map_[characteristic].native_characteristic;
if (!gatt_characteristic.has_value()) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get native GATT characteristic.";
LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic.";
return false;
}
@@ -498,7 +491,6 @@ bool BleGattClient::SetCharacteristicSubscription(
return false;
}
absl::MutexLock lock(&mutex_);
// Set value changed handler
try {
if (enable) {
@@ -513,27 +505,23 @@ bool BleGattClient::SetCharacteristicSubscription(
});
if (!native_characteristic_map_[characteristic].notification_token) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to add value change handler.";
LOG(ERROR) << __func__ << ": Failed to add value change handler.";
return false;
}
} else if (native_characteristic_map_[characteristic].notification_token) {
gatt_characteristic->ValueChanged(std::exchange(
native_characteristic_map_[characteristic].notification_token, {}));
}
NEARBY_LOGS(ERROR) << __func__
<< ": Successfully set Characteristic Subscription.";
LOG(ERROR) << __func__ << ": Successfully set Characteristic Subscription.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set Characteristic Subscription."
<< exception.what();
LOG(ERROR) << __func__ << ": Failed to set Characteristic Subscription."
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set Characteristic Subscription."
" WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to set Characteristic Subscription."
" WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
return false;
}
@@ -541,38 +529,36 @@ bool BleGattClient::SetCharacteristicSubscription(
void BleGattClient::Disconnect() {
absl::MutexLock lock(&mutex_);
try {
NEARBY_LOGS(VERBOSE) << __func__ << ": Disconnect is called.";
VLOG(1) << __func__ << ": Disconnect is called.";
if (ble_device_ != nullptr) {
ble_device_.Close();
ble_device_ = nullptr;
}
native_characteristic_map_.clear();
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to disconnect GATT device. exception: "
<< exception.what();
LOG(ERROR) << __func__ << ": Failed to disconnect GATT device. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to disconnect GATT device. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to disconnect GATT device. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
}
}
std::optional<GattCharacteristic> BleGattClient::GetNativeCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Stared to get native characteristic UUID="
<< std::string(characteristic_uuid)
<< " in service UUID=" << std::string(service_uuid);
VLOG(1) << __func__ << ": Stared to get native characteristic UUID="
<< std::string(characteristic_uuid)
<< " in service UUID=" << std::string(service_uuid);
try {
if (ble_device_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": BLE device is disconnected.";
LOG(ERROR) << __func__ << ": BLE device is disconnected.";
return absl::nullopt;
}
if (gatt_devices_services_result_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": No available GATT services.";
LOG(ERROR) << __func__ << ": No available GATT services.";
return absl::nullopt;
}
@@ -582,10 +568,10 @@ std::optional<GattCharacteristic> BleGattClient::GetNativeCharacteristic(
service.GetCharacteristicsAsync(BluetoothCacheMode::Cached).get();
if (gatt_characteristics_result.Status() !=
GattCommunicationStatus::Success) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to get characteristics with error: "
<< GattCommunicationStatusToString(
gatt_characteristics_result.Status());
LOG(ERROR) << __func__
<< ": Failed to get characteristics with error: "
<< GattCommunicationStatusToString(
gatt_characteristics_result.Status());
continue;
}
@@ -593,9 +579,8 @@ std::optional<GattCharacteristic> BleGattClient::GetNativeCharacteristic(
gatt_characteristics_result.Characteristics()) {
if (is_nearby_uuid_equal_to_winrt_guid(characteristic_uuid,
characteristic.Uuid())) {
NEARBY_LOGS(VERBOSE)
<< __func__ << ": Return native Characteristic. uuid="
<< std::string(characteristic_uuid);
VLOG(1) << __func__ << ": Return native Characteristic. uuid="
<< std::string(characteristic_uuid);
return characteristic;
}
@@ -603,13 +588,13 @@ std::optional<GattCharacteristic> BleGattClient::GetNativeCharacteristic(
}
}
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get native characteristic.";
LOG(ERROR) << __func__ << ": Failed to get native characteristic.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to get native GATT characteristic. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to get native GATT characteristic. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
LOG(ERROR)
<< __func__
<< ": Failed to get native GATT characteristic. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
@@ -621,9 +606,8 @@ std::optional<GattCharacteristic> BleGattClient::GetNativeCharacteristic(
bool BleGattClient::WriteCharacteristicConfigurationDescriptor(
GattCharacteristic& characteristic,
GattClientCharacteristicConfigurationDescriptorValue value) {
NEARBY_LOGS(VERBOSE)
<< __func__
<< ": Stared to write characteristic configuration descriptor";
VLOG(1) << __func__
<< ": Stared to write characteristic configuration descriptor";
try {
GattCommunicationStatus status =
@@ -631,23 +615,23 @@ bool BleGattClient::WriteCharacteristicConfigurationDescriptor(
.WriteClientCharacteristicConfigurationDescriptorAsync(value)
.get();
if (status == GattCommunicationStatus::Success) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Successfully write client characteristic "
"configuration descriptor";
VLOG(1) << __func__
<< ": Successfully write client characteristic "
"configuration descriptor";
return true;
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Failed to write client characteristic "
"configuration descriptor with error: "
<< GattCommunicationStatusToString(status);
LOG(ERROR) << __func__
<< ": Failed to write client characteristic "
"configuration descriptor with error: "
<< GattCommunicationStatusToString(status);
} catch (std::exception exception) {
// This usually happens when a device reports that it support notify, but
// it actually doesn't.
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to write client characteristic "
"configuration descriptor";
LOG(ERROR) << __func__
<< ": Failed to write client characteristic "
"configuration descriptor";
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
LOG(ERROR)
<< __func__
<< ": Failed to write client characteristic configuration descriptor."
" WinRT exception: "
@@ -659,7 +643,7 @@ bool BleGattClient::WriteCharacteristicConfigurationDescriptor(
void BleGattClient::OnCharacteristicValueChanged(
const api::ble_v2::GattCharacteristic& characteristic,
GattValueChangedEventArgs args) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Gatt Characteristic value changed.";
VLOG(1) << __func__ << ": Gatt Characteristic value changed.";
IBuffer buffer = args.CharacteristicValue();
int size = buffer.Length();
DataReader data_reader = DataReader::FromBuffer(buffer);
@@ -668,8 +652,7 @@ void BleGattClient::OnCharacteristicValueChanged(
for (int i = 0; i < size; ++i) {
data.push_back(static_cast<char>(data_reader.ReadByte()));
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Got characteristic value length= " << data.size();
VLOG(1) << __func__ << ": Got characteristic value length= " << data.size();
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb;
@@ -678,8 +661,7 @@ void BleGattClient::OnCharacteristicValueChanged(
if (!native_characteristic_map_.contains(characteristic) ||
!native_characteristic_map_[characteristic]
.on_characteristic_changed_cb) {
NEARBY_LOGS(INFO) << __func__
<< ": No registered callback for characteristic.";
LOG(INFO) << __func__ << ": No registered callback for characteristic.";
return;
}
on_characteristic_changed_cb =
@@ -23,10 +23,15 @@
#include <string>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/types/optional.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/uuid.h"
#include "winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h"
#include "winrt/Windows.Devices.Bluetooth.h"
#include "winrt/base.h"
@@ -42,25 +47,29 @@ class BleGattClient : public api::ble_v2::GattClient {
bool DiscoverServiceAndCharacteristics(
const Uuid& service_uuid,
const std::vector<Uuid>& characteristic_uuids) override;
const std::vector<Uuid>& characteristic_uuids) override
ABSL_LOCKS_EXCLUDED(mutex_);
absl::optional<api::ble_v2::GattCharacteristic> GetCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid) override;
const Uuid& service_uuid, const Uuid& characteristic_uuid) override
ABSL_LOCKS_EXCLUDED(mutex_);
absl::optional<std::string> ReadCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic) override;
const api::ble_v2::GattCharacteristic& characteristic) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool WriteCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic,
absl::string_view value,
api::ble_v2::GattClient::WriteType write_type) override;
api::ble_v2::GattClient::WriteType write_type) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool SetCharacteristicSubscription(
const api::ble_v2::GattCharacteristic& characteristic, bool enable,
absl::AnyInvocable<void(absl::string_view value)>
on_characteristic_changed_cb) override;
on_characteristic_changed_cb) override ABSL_LOCKS_EXCLUDED(mutex_);
void Disconnect() override;
void Disconnect() override ABSL_LOCKS_EXCLUDED(mutex_);
private:
// Used to save native data related to the GATT characteristic.
@@ -75,13 +84,15 @@ class BleGattClient : public api::ble_v2::GattClient {
std::optional<::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCharacteristic>
GetNativeCharacteristic(const Uuid& service_uuid,
const Uuid& characteristic_uuid);
const Uuid& characteristic_uuid)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool WriteCharacteristicConfigurationDescriptor(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattCharacteristic& characteristic,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattClientCharacteristicConfigurationDescriptorValue value);
GattClientCharacteristicConfigurationDescriptorValue value)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void OnCharacteristicValueChanged(
const api::ble_v2::GattCharacteristic& characteristic,
@@ -90,9 +101,11 @@ class BleGattClient : public api::ble_v2::GattClient {
absl::Mutex mutex_;
::winrt::Windows::Devices::Bluetooth::BluetoothLEDevice ble_device_;
::winrt::Windows::Devices::Bluetooth::BluetoothLEDevice ble_device_
ABSL_GUARDED_BY(mutex_);
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattDeviceServicesResult gatt_devices_services_result_ = nullptr;
GattDeviceServicesResult gatt_devices_services_result_
ABSL_GUARDED_BY(mutex_) = nullptr;
absl::flat_hash_map<api::ble_v2::GattCharacteristic, GattCharacteristicData>
native_characteristic_map_ ABSL_GUARDED_BY(mutex_);
@@ -15,6 +15,7 @@
#include "internal/platform/implementation/windows/ble_gatt_server.h"
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <exception>
#include <memory>
@@ -25,15 +26,21 @@
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/log/check.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_format.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "absl/types/optional.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/logging.h"
#include "internal/platform/uuid.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Windows.Storage.Streams.h"
#include "winrt/base.h"
@@ -81,6 +88,9 @@ using ::winrt::Windows::Storage::Streams::DataWriter;
using Permission = api::ble_v2::GattCharacteristic::Permission;
using Property = api::ble_v2::GattCharacteristic::Property;
constexpr absl::Duration kGattServerTimeout = absl::Milliseconds(500);
constexpr int kGattServerCheckIntervalInMills = 50;
std::string ConvertGattStatusToString(
GattServiceProviderAdvertisementStatus status) {
switch (status) {
@@ -106,20 +116,22 @@ BleGattServer::BleGattServer(api::BluetoothAdapter* adapter,
api::ble_v2::ServerGattConnectionCallback callback)
: adapter_(dynamic_cast<BluetoothAdapter*>(adapter)),
peripheral_(adapter_->GetMacAddress()),
gatt_connection_callback_(std::move(callback)) {}
gatt_connection_callback_(std::move(callback)) {
DCHECK(adapter_ != nullptr);
}
absl::optional<api::ble_v2::GattCharacteristic>
BleGattServer::CreateCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid,
api::ble_v2::GattCharacteristic::Permission permission,
api::ble_v2::GattCharacteristic::Property property) {
NEARBY_LOGS(VERBOSE) << __func__ << ": create characteristic, service_uuid: "
<< std::string(service_uuid) << ", characteristic_uuid: "
<< std::string(characteristic_uuid);
absl::MutexLock lock(&mutex_);
LOG(INFO) << __func__ << ": create characteristic, service_uuid: "
<< std::string(service_uuid)
<< ", characteristic_uuid: " << std::string(characteristic_uuid);
if (!service_uuid_.IsEmpty() && service_uuid_ != service_uuid) {
NEARBY_LOGS(ERROR) << __func__
<< ": Only support one GATT service for now.";
LOG(ERROR) << __func__ << ": Only support one GATT service for now.";
return absl::nullopt;
}
@@ -142,18 +154,18 @@ BleGattServer::CreateCharacteristic(
bool BleGattServer::UpdateCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic,
const nearby::ByteArray& value) {
NEARBY_LOGS(VERBOSE) << __func__ << ": update characteristic: "
<< std::string(characteristic.uuid);
absl::MutexLock lock(&mutex_);
LOG(INFO) << __func__
<< ": update characteristic: " << std::string(characteristic.uuid);
if (characteristic.service_uuid != service_uuid_) {
NEARBY_LOGS(ERROR) << __func__ << ": Cannot found the GATT service.";
LOG(ERROR) << __func__ << ": Cannot found the GATT service.";
return false;
}
for (auto& it : gatt_characteristic_datas_) {
if (it.gatt_characteristic.uuid == characteristic.uuid) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Found the characteristic to update.";
VLOG(1) << __func__ << ": Found the characteristic to update.";
it.data = value;
// If it is in running, notify the value changed.
@@ -165,8 +177,7 @@ bool BleGattServer::UpdateCharacteristic(
is_indicate_characteristic = true;
}
NEARBY_LOGS(INFO) << __func__
<< ": Notify characteristic value updated.";
LOG(INFO) << __func__ << ": Notify characteristic value updated.";
if (is_indicate_characteristic) {
NotifyValueChanged(it.gatt_characteristic);
}
@@ -176,7 +187,7 @@ bool BleGattServer::UpdateCharacteristic(
}
}
NEARBY_LOGS(ERROR) << __func__ << ": Failed to update the characteristic.";
LOG(ERROR) << __func__ << ": Failed to update the characteristic.";
return false;
}
@@ -184,45 +195,75 @@ bool BleGattServer::UpdateCharacteristic(
absl::Status BleGattServer::NotifyCharacteristicChanged(
const api::ble_v2::GattCharacteristic& characteristic, bool confirm,
const ByteArray& new_value) {
absl::MutexLock lock(&mutex_);
// Currently, the method is not hooked up at platform layer.
NEARBY_LOGS(VERBOSE) << __func__ << ": Notify characteristic="
<< std::string(characteristic.uuid) << " changed.";
VLOG(1) << __func__
<< ": Notify characteristic=" << std::string(characteristic.uuid)
<< " changed.";
return absl::OkStatus();
}
void BleGattServer::Stop() {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to stop GATT server.";
try {
if (gatt_service_provider_ == nullptr) {
NEARBY_LOGS(WARNING) << __func__ << ": GATT server already stopped.";
return;
}
absl::AnyInvocable<void()> close_notifier = nullptr;
{
absl::MutexLock lock(&mutex_);
VLOG(1) << __func__ << ": Start to stop GATT server.";
if (gatt_service_provider_ != nullptr) {
try {
if (is_advertising_) {
gatt_service_provider_.StopAdvertising();
}
if (is_advertising_) {
gatt_service_provider_.StopAdvertising();
gatt_characteristic_datas_.clear();
service_uuid_ = Uuid();
gatt_service_provider_ = nullptr;
} catch (std::exception exception) {
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
LOG(ERROR) << __func__ << ": Unknown exception.";
}
} else {
LOG(WARNING) << __func__ << ": no GATT server is running.";
}
close_notifier = std::move(close_notifier_);
}
gatt_characteristic_datas_.clear();
service_uuid_ = Uuid();
gatt_service_provider_ = nullptr;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
if (close_notifier != nullptr) {
close_notifier();
}
}
bool BleGattServer::InitializeGattServer() {
try {
// Create and advertise GATT service.
NEARBY_LOGS(VERBOSE) << __func__ << ": Create GATT service service_uuid="
<< std::string(service_uuid_);
VLOG(1) << __func__ << ": Create GATT service service_uuid="
<< std::string(service_uuid_);
if (adapter_ == nullptr || !adapter_->IsEnabled()) {
NEARBY_LOGS(ERROR) << __func__ << ": Bluetooth adapter is disabled.";
if (adapter_ == nullptr) {
LOG(ERROR) << __func__ << ": Bluetooth adapter is absent.";
return false;
}
if (!adapter_->IsEnabled()) {
LOG(ERROR) << __func__ << ": Bluetooth adapter is disabled.";
return false;
}
if (!adapter_->IsLowEnergySupported()) {
LOG(ERROR) << __func__
<< ": Bluetooth adapter does not support BLE, which "
"is needed to start GATT server.";
return false;
}
if (!adapter_->IsPeripheralRoleSupported()) {
LOG(ERROR)
<< __func__
<< ": Bluetooth Hardware does not support Peripheral Role, which is "
"required to start GATT server.";
return false;
}
@@ -231,9 +272,8 @@ bool BleGattServer::InitializeGattServer() {
GattServiceProvider::CreateAsync(service_uuid).get();
if (service_provider_result.Error() != BluetoothError::Success) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to create GATT service. Error: "
<< static_cast<int>(service_provider_result.Error());
LOG(ERROR) << __func__ << ": Failed to create GATT service. Error: "
<< static_cast<int>(service_provider_result.Error());
return false;
}
@@ -242,7 +282,7 @@ bool BleGattServer::InitializeGattServer() {
service_provider_advertisement_changed_token_ =
gatt_service_provider_.AdvertisementStatusChanged(
{this, &BleGattServer::ServiceProvider_AdvertisementStatusChanged});
NEARBY_LOGS(INFO) << __func__ << ": GATT service created.";
LOG(INFO) << __func__ << ": GATT service created.";
// Create GATT characteristics.
for (auto& characteristic_data : gatt_characteristic_datas_) {
@@ -276,12 +316,11 @@ bool BleGattServer::InitializeGattServer() {
is_notify_supported = true;
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": GATT characteristic properties: read="
<< is_read_supported
<< ",write=" << is_write_supported
<< ",indicate=" << is_indicate_supported
<< ",notify=" << is_notify_supported;
VLOG(1) << __func__
<< ": GATT characteristic properties: read=" << is_read_supported
<< ",write=" << is_write_supported
<< ",indicate=" << is_indicate_supported
<< ",notify=" << is_notify_supported;
gatt_characteristic_parameters.CharacteristicProperties(properties);
gatt_characteristic_parameters.WriteProtectionLevel(
@@ -290,10 +329,8 @@ bool BleGattServer::InitializeGattServer() {
winrt::guid characteristic_uuid = nearby_uuid_to_winrt_guid(
characteristic_data.gatt_characteristic.uuid);
NEARBY_LOGS(VERBOSE) << __func__
<< ": Create characteristic characteristic_uuid="
<< winrt::to_string(
winrt::to_hstring(characteristic_uuid));
VLOG(1) << __func__ << ": Create characteristic characteristic_uuid="
<< winrt::to_string(winrt::to_hstring(characteristic_uuid));
GattLocalCharacteristicResult result =
gatt_service_provider_.Service()
@@ -302,9 +339,9 @@ bool BleGattServer::InitializeGattServer() {
.get();
if (result.Error() != BluetoothError::Success) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to create GATT characteristic. Error: "
<< static_cast<int>(result.Error());
LOG(ERROR) << __func__
<< ": Failed to create GATT characteristic. Error: "
<< static_cast<int>(result.Error());
return false;
}
@@ -312,9 +349,8 @@ bool BleGattServer::InitializeGattServer() {
::winrt::guid local_characteristic_guid =
characteristic_data.local_characteristic.Uuid();
NEARBY_LOGS(VERBOSE) << __func__ << ": Local GATT characteristic. uuid: "
<< winrt::to_string(
winrt::to_hstring(local_characteristic_guid));
VLOG(1) << __func__ << ": Local GATT characteristic. uuid: "
<< winrt::to_string(winrt::to_hstring(local_characteristic_guid));
// Setup gatt local characteristic events.
if (is_read_supported) {
@@ -339,15 +375,15 @@ bool BleGattServer::InitializeGattServer() {
is_gatt_server_inited_ = true;
NEARBY_LOGS(INFO) << __func__ << ": GATT service is initalized.";
LOG(INFO) << __func__ << ": GATT service is initalized.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
// Clean up.
@@ -361,21 +397,31 @@ bool BleGattServer::InitializeGattServer() {
bool BleGattServer::StartAdvertisement(const ByteArray& service_data,
bool is_connectable) {
absl::MutexLock lock(&mutex_);
try {
NEARBY_LOGS(VERBOSE) << __func__ << ": service_data="
<< absl::BytesToHexString(service_data.AsStringView())
<< ", is_connectable=" << is_connectable;
VLOG(1) << __func__ << ": service_data="
<< absl::BytesToHexString(service_data.AsStringView())
<< ", is_connectable=" << is_connectable;
if (is_advertising_) {
NEARBY_LOGS(ERROR) << ": GATT server is already in advertising.";
LOG(ERROR) << ": GATT server is already in advertising.";
return false;
}
is_advertising_ = true;
if (!is_gatt_server_inited_ && !InitializeGattServer()) {
NEARBY_LOGS(ERROR) << ":Failed to initalize GATT service.";
is_advertising_ = false;
LOG(ERROR) << ":Failed to initalize GATT service.";
return false;
}
if (gatt_service_provider_ == nullptr) {
LOG(WARNING) << __func__ << ": no GATT server is running.";
return false;
}
if (gatt_service_provider_.AdvertisementStatus() ==
GattServiceProviderAdvertisementStatus::Started) {
LOG(WARNING) << __func__ << ": GATT server is already in advertising.";
return false;
}
@@ -392,69 +438,96 @@ bool BleGattServer::StartAdvertisement(const ByteArray& service_data,
advertisement_parameters.ServiceData(data_writer.DetachBuffer());
gatt_service_provider_.StartAdvertising(advertisement_parameters);
NEARBY_LOGS(INFO) << __func__ << ": GATT server started.";
// Wait for the advertising to start.
int wait_milliseconds = 0;
while (gatt_service_provider_.AdvertisementStatus() !=
GattServiceProviderAdvertisementStatus::Started) {
absl::SleepFor(absl::Milliseconds(kGattServerCheckIntervalInMills));
wait_milliseconds += kGattServerCheckIntervalInMills;
if (absl::Milliseconds(wait_milliseconds) > kGattServerTimeout) {
LOG(ERROR) << __func__
<< ": Failed to start GATT advertising due to timeout.";
return false;
}
}
is_advertising_ = true;
LOG(INFO) << __func__ << ": GATT server started.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
is_advertising_ = false;
NEARBY_LOGS(ERROR) << __func__ << ": Failed to advertise GATT server.";
LOG(ERROR) << __func__ << ": Failed to advertise GATT server.";
return false;
}
bool BleGattServer::StopAdvertisement() {
absl::MutexLock lock(&mutex_);
try {
NEARBY_LOGS(INFO) << __func__ << ": stop advertisement.";
LOG(INFO) << __func__ << ": stop advertisement.";
if (!is_advertising_) {
NEARBY_LOGS(WARNING) << __func__ << ": no GATT advertisement.";
LOG(WARNING) << __func__ << ": no GATT advertisement.";
return true;
}
if (gatt_service_provider_ == nullptr) {
NEARBY_LOGS(WARNING) << __func__ << ": no GATT server is running.";
LOG(WARNING) << __func__ << ": no GATT server is running.";
is_advertising_ = false;
return true;
}
if (gatt_service_provider_.AdvertisementStatus() ==
GattServiceProviderAdvertisementStatus ::Stopped) {
NEARBY_LOGS(WARNING) << __func__ << ": no GATT advertisement is running.";
LOG(WARNING) << __func__ << ": no GATT advertisement is running.";
is_advertising_ = false;
return true;
}
gatt_service_provider_.StopAdvertising();
// Don't wait for the advertising to stop, because the advertisement status
// cannot back to stopped. Based on the observation, the advertisement
// status is stopped after the stop advertising is called.
is_advertising_ = false;
NEARBY_LOGS(INFO) << __func__ << ": GATT server stopped.";
LOG(INFO) << __func__ << ": GATT server stopped.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return false;
}
void BleGattServer::SetCloseNotifier(absl::AnyInvocable<void()> notifier) {
absl::MutexLock lock(&mutex_);
close_notifier_ = std::move(notifier);
}
::winrt::fire_and_forget BleGattServer::Characteristic_ReadRequestedAsync(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattLocalCharacteristic const& gatt_local_characteristic,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattReadRequestedEventArgs args) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Read characteristic. uuid: "
<< winrt::to_string(winrt::to_hstring(
gatt_local_characteristic.Uuid()));
LOG(INFO) << __func__ << ": Read characteristic. uuid: "
<< winrt::to_string(
winrt::to_hstring(gatt_local_characteristic.Uuid()));
auto deferral = args.GetDeferral();
@@ -464,15 +537,15 @@ bool BleGattServer::StopAdvertisement() {
FindGattCharacteristicData(gatt_local_characteristic);
if (characteristic_data == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to find characteristic="
<< ::winrt::to_string(::winrt::to_hstring(
gatt_local_characteristic.Uuid()));
LOG(ERROR) << __func__ << ": Failed to find characteristic="
<< ::winrt::to_string(
::winrt::to_hstring(gatt_local_characteristic.Uuid()));
return {};
}
GattReadRequest request = args.GetRequestAsync().get();
if (request == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get GATT read request.";
LOG(ERROR) << __func__ << ": Failed to get GATT read request.";
deferral.Complete();
return {};
}
@@ -485,20 +558,20 @@ bool BleGattServer::StopAdvertisement() {
request.RespondWithValue(buffer);
deferral.Complete();
NEARBY_LOGS(VERBOSE) << __func__ << ": Sent data to remote device.";
VLOG(1) << __func__ << ": Sent data to remote device.";
return {};
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
deferral.Complete();
NEARBY_LOGS(ERROR) << __func__ << ": Failed to send data to remote device.";
LOG(ERROR) << __func__ << ": Failed to send data to remote device.";
return {};
}
@@ -507,7 +580,7 @@ bool BleGattServer::StopAdvertisement() {
GattLocalCharacteristic const& gatt_local_characteristic,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattWriteRequestedEventArgs args) {
// In Nearby Connctions, don't support write charaterisctics right now.
// In Nearby Connections, don't support write characteristics right now.
throw std::logic_error("Not implemented.");
}
@@ -515,10 +588,9 @@ void BleGattServer::Characteristic_SubscribedClientsChanged(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattLocalCharacteristic const& gatt_local_characteristic,
::winrt::Windows::Foundation::IInspectable const& args) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": Subscribed clients changed. characteristic="
<< ::winrt::to_string(::winrt::to_hstring(
gatt_local_characteristic.Uuid()));
LOG(INFO) << __func__ << ": Subscribed clients changed. characteristic="
<< ::winrt::to_string(
::winrt::to_hstring(gatt_local_characteristic.Uuid()));
try {
std::vector<api::ble_v2::GattCharacteristic>
@@ -530,9 +602,9 @@ void BleGattServer::Characteristic_SubscribedClientsChanged(
FindGattCharacteristicData(gatt_local_characteristic);
if (characteristic_data == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to find characteristic="
<< ::winrt::to_string(::winrt::to_hstring(
gatt_local_characteristic.Uuid()));
LOG(ERROR) << __func__ << ": Failed to find characteristic="
<< ::winrt::to_string(
::winrt::to_hstring(gatt_local_characteristic.Uuid()));
return;
}
@@ -588,12 +660,12 @@ void BleGattServer::Characteristic_SubscribedClientsChanged(
subscribed_characteristic);
}
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
}
@@ -602,8 +674,9 @@ void BleGattServer::ServiceProvider_AdvertisementStatusChanged(
GattServiceProvider const& sender,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattServiceProviderAdvertisementStatusChangedEventArgs const& args) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Advertisement status changed. status="
<< ConvertGattStatusToString(args.Status());
LOG(INFO) << __func__ << ": Advertisement status changed. status="
<< ConvertGattStatusToString(args.Status())
<< ", error=" << static_cast<int>(args.Error());
}
void BleGattServer::NotifyValueChanged(
@@ -613,8 +686,8 @@ void BleGattServer::NotifyValueChanged(
FindGattCharacteristicData(gatt_characteristic);
if (characteristic_data == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to find characteristic="
<< std::string(gatt_characteristic.uuid);
LOG(ERROR) << __func__ << ": Failed to find characteristic="
<< std::string(gatt_characteristic.uuid);
return;
}
@@ -634,19 +707,19 @@ void BleGattServer::NotifyValueChanged(
for (const auto& result : results) {
if (result.Status() != GattCommunicationStatus::Success) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to notify value change. remote device id="
<< ::winrt::to_string(
result.SubscribedClient().Session().DeviceId().Id());
LOG(ERROR) << __func__
<< ": Failed to notify value change. remote device id="
<< ::winrt::to_string(
result.SubscribedClient().Session().DeviceId().Id());
}
}
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
}
@@ -17,13 +17,20 @@
#include <windows.h>
#include <optional>
#include <memory>
#include <vector>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "absl/types/optional.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/ble_v2_peripheral.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/uuid.h"
@@ -37,26 +44,32 @@ namespace windows {
class BleGattServer : public api::ble_v2::GattServer {
public:
// Make sure the adapter parameter is not null.
BleGattServer(api::BluetoothAdapter* adapter,
api::ble_v2::ServerGattConnectionCallback callback);
~BleGattServer() override = default;
absl::optional<api::ble_v2::GattCharacteristic> CreateCharacteristic(
const Uuid& service_uuid, const Uuid& characteristic_uuid,
api::ble_v2::GattCharacteristic::Permission permission,
api::ble_v2::GattCharacteristic::Property property) override;
api::ble_v2::GattCharacteristic::Property property) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool UpdateCharacteristic(
const api::ble_v2::GattCharacteristic& characteristic,
const nearby::ByteArray& value) override;
const nearby::ByteArray& value) override ABSL_LOCKS_EXCLUDED(mutex_);
absl::Status NotifyCharacteristicChanged(
const api::ble_v2::GattCharacteristic& characteristic, bool confirm,
const ByteArray& new_value) override;
const ByteArray& new_value) override ABSL_LOCKS_EXCLUDED(mutex_);
void Stop() override;
void Stop() override ABSL_LOCKS_EXCLUDED(mutex_);
bool StartAdvertisement(const ByteArray& service_data, bool is_connectable);
bool StopAdvertisement();
bool StartAdvertisement(const ByteArray& service_data, bool is_connectable)
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertisement() ABSL_LOCKS_EXCLUDED(mutex_);
void SetCloseNotifier(absl::AnyInvocable<void()> notifier)
ABSL_LOCKS_EXCLUDED(mutex_);
api::ble_v2::BlePeripheral& GetBlePeripheral() override {
return peripheral_;
@@ -78,51 +91,65 @@ class BleGattServer : public api::ble_v2::GattServer {
::winrt::event_token subscribed_clients_changed_token{};
};
bool InitializeGattServer();
bool InitializeGattServer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void NotifyValueChanged(
const api::ble_v2::GattCharacteristic& gatt_characteristic);
const api::ble_v2::GattCharacteristic& gatt_characteristic)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
GattCharacteristicData* FindGattCharacteristicData(
const ::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattLocalCharacteristic& gatt_local_characteristic);
GattLocalCharacteristic& gatt_local_characteristic)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
GattCharacteristicData* FindGattCharacteristicData(
const api::ble_v2::GattCharacteristic& gatt_characteristic);
const api::ble_v2::GattCharacteristic& gatt_characteristic)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
::winrt::fire_and_forget Characteristic_ReadRequestedAsync(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattLocalCharacteristic const& gatt_local_characteristic,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattReadRequestedEventArgs args);
GattReadRequestedEventArgs args)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
::winrt::fire_and_forget Characteristic_WriteRequestedAsync(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattLocalCharacteristic const& gatt_local_characteristic,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattWriteRequestedEventArgs args);
GattWriteRequestedEventArgs args)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void Characteristic_SubscribedClientsChanged(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattLocalCharacteristic const& gatt_local_characteristic,
::winrt::Windows::Foundation::IInspectable const& args);
::winrt::Windows::Foundation::IInspectable const& args)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void ServiceProvider_AdvertisementStatusChanged(
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattServiceProvider const& sender,
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattServiceProviderAdvertisementStatusChangedEventArgs const& args);
GattServiceProviderAdvertisementStatusChangedEventArgs const& args)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
BluetoothAdapter* adapter_ = nullptr;
absl::Mutex mutex_;
BluetoothAdapter* const adapter_ = nullptr;
BleV2Peripheral peripheral_;
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattServiceProvider gatt_service_provider_ = nullptr;
Uuid service_uuid_;
std::vector<GattCharacteristicData> gatt_characteristic_datas_;
api::ble_v2::ServerGattConnectionCallback gatt_connection_callback_{};
::winrt::event_token service_provider_advertisement_changed_token_{};
bool is_advertising_ = false;
bool is_gatt_server_inited_ = false;
::winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::
GattServiceProvider gatt_service_provider_ ABSL_GUARDED_BY(mutex_) =
nullptr;
absl::AnyInvocable<void()> close_notifier_ ABSL_GUARDED_BY(mutex_) = nullptr;
Uuid service_uuid_ ABSL_GUARDED_BY(mutex_);
std::vector<GattCharacteristicData> gatt_characteristic_datas_
ABSL_GUARDED_BY(mutex_);
bool is_advertising_ ABSL_GUARDED_BY(mutex_) = false;
bool is_gatt_server_inited_ ABSL_GUARDED_BY(mutex_) = false;
::winrt::event_token service_provider_advertisement_changed_token_
ABSL_GUARDED_BY(mutex_) = {};
};
} // namespace windows
@@ -14,10 +14,13 @@
#include "internal/platform/implementation/windows/ble_gatt_server.h"
#include <functional>
#include <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/synchronization/notification.h"
#include "absl/time/time.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
@@ -44,6 +47,23 @@ TEST(BleV2GattServer, DISABLED_Stop) {
blev2_gatt_server.Stop();
}
TEST(BleV2GattServer, DISABLED_StopNotifierIsCalled) {
BluetoothAdapter bluetoothAdapter;
BleGattServer blev2_gatt_server(&bluetoothAdapter, {});
bool is_close_notifier_called = false;
absl::Notification notification;
std::function<void()> notifier = [&is_close_notifier_called,
&notification]() {
is_close_notifier_called = true;
notification.Notify();
};
blev2_gatt_server.SetCloseNotifier(std::move(notifier));
blev2_gatt_server.Stop();
notification.WaitForNotificationWithTimeout(absl::Seconds(1));
EXPECT_TRUE(is_close_notifier_called);
}
TEST(BleV2GattServer, DISABLED_CreateCharacteristic) {
BluetoothAdapter bluetoothAdapter;
BleGattServer blev2_gatt_server(&bluetoothAdapter, {});
@@ -15,6 +15,7 @@
#include "internal/platform/implementation/windows/ble_medium.h"
#include <chrono> // NOLINT
#include <cstdint>
#include <exception>
#include <future> // NOLINT
#include <list>
@@ -26,7 +27,9 @@
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "absl/time/time.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/ble_peripheral.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/utils.h"
@@ -146,22 +149,20 @@ bool BleMedium::StartAdvertising(
const std::string& fast_advertisement_service_uuid) {
try {
if (!adapter_->IsEnabled()) {
NEARBY_LOGS(WARNING) << "BLE cannot start advertising because the "
"bluetooth adapter is not enabled.";
LOG(WARNING) << "BLE cannot start advertising because the "
"bluetooth adapter is not enabled.";
return false;
}
NEARBY_LOGS(INFO)
<< "Windows Ble StartAdvertising: service_id=" << service_id
<< ", advertisement bytes= 0x"
<< absl::BytesToHexString(advertisement_bytes.AsStringView()) << "("
<< advertisement_bytes.size() << "),"
<< " fast advertisement service uuid= 0x"
<< absl::BytesToHexString(fast_advertisement_service_uuid);
LOG(INFO) << "Windows Ble StartAdvertising: service_id=" << service_id
<< ", advertisement bytes= 0x"
<< absl::BytesToHexString(advertisement_bytes.AsStringView())
<< "(" << advertisement_bytes.size() << "),"
<< " fast advertisement service uuid= 0x"
<< absl::BytesToHexString(fast_advertisement_service_uuid);
if (is_publisher_started_) {
NEARBY_LOGS(WARNING)
<< "BLE cannot start to advertise again when it is running.";
LOG(WARNING) << "BLE cannot start to advertise again when it is running.";
return false;
}
@@ -205,8 +206,8 @@ bool BleMedium::StartAdvertising(
publisher_.UseExtendedAdvertisement(false);
} else {
// otherwise no-op
NEARBY_LOGS(INFO) << "Everyone Mode unavailable for hardware that does "
"not support Extended Advertising.";
LOG(INFO) << "Everyone Mode unavailable for hardware that does "
"not support Extended Advertising.";
publisher_ = nullptr;
return false;
}
@@ -217,21 +218,21 @@ bool BleMedium::StartAdvertising(
publisher_.Start();
is_publisher_started_ = true;
NEARBY_LOGS(INFO) << "Windows Ble StartAdvertising started.";
LOG(INFO) << "Windows Ble StartAdvertising started.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception to start BLE advertising: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Exception to start BLE advertising: " << exception.what();
return false;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Exception to start BLE advertising: " << ex.code()
<< ": " << winrt::to_string(ex.message());
LOG(ERROR) << __func__
<< ": Exception to start BLE advertising: " << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return false;
}
}
@@ -239,16 +240,15 @@ bool BleMedium::StartAdvertising(
bool BleMedium::StopAdvertising(const std::string& service_id) {
try {
if (!adapter_->IsEnabled()) {
NEARBY_LOGS(WARNING) << "BLE cannot stop advertising because the "
"bluetooth adapter is not enabled.";
LOG(WARNING) << "BLE cannot stop advertising because the "
"bluetooth adapter is not enabled.";
return false;
}
NEARBY_LOGS(INFO) << "Windows Ble StopAdvertising: service_id="
<< service_id;
LOG(INFO) << "Windows Ble StopAdvertising: service_id=" << service_id;
if (!is_publisher_started_) {
NEARBY_LOGS(WARNING) << "BLE advertising is not running.";
LOG(WARNING) << "BLE advertising is not running.";
return false;
}
@@ -266,18 +266,18 @@ bool BleMedium::StopAdvertising(const std::string& service_id) {
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception to stop BLE advertising: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Exception to stop BLE advertising: " << exception.what();
return false;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Exception to stop BLE advertising: " << ex.code()
<< ": " << winrt::to_string(ex.message());
LOG(ERROR) << __func__
<< ": Exception to stop BLE advertising: " << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return false;
}
}
@@ -288,16 +288,15 @@ bool BleMedium::StartScanning(
DiscoveredPeripheralCallback callback) {
try {
if (!adapter_->IsEnabled()) {
NEARBY_LOGS(WARNING) << "BLE cannot start scanning because the "
"bluetooth adapter is not enabled.";
LOG(WARNING) << "BLE cannot start scanning because the "
"bluetooth adapter is not enabled.";
return false;
}
NEARBY_LOGS(INFO) << "Windows Ble StartScanning: service_id=" << service_id;
LOG(INFO) << "Windows Ble StartScanning: service_id=" << service_id;
if (is_watcher_started_) {
NEARBY_LOGS(WARNING)
<< "BLE cannot start to scan again when it is running.";
LOG(WARNING) << "BLE cannot start to scan again when it is running.";
return false;
}
@@ -327,21 +326,20 @@ bool BleMedium::StartScanning(
is_watcher_started_ = true;
NEARBY_LOGS(INFO) << "Windows Ble StartScanning started.";
LOG(INFO) << "Windows Ble StartScanning started.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception to start BLE scanning: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Exception to start BLE scanning: " << exception.what();
return false;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Exception to start BLE scanning: " << ex.code()
<< ": " << winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": Exception to start BLE scanning: " << ex.code()
<< ": " << winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return false;
}
}
@@ -349,15 +347,15 @@ bool BleMedium::StartScanning(
bool BleMedium::StopScanning(const std::string& service_id) {
try {
if (!adapter_->IsEnabled()) {
NEARBY_LOGS(WARNING) << "BLE cannot stop scanning because the "
"bluetooth adapter is not enabled.";
LOG(WARNING) << "BLE cannot stop scanning because the "
"bluetooth adapter is not enabled.";
return false;
}
NEARBY_LOGS(INFO) << "Windows Ble StopScanning: service_id=" << service_id;
LOG(INFO) << "Windows Ble StopScanning: service_id=" << service_id;
if (!is_watcher_started_) {
NEARBY_LOGS(WARNING) << "BLE scanning is not running.";
LOG(WARNING) << "BLE scanning is not running.";
return false;
}
@@ -368,37 +366,35 @@ bool BleMedium::StopScanning(const std::string& service_id) {
// stopping to finish.
is_watcher_started_ = false;
NEARBY_LOGS(ERROR)
<< "Windows Ble stoped scanning successfully for service_id="
<< service_id;
LOG(ERROR) << "Windows Ble stoped scanning successfully for service_id="
<< service_id;
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception to stop BLE scanning: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Exception to stop BLE scanning: " << exception.what();
return false;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Exception to stop BLE scanning: " << ex.code()
<< ": " << winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": Exception to stop BLE scanning: " << ex.code()
<< ": " << winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return false;
}
}
bool BleMedium::StartAcceptingConnections(const std::string& service_id,
AcceptedConnectionCallback callback) {
NEARBY_LOGS(INFO) << "Windows Ble StartAcceptingConnections: service_id="
<< service_id;
LOG(INFO) << "Windows Ble StartAcceptingConnections: service_id="
<< service_id;
return true;
}
bool BleMedium::StopAcceptingConnections(const std::string& service_id) {
NEARBY_LOGS(INFO) << "Windows Ble StopAcceptingConnections: service_id="
<< service_id;
LOG(INFO) << "Windows Ble StopAcceptingConnections: service_id="
<< service_id;
return true;
}
@@ -406,15 +402,15 @@ std::unique_ptr<api::BleSocket> BleMedium::Connect(
api::BlePeripheral& remote_peripheral, const std::string& service_id,
CancellationFlag* cancellation_flag) {
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(ERROR) << "Windows BLE Connect: Has been cancelled: "
"service_id="
<< service_id;
LOG(ERROR) << "Windows BLE Connect: Has been cancelled: "
"service_id="
<< service_id;
return {};
}
NEARBY_LOGS(ERROR) << "Windows Ble Connect: Cannot connect over BLE socket. "
"service_id="
<< service_id;
LOG(ERROR) << "Windows Ble Connect: Cannot connect over BLE socket. "
"service_id="
<< service_id;
return {};
}
@@ -424,75 +420,73 @@ void BleMedium::PublisherHandler(
// This method is called when publisher's status is changed.
switch (args.Status()) {
case BluetoothLEAdvertisementPublisherStatus::Created:
NEARBY_LOGS(INFO) << "Nearby BLE Medium created to advertise.";
LOG(INFO) << "Nearby BLE Medium created to advertise.";
return;
case BluetoothLEAdvertisementPublisherStatus::Started:
NEARBY_LOGS(INFO) << "Nearby BLE Medium started to advertise.";
LOG(INFO) << "Nearby BLE Medium started to advertise.";
return;
case BluetoothLEAdvertisementPublisherStatus::Stopping:
NEARBY_LOGS(INFO) << "Nearby BLE Medium is stopping.";
LOG(INFO) << "Nearby BLE Medium is stopping.";
return;
case BluetoothLEAdvertisementPublisherStatus::Waiting:
NEARBY_LOGS(INFO) << "Nearby BLE Medium is waiting.";
LOG(INFO) << "Nearby BLE Medium is waiting.";
return;
case BluetoothLEAdvertisementPublisherStatus::Stopped:
NEARBY_LOGS(INFO) << "Nearby BLE Medium stopped to advertise.";
LOG(INFO) << "Nearby BLE Medium stopped to advertise.";
break;
case BluetoothLEAdvertisementPublisherStatus::Aborted:
switch (args.Error()) {
case BluetoothError::Success:
if (publisher_.Status() ==
BluetoothLEAdvertisementPublisherStatus::Started) {
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium start advertising operation was "
"successfully completed or serviced.";
LOG(ERROR) << "Nearby BLE Medium start advertising operation was "
"successfully completed or serviced.";
}
if (publisher_.Status() ==
BluetoothLEAdvertisementPublisherStatus::Stopped) {
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium stop advertising operation was "
"successfully completed or serviced.";
LOG(ERROR) << "Nearby BLE Medium stop advertising operation was "
"successfully completed or serviced.";
} else {
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"unknown errors.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"unknown errors.";
}
break;
case BluetoothError::RadioNotAvailable:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"radio not available.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"radio not available.";
break;
case BluetoothError::ResourceInUse:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"resource in use.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"resource in use.";
break;
case BluetoothError::DeviceNotConnected:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"remote device is not connected.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"remote device is not connected.";
break;
case BluetoothError::DisabledByPolicy:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"disabled by policy.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"disabled by policy.";
break;
case BluetoothError::DisabledByUser:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"disabled by user.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"disabled by user.";
break;
case BluetoothError::NotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"hardware not supported.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"hardware not supported.";
break;
case BluetoothError::TransportNotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"transport not supported.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"transport not supported.";
break;
case BluetoothError::ConsentRequired:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"consent required.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"consent required.";
break;
case BluetoothError::OtherError:
default:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium advertising failed due to "
"unknown errors.";
LOG(ERROR) << "Nearby BLE Medium advertising failed due to "
"unknown errors.";
break;
}
break;
@@ -502,7 +496,7 @@ void BleMedium::PublisherHandler(
// The publisher is stopped. Clean up the running publisher
if (publisher_ != nullptr) {
NEARBY_LOGS(ERROR) << "Nearby BLE Medium cleaned the publisher.";
LOG(ERROR) << "Nearby BLE Medium cleaned the publisher.";
publisher_.StatusChanged(publisher_token_);
publisher_ = nullptr;
is_publisher_started_ = false;
@@ -516,47 +510,42 @@ void BleMedium::WatcherHandler(
// information on the reason.
switch (args.Error()) {
case BluetoothError::Success:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium stoped to scan successfully.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan successfully.";
break;
case BluetoothError::RadioNotAvailable:
NEARBY_LOGS(ERROR)
LOG(ERROR)
<< "Nearby BLE Medium stoped to scan due to radio not available.";
break;
case BluetoothError::ResourceInUse:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium stoped to scan due to resource in use.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to resource in use.";
break;
case BluetoothError::DeviceNotConnected:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium stoped to scan due to "
"remote device is not connected.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to "
"remote device is not connected.";
break;
case BluetoothError::DisabledByPolicy:
NEARBY_LOGS(ERROR)
LOG(ERROR)
<< "Nearby BLE Medium stoped to scan due to disabled by policy.";
break;
case BluetoothError::DisabledByUser:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium stoped to scan due to disabled by user.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to disabled by user.";
break;
case BluetoothError::NotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium stoped to scan due to "
"hardware not supported.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to "
"hardware not supported.";
break;
case BluetoothError::TransportNotSupported:
NEARBY_LOGS(ERROR) << "Nearby BLE Medium stoped to scan due to "
"transport not supported.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to "
"transport not supported.";
break;
case BluetoothError::ConsentRequired:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium stoped to scan due to consent required.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to consent required.";
break;
case BluetoothError::OtherError:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium stoped to scan due to unknown errors.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to unknown errors.";
break;
default:
NEARBY_LOGS(ERROR)
<< "Nearby BLE Medium stoped to scan due to unknown errors.";
LOG(ERROR) << "Nearby BLE Medium stoped to scan due to unknown errors.";
break;
}
@@ -564,7 +553,7 @@ void BleMedium::WatcherHandler(
// The BLE V1 interface doesn't have an API to return the error to the upper
// layer.
if (watcher_ != nullptr) {
NEARBY_LOGS(ERROR) << "Nearby BLE Medium cleaned the watcher.";
LOG(ERROR) << "Nearby BLE Medium cleaned the watcher.";
watcher_.Stopped(watcher_token_);
watcher_.Received(advertisement_received_token_);
watcher_ = nullptr;
@@ -600,11 +589,10 @@ void BleMedium::AdvertisementReceivedHandler(
ByteArray advertisement_data(data);
NEARBY_LOGS(VERBOSE) << "Nearby BLE Medium Advertisement discovered. "
"0x16 Service data: advertisement bytes= 0x"
<< absl::BytesToHexString(
advertisement_data.AsStringView())
<< "(" << advertisement_data.size() << ")";
VLOG(1) << "Nearby BLE Medium Advertisement discovered. "
"0x16 Service data: advertisement bytes= 0x"
<< absl::BytesToHexString(advertisement_data.AsStringView())
<< "(" << advertisement_data.size() << ")";
std::string peripheral_name =
uint64_to_mac_address_string(args.BluetoothAddress());
@@ -616,7 +604,7 @@ void BleMedium::AdvertisementReceivedHandler(
if (peripheral_map_.contains(peripheral_name)) {
if (peripheral_map_[peripheral_name]->GetAdvertisementBytes(
service_id_) != advertisement_data) {
NEARBY_LOGS(INFO) << "BLE reports lost device: " << peripheral_name;
LOG(INFO) << "BLE reports lost device: " << peripheral_name;
// Lost the device first and then the report discovered the
// device.
@@ -644,15 +632,13 @@ void BleMedium::AdvertisementReceivedHandler(
// Received Fast Advertisement packet
if (unconsumed_buffer_length <= 27) {
NEARBY_LOGS(INFO)
<< "Sending Fast Advertisement packet for processing.";
LOG(INFO) << "Sending Fast Advertisement packet for processing.";
advertisement_received_callback_.peripheral_discovered_cb(
/*ble_peripheral*/ *peripheral_ptr, /*service_id*/ service_id_,
/*is_fast_advertisement*/ true);
} else {
// Received Extended Advertising packet
NEARBY_LOGS(INFO)
<< "Sending Extended Advertising packet for processing.";
LOG(INFO) << "Sending Extended Advertising packet for processing.";
advertisement_received_callback_.peripheral_discovered_cb(
/*ble_peripheral*/ *peripheral_ptr, /*service_id*/ service_id_,
/*is_fast_advertisement*/ false);
@@ -15,7 +15,10 @@
#include "internal/platform/implementation/windows/ble_socket.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/windows/ble_peripheral.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace windows {
File diff suppressed because it is too large Load Diff
@@ -15,18 +15,24 @@
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_V2_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLE_V2_H_
#include <algorithm>
#include <cstdint>
#include <memory>
#include <string>
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/byte_array.h"
#include "absl/synchronization/notification.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/ble_gatt_server.h"
#include "internal/platform/implementation/windows/ble_v2_peripheral.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/bluetooth_classic.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/output_stream.h"
#include "internal/platform/uuid.h"
#include "winrt/Windows.Devices.Bluetooth.Advertisement.h"
@@ -42,51 +48,59 @@ class BleV2Medium : public api::ble_v2::BleMedium {
// Returns true once the Ble advertising has been initiated.
bool StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertising_parameters) override;
bool StopAdvertising() override;
api::ble_v2::AdvertiseParameters advertising_parameters) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopAdvertising() override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
AdvertisingCallback callback) override;
AdvertisingCallback callback) override ABSL_LOCKS_EXCLUDED(mutex_);
bool StartScanning(const Uuid& service_uuid,
api::ble_v2::TxPowerLevel tx_power_level,
ScanCallback callback) override;
bool StopScanning() override;
ScanCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool StopScanning() override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<ScanningSession> StartScanning(
const Uuid& service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
ScanningCallback callback) override;
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override;
api::ble_v2::ServerGattConnectionCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
api::ble_v2::BlePeripheral& peripheral,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::ClientGattConnectionCallback callback) override;
api::ble_v2::ClientGattConnectionCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<api::ble_v2::BleServerSocket> OpenServerSocket(
const std::string& service_id) override;
const std::string& service_id) override ABSL_LOCKS_EXCLUDED(mutex_);
std::unique_ptr<api::ble_v2::BleSocket> Connect(
const std::string& service_id, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral& remote_peripheral,
CancellationFlag* cancellation_flag) override;
CancellationFlag* cancellation_flag) override ABSL_LOCKS_EXCLUDED(mutex_);
bool IsExtendedAdvertisementsAvailable() override;
bool GetRemotePeripheral(const std::string& mac_address,
GetRemotePeripheralCallback callback) override;
GetRemotePeripheralCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id,
GetRemotePeripheralCallback callback) override;
GetRemotePeripheralCallback callback) override
ABSL_LOCKS_EXCLUDED(mutex_);
private:
bool StartBleAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertising_parameters);
bool StopBleAdvertising();
api::ble_v2::AdvertiseParameters advertising_parameters)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool StopBleAdvertising() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool StartGattAdvertising(
const api::ble_v2::BleAdvertisementData& advertising_data,
api::ble_v2::AdvertiseParameters advertising_parameters);
bool StopGattAdvertising();
api::ble_v2::AdvertiseParameters advertising_parameters)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
bool StopGattAdvertising() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void PublisherHandler(
winrt::Windows::Devices::Bluetooth::Advertisement::
@@ -111,50 +125,53 @@ class BleV2Medium : public api::ble_v2::BleMedium {
winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcherStoppedEventArgs args);
uint64_t GenerateSessionId();
uint64_t GenerateSessionId() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns nullptr if `address` is invalid.
BleV2Peripheral* GetOrCreatePeripheral(absl::string_view address);
BleV2Peripheral* GetOrCreatePeripheral(absl::string_view address)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Returns nullptr if `id` does not match a known peripheral.
BleV2Peripheral* GetPeripheral(BleV2Peripheral::UniqueId id);
BleV2Peripheral* GetPeripheral(BleV2Peripheral::UniqueId id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void RemoveExpiredPeripherals()
ABSL_EXCLUSIVE_LOCKS_REQUIRED(peripheral_map_mutex_);
void RemoveExpiredPeripherals() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
BluetoothAdapter* adapter_;
absl::Mutex mutex_;
BluetoothAdapter* const adapter_;
Uuid service_uuid_;
api::ble_v2::TxPowerLevel tx_power_level_;
ScanCallback scan_callback_;
absl::Mutex map_mutex_;
// std::map<Uuid, std::map<uint64_t, ScanningCallback>>
absl::flat_hash_map<Uuid, absl::flat_hash_map<uint64_t, ScanningCallback>>
service_uuid_to_session_map_ ABSL_GUARDED_BY(map_mutex_);
service_uuid_to_session_map_ ABSL_GUARDED_BY(mutex_);
// WinRT objects
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementPublisher publisher_ = nullptr;
BluetoothLEAdvertisementPublisher publisher_ ABSL_GUARDED_BY(mutex_) =
nullptr;
::winrt::Windows::Devices::Bluetooth::Advertisement::
BluetoothLEAdvertisementWatcher watcher_ = nullptr;
BluetoothLEAdvertisementWatcher watcher_ ABSL_GUARDED_BY(mutex_) =
nullptr;
bool is_ble_publisher_started_ = false;
bool is_gatt_publisher_started_ = false;
bool is_watcher_started_ = false;
bool is_ble_publisher_started_ ABSL_GUARDED_BY(mutex_) = false;
bool is_gatt_publisher_started_ ABSL_GUARDED_BY(mutex_) = false;
bool is_watcher_started_ ABSL_GUARDED_BY(mutex_) = false;
::winrt::event_token publisher_token_;
::winrt::event_token watcher_token_;
::winrt::event_token advertisement_received_token_;
::winrt::event_token publisher_token_ ABSL_GUARDED_BY(mutex_);
::winrt::event_token watcher_token_ ABSL_GUARDED_BY(mutex_);
::winrt::event_token advertisement_received_token_ ABSL_GUARDED_BY(mutex_);
BleGattServer* ble_gatt_server_ = nullptr;
// Map to protect the pointer for BlePeripheral because
// DiscoveredPeripheralCallback only keeps the pointer to the object
absl::Mutex peripheral_map_mutex_;
struct PeripheralInfo {
absl::Time last_access_time;
std::unique_ptr<BleV2Peripheral> peripheral;
};
absl::flat_hash_map<BleV2Peripheral::UniqueId, PeripheralInfo> peripheral_map_
ABSL_GUARDED_BY(peripheral_map_mutex_);
absl::Time cleanup_time_ ABSL_GUARDED_BY(peripheral_map_mutex_) = absl::Now();
ABSL_GUARDED_BY(mutex_);
absl::Time cleanup_time_ ABSL_GUARDED_BY(mutex_) = absl::Now();
};
} // namespace windows
@@ -35,7 +35,7 @@ BleV2Peripheral::BleV2Peripheral(absl::string_view address) {
bool BleV2Peripheral::SetAddress(absl::string_view address) {
// The address must be in format "00:B0:D0:63:C2:26".
if (address.size() != kMacAddressLength) {
NEARBY_LOGS(ERROR) << ": Invalid MAC address length.";
LOG(ERROR) << ": Invalid MAC address length.";
return false;
}
@@ -52,7 +52,7 @@ bool BleV2Peripheral::SetAddress(absl::string_view address) {
}
}
NEARBY_LOGS(ERROR) << ": Invalid MAC address format.";
LOG(ERROR) << ": Invalid MAC address format.";
return false;
}
@@ -18,10 +18,11 @@
#include <exception>
#include <memory>
#include "absl/log/check.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/ble_v2_socket.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/utils.h"
@@ -37,7 +38,7 @@ BleV2ServerSocket::BleV2ServerSocket(api::BluetoothAdapter* adapter)
std::unique_ptr<api::ble_v2::BleSocket> BleV2ServerSocket::Accept() {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << __func__ << ": Accept is called.";
LOG(INFO) << __func__ << ": Accept is called.";
while (!closed_ && pending_sockets_.empty()) {
cond_.Wait(&mutex_);
@@ -47,14 +48,14 @@ std::unique_ptr<api::ble_v2::BleSocket> BleV2ServerSocket::Accept() {
BleV2Socket ble_socket = pending_sockets_.front();
pending_sockets_.pop_front();
NEARBY_LOGS(INFO) << __func__ << ": Accepted a remote connection.";
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<BleV2Socket>(ble_socket);
}
Exception BleV2ServerSocket::Close() {
// TODO(b/271031645): implement BLE socket using weave
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << __func__ << ": Close is called.";
LOG(INFO) << __func__ << ": Close is called.";
if (closed_) {
return {Exception::kSuccess};
@@ -68,7 +69,7 @@ Exception BleV2ServerSocket::Close() {
bool BleV2ServerSocket::Bind() {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(ERROR) << __func__ << ": GATT socket started.";
LOG(ERROR) << __func__ << ": GATT socket started.";
return true;
}
@@ -15,6 +15,7 @@
#include "internal/platform/implementation/windows/ble_v2_socket.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include "absl/synchronization/mutex.h"
@@ -22,8 +23,11 @@
#include "absl/time/time.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/input_stream.h"
#include "internal/platform/logging.h"
#include "internal/platform/output_stream.h"
namespace nearby {
namespace windows {
@@ -40,38 +44,38 @@ api::ble_v2::BlePeripheral* BleV2Socket::GetRemotePeripheral() {
bool BleV2Socket::Connect(api::ble_v2::BlePeripheral* ble_peripheral) {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(VERBOSE) << __func__ << ": Connect to BLE peripheral="
<< ble_peripheral->GetAddress();
VLOG(1) << __func__
<< ": Connect to BLE peripheral=" << ble_peripheral->GetAddress();
return false;
}
ExceptionOr<ByteArray> BleV2Socket::BleInputStream::Read(std::int64_t size) {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(VERBOSE) << __func__ << ": Read data size=" << size;
VLOG(1) << __func__ << ": Read data size=" << size;
return ExceptionOr<ByteArray>(Exception::kIo);
}
Exception BleV2Socket::BleInputStream::Close() {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(VERBOSE) << __func__ << ": Close BLE input stream.";
VLOG(1) << __func__ << ": Close BLE input stream.";
return {Exception::kSuccess};
}
Exception BleV2Socket::BleOutputStream::Write(const ByteArray& data) {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(VERBOSE) << __func__ << ": Write data size=" << data.size();
VLOG(1) << __func__ << ": Write data size=" << data.size();
return {Exception::kIo};
}
Exception BleV2Socket::BleOutputStream::Flush() {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(INFO) << __func__ << ": Flush is called.";
LOG(INFO) << __func__ << ": Flush is called.";
return {Exception::kSuccess};
}
Exception BleV2Socket::BleOutputStream::Close() {
// TODO(b/271031645): implement BLE socket using weave
NEARBY_LOGS(INFO) << __func__ << ": close is called.";
LOG(INFO) << __func__ << ": close is called.";
return {Exception::kSuccess};
}
@@ -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.
@@ -32,12 +32,17 @@
#include <stdio.h>
#include <usbiodef.h>
#include <cstdint>
#include <cstring>
#include <exception>
#include <optional>
#include <string>
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "third_party/json/src/json.hpp"
#include "internal/platform/feature_flags.h"
#include "internal/platform/implementation/platform.h"
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/logging.h"
@@ -85,8 +90,7 @@ BluetoothAdapter::BluetoothAdapter() : windows_bluetooth_adapter_(nullptr) {
winrt::Windows::Devices::Bluetooth::BluetoothAdapter::GetDefaultAsync()
.get();
if (windows_bluetooth_adapter_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": No Bluetooth adapter on this device.";
LOG(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
} else {
// Gets the radio represented by this Bluetooth adapter.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.getradioasync?view=winrt-20348
@@ -94,20 +98,20 @@ BluetoothAdapter::BluetoothAdapter() : windows_bluetooth_adapter_(nullptr) {
windows_bluetooth_adapter_.GetRadioAsync().get();
}
} catch (const winrt::hresult_error &error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
}
}
// Synchronously sets the status of the BluetoothAdapter to 'status', and
// returns true if the operation was a success.
bool BluetoothAdapter::SetStatus(Status status) {
NEARBY_LOGS(ERROR) << __func__ << ": Set Bluetooth radio status to "
<< (status == Status::kEnabled ? "On" : "Off");
LOG(ERROR) << __func__ << ": Set Bluetooth radio status to "
<< (status == Status::kEnabled ? "On" : "Off");
if (windows_bluetooth_radio_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": No Bluetooth radio on this device.";
LOG(ERROR) << __func__ << ": No Bluetooth radio on this device.";
return false;
}
@@ -116,25 +120,23 @@ bool BluetoothAdapter::SetStatus(Status status) {
if (status == Status::kDisabled &&
(radio_state == RadioState::Unknown || radio_state == RadioState::Off ||
radio_state == RadioState::Disabled)) {
NEARBY_LOGS(INFO)
<< __func__
<< ": Skip set radio status kDisabled due to requested state is "
"already kDisabled.";
LOG(INFO) << __func__
<< ": Skip set radio status kDisabled due to requested state is "
"already kDisabled.";
return true;
}
if (status == Status::kEnabled && radio_state == RadioState::On) {
NEARBY_LOGS(INFO)
<< __func__
<< ": Skip set radio status kEnabled due to requested state is "
"already kEnabled.";
LOG(INFO) << __func__
<< ": Skip set radio status kEnabled due to requested state is "
"already kEnabled.";
return true;
}
if (!FeatureFlags::GetInstance().GetFlags().enable_set_radio_state) {
NEARBY_LOGS(INFO) << __func__
<< ": Attempt to set the radio state while "
"FeatureFlags::enable_set_radio_state is false.";
LOG(INFO) << __func__
<< ": Attempt to set the radio state while "
"FeatureFlags::enable_set_radio_state is false.";
return false;
}
@@ -148,22 +150,19 @@ bool BluetoothAdapter::SetStatus(Status status) {
windows_bluetooth_radio_.SetStateAsync(RadioState::On).get();
}
} catch (const winrt::hresult_error &ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set Bluetooth radio state to "
<< (status == Status::kDisabled ? "kDisabled."
: "kEnabled.")
<< "Exception: " << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": Failed to set Bluetooth radio state to "
<< (status == Status::kDisabled ? "kDisabled." : "kEnabled.")
<< "Exception: " << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
return false;
}
NEARBY_LOGS(INFO) << __func__ << ": Successfully set the radio state to "
<< (status == Status::kDisabled ? "kDisabled."
: "kEnabled.");
LOG(INFO) << __func__ << ": Successfully set the radio state to "
<< (status == Status::kDisabled ? "kDisabled." : "kEnabled.");
return true;
}
@@ -171,7 +170,7 @@ bool BluetoothAdapter::SetStatus(Status status) {
// Status::Value::kEnabled.
bool BluetoothAdapter::IsEnabled() const {
if (windows_bluetooth_radio_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": No Bluetooth radio on this device.";
LOG(ERROR) << __func__ << ": No Bluetooth radio on this device.";
return false;
}
try {
@@ -179,14 +178,14 @@ bool BluetoothAdapter::IsEnabled() const {
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radio.state?view=winrt-20348
return windows_bluetooth_radio_.State() == RadioState::On;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << exception.what();
LOG(ERROR) << __func__ << ": exception:" << exception.what();
return false;
} catch (const winrt::hresult_error &ex) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
return false;
}
}
@@ -195,7 +194,7 @@ bool BluetoothAdapter::IsEnabled() const {
// Advertising
bool BluetoothAdapter::IsExtendedAdvertisingSupported() const {
if (windows_bluetooth_adapter_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
LOG(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
return false;
}
try {
@@ -204,14 +203,83 @@ bool BluetoothAdapter::IsExtendedAdvertisingSupported() const {
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.isextendedadvertisingsupported?view=winrt-22621
return windows_bluetooth_adapter_.IsExtendedAdvertisingSupported();
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << exception.what();
LOG(ERROR) << __func__ << ": exception:" << exception.what();
return false;
} catch (const winrt::hresult_error &ex) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
return false;
}
}
// Returns true if the Bluetooth hardware supports BLE Central Role
bool BluetoothAdapter::IsCentralRoleSupported() const {
if (windows_bluetooth_adapter_ == nullptr) {
LOG(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
return false;
}
try {
// Indicates whether the adapter supports the BLE Central Role
// https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.iscentralrolesupported?view=winrt-22621
return windows_bluetooth_adapter_.IsCentralRoleSupported();
} catch (std::exception exception) {
LOG(ERROR) << __func__ << ": exception:" << exception.what();
return false;
} catch (const winrt::hresult_error &ex) {
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
LOG(ERROR) << __func__ << ": unknown error.";
return false;
}
}
// Returns true if the Bluetooth hardware supports BLE Peripheral Role
bool BluetoothAdapter::IsPeripheralRoleSupported() const {
if (windows_bluetooth_adapter_ == nullptr) {
LOG(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
return false;
}
try {
// Indicates whether the adapter supports the BLE Peripheral Role
// https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.isperipheralrolesupported?view=winrt-22621
return windows_bluetooth_adapter_.IsPeripheralRoleSupported();
} catch (std::exception exception) {
LOG(ERROR) << __func__ << ": exception:" << exception.what();
return false;
} catch (const winrt::hresult_error &ex) {
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
LOG(ERROR) << __func__ << ": unknown error.";
return false;
}
}
// Returns true if the Bluetooth hardware supports BLE
bool BluetoothAdapter::IsLowEnergySupported() const {
if (windows_bluetooth_adapter_ == nullptr) {
LOG(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
return false;
}
try {
// Indicates whether the adapter supports BLE
// https://learn.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.islowenergysupported?view=winrt-22621
return windows_bluetooth_adapter_.IsLowEnergySupported();
} catch (std::exception exception) {
LOG(ERROR) << __func__ << ": exception:" << exception.what();
return false;
} catch (const winrt::hresult_error &ex) {
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
return false;
} catch (...) {
LOG(ERROR) << __func__ << ": unknown error.";
return false;
}
}
@@ -248,13 +316,13 @@ void BluetoothAdapter::RestoreRadioNameIfNecessary() {
auto settings_file =
nearby::api::ImplementationPlatform::CreateInputFile(full_path, 0);
if (settings_file == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to create input file.";
LOG(ERROR) << __func__ << ": Failed to create input file.";
return;
}
auto total_size = settings_file->GetTotalSize();
if (total_size == 0) {
NEARBY_LOGS(WARNING) << __func__ << ": No data for local settings.";
LOG(WARNING) << __func__ << ": No data for local settings.";
return;
}
@@ -264,7 +332,7 @@ void BluetoothAdapter::RestoreRadioNameIfNecessary() {
settings_file->Close();
if (!raw_local_settings.ok()) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to read data file.";
LOG(ERROR) << __func__ << ": Failed to read data file.";
return;
}
@@ -272,12 +340,11 @@ void BluetoothAdapter::RestoreRadioNameIfNecessary() {
json::parse(raw_local_settings.GetResult().data(), nullptr, false);
if (local_settings.is_discarded()) {
NEARBY_LOGS(ERROR) << __func__ << ": Invalid local settings data.";
LOG(ERROR) << __func__ << ": Invalid local settings data.";
return;
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": loaded settings: " << local_settings.dump();
VLOG(1) << __func__ << ": loaded settings: " << local_settings.dump();
LocalSettings settings = local_settings.get<LocalSettings>();
@@ -286,10 +353,10 @@ void BluetoothAdapter::RestoreRadioNameIfNecessary() {
/* persist= */ true);
}
} catch (const winrt::hresult_error &ex) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
}
}
@@ -297,9 +364,8 @@ void BluetoothAdapter::StoreRadioNames(absl::string_view original_radio_name,
absl::string_view nearby_radio_name) {
try {
if (original_radio_name.empty() || nearby_radio_name.empty()) {
NEARBY_LOGS(ERROR)
<< __func__
<< ":Failed to save radio names due to invalid parameters.";
LOG(ERROR) << __func__
<< ":Failed to save radio names due to invalid parameters.";
return;
}
@@ -311,7 +377,7 @@ void BluetoothAdapter::StoreRadioNames(absl::string_view original_radio_name,
nearby::api::ImplementationPlatform::CreateOutputFile(full_path);
if (settings_file == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to create output file.";
LOG(ERROR) << __func__ << ": Failed to create output file.";
return;
}
@@ -320,18 +386,18 @@ void BluetoothAdapter::StoreRadioNames(absl::string_view original_radio_name,
json encoded_local_settings;
to_json(encoded_local_settings, local_settings);
NEARBY_LOGS(VERBOSE) << __func__ << ": saved settings: "
<< encoded_local_settings.dump();
VLOG(1) << __func__
<< ": saved settings: " << encoded_local_settings.dump();
ByteArray data(encoded_local_settings.dump());
settings_file->Write(data);
settings_file->Close();
} catch (const winrt::hresult_error &ex) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
}
}
@@ -342,20 +408,22 @@ std::string BluetoothAdapter::GetName() const {
return *device_name_;
}
char *_instance_id = GetGenericBluetoothAdapterInstanceID();
if (_instance_id == nullptr) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to get Generic Bluetooth Adapter InstanceID";
std::optional<std::string> adapter_instance_id =
GetGenericBluetoothAdapterInstanceID();
if (!adapter_instance_id.has_value()) {
LOG(ERROR) << __func__
<< ": Failed to get Generic Bluetooth Adapter InstanceID";
return std::string();
}
std::string instance_id(_instance_id);
std::string instance_id = *adapter_instance_id;
// Change radio module local name in registry
HKEY hKey;
// Retrieve the size required
size_t registry_query_size = absl::SNPrintF(nullptr, // output
char empty[0];
size_t registry_query_size = absl::SNPrintF(empty, // output
0, // size
REGISTRY_QUERY_FORMAT, // format
instance_id.c_str()); // args
@@ -410,18 +478,18 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
StoreRadioNames(GetName(), name);
}
if (name.size() > 248 * sizeof(char)) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set name for bluetooth adapter because "
"the name exceeded the 248 bytes limit for Windows.";
LOG(ERROR) << __func__
<< ": Failed to set name for bluetooth adapter because "
"the name exceeded the 248 bytes limit for Windows.";
return false;
}
if (name.size() > kAndroidDiscoverableBluetoothNameMaxLength * sizeof(char)) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set name for bluetooth adapter because "
"Android cannot discover Windows bluetooth device "
"name that exceeded the 37 bytes limit (11 "
"characters in EndpointInfo).";
LOG(ERROR) << __func__
<< ": Failed to set name for bluetooth adapter because "
"Android cannot discover Windows bluetooth device "
"name that exceeded the 37 bytes limit (11 "
"characters in EndpointInfo).";
device_name_ = std::string(name);
return true;
}
@@ -429,19 +497,22 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
device_name_ = std::nullopt;
if (registry_bluetooth_adapter_name_ == name) {
NEARBY_LOGS(INFO) << __func__
<< ": Tried to set name for bluetooth adapter to the "
"same name again.";
LOG(INFO) << __func__
<< ": Tried to set name for bluetooth adapter to the "
"same name again.";
return true;
}
std::string instance_id(GetGenericBluetoothAdapterInstanceID());
std::optional<std::string> adapter_instance_id =
GetGenericBluetoothAdapterInstanceID();
if (instance_id.empty()) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Failed to get Generic Bluetooth Adapter InstanceID";
if (!adapter_instance_id.has_value()) {
LOG(ERROR) << __func__
<< ": Failed to get Generic Bluetooth Adapter InstanceID";
return false;
}
std::string instance_id = *adapter_instance_id;
// defined in usbiodef.h
const GUID guid = GUID_DEVINTERFACE_USB_DEVICE;
@@ -461,7 +532,7 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
StringFromGUID2(guid, guid_ole_str, guid_ole_str_size);
if (conversionResult == 0) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to convert guid to string";
LOG(ERROR) << __func__ << ": Failed to convert guid to string";
return false;
}
std::string guid_str;
@@ -523,9 +594,9 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
// Convert the P&P instance id, to one that CreateFileA expects
find_and_replace(instance_id_modified.data(), "\\", "#");
size_t file_name_size =
absl::SNPrintF(nullptr, 0, "\\\\.\\%s#%s", instance_id_modified.c_str(),
guid_str.c_str());
char empty[0];
size_t file_name_size = absl::SNPrintF(
empty, 0, "\\\\.\\%s#%s", instance_id_modified.c_str(), guid_str.c_str());
std::string file_name;
file_name.reserve(file_name_size + 1);
@@ -552,15 +623,15 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
// access right. This parameter can be NULL.
if (hDevice == INVALID_HANDLE_VALUE) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to open device. Error code: "
<< GetLastError();
LOG(ERROR) << __func__
<< ": Failed to open device. Error code: " << GetLastError();
return false;
}
// Change radio module local name in registry
HKEY hKey;
size_t buffer_size =
absl::SNPrintF(nullptr, 0, REGISTRY_QUERY_FORMAT, instance_id);
absl::SNPrintF(empty, 0, REGISTRY_QUERY_FORMAT, instance_id);
std::string local_name_key;
local_name_key.reserve(buffer_size + 1);
@@ -582,9 +653,8 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
// key.
if (status != ERROR_SUCCESS) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to open registry key. Error code: "
<< status;
LOG(ERROR) << __func__
<< ": Failed to open registry key. Error code: " << status;
return false;
}
@@ -610,9 +680,8 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
}
if (status != ERROR_SUCCESS) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set/delete registry key. Error code: "
<< status;
LOG(ERROR) << __func__
<< ": Failed to set/delete registry key. Error code: " << status;
return false;
}
@@ -642,10 +711,9 @@ bool BluetoothAdapter::SetName(absl::string_view name, bool persist) {
&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: "
<< GetLastError();
LOG(ERROR) << __func__
<< ": Failed to update radio module local name. Error code: "
<< GetLastError();
return false;
}
@@ -679,8 +747,8 @@ void BluetoothAdapter::process_error() {
break;
}
NEARBY_LOGS(ERROR) << __func__ << ": Failed to convert guid to string "
<< errorResult << " Error code:" << errorMessageID;
LOG(ERROR) << __func__ << ": Failed to convert guid to string " << errorResult
<< " Error code:" << errorMessageID;
}
void BluetoothAdapter::find_and_replace(char *source, const char *strFind,
@@ -697,7 +765,8 @@ void BluetoothAdapter::find_and_replace(char *source, const char *strFind,
memcpy(source, s.c_str(), s.size());
}
char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) const {
std::optional<std::string>
BluetoothAdapter::GetGenericBluetoothAdapterInstanceID() const {
unsigned i;
CONFIGRET r;
HDEVINFO hDevInfo;
@@ -713,9 +782,9 @@ char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) const {
SetupDiGetClassDevsA(&GUID_DEVCLASS_BLUETOOTH, NULL, NULL, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE) {
NEARBY_LOGS(ERROR) << __func__
<< ": Could not find BluetoothDevice on this machine";
return NULL;
LOG(ERROR) << __func__
<< ": Could not find BluetoothDevice on this machine";
return std::nullopt;
}
// Get first Generic Bluetooth Adapter InstanceID
@@ -741,34 +810,34 @@ char *BluetoothAdapter::GetGenericBluetoothAdapterInstanceID(void) const {
// computer's USB ports.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/bluetooth/bluetooth-host-radio-support
if (strncmp("USB", deviceInstanceID, 3) == 0) {
return deviceInstanceID;
SetupDiDestroyDeviceInfoList(hDevInfo);
return std::string(deviceInstanceID);
}
}
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get the generic bluetooth adapter id";
return NULL;
LOG(ERROR) << __func__ << ": Failed to get the generic bluetooth adapter id";
SetupDiDestroyDeviceInfoList(hDevInfo);
return std::nullopt;
}
// Returns BT MAC address assigned to this adapter.
std::string BluetoothAdapter::GetMacAddress() const {
if (windows_bluetooth_adapter_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
LOG(ERROR) << __func__ << ": No Bluetooth adapter on this device.";
return "";
}
try {
return uint64_to_mac_address_string(
windows_bluetooth_adapter_.BluetoothAddress());
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << exception.what();
LOG(ERROR) << __func__ << ": exception:" << exception.what();
return "";
} catch (const winrt::hresult_error &ex) {
NEARBY_LOGS(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": exception:" << ex.code() << ": "
<< winrt::to_string(ex.message());
return "";
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": unknown error.";
LOG(ERROR) << __func__ << ": unknown error.";
return "";
}
}
@@ -794,9 +863,8 @@ std::string BluetoothAdapter::GetNameFromRegistry(PHKEY hKey) const {
// size of the buffer pointed to by the lpData
// parameter, in bytes.
if (status != ERROR_SUCCESS) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to get the required size of the local name buffer";
LOG(ERROR) << __func__
<< ": Failed to get the required size of the local name buffer";
return "";
}
unsigned char *local_name = new unsigned char[local_name_size];
@@ -834,7 +902,7 @@ std::string BluetoothAdapter::GetNameFromComputerName() const {
return std::string(computer_name);
}
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get any computer name";
LOG(ERROR) << __func__ << ": Failed to get any computer name";
return "";
}
@@ -40,7 +40,7 @@ using WindowsBluetoothAdapter =
// Represents a radio device on the system.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radio?view=winrt-20348
using winrt::Windows::Devices::Radios::IRadio;
using winrt::Windows::Devices::Radios::Radio;
// Enumeration that describes possible radio states.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radiostate?view=winrt-20348
@@ -98,6 +98,16 @@ class BluetoothAdapter : public api::BluetoothAdapter {
// Returns true if the Bluetooth hardware supports Bluetooth 5.0 Extended
// Advertising
bool IsExtendedAdvertisingSupported() const;
// Returns true if the Bluetooth hardware supports BLE Central Role
bool IsCentralRoleSupported() const;
// Returns true if the Bluetooth hardware supports BLE Peripheral Role
bool IsPeripheralRoleSupported() const;
// Returns true if the Bluetooth hardware supports BLE
bool IsLowEnergySupported() const;
void RestoreRadioNameIfNecessary();
private:
@@ -105,11 +115,11 @@ class BluetoothAdapter : public api::BluetoothAdapter {
void StoreRadioNames(absl::string_view original_radio_name,
absl::string_view nearby_radio_name);
WindowsBluetoothAdapter windows_bluetooth_adapter_;
WindowsBluetoothAdapter windows_bluetooth_adapter_ = nullptr;
std::string registry_bluetooth_adapter_name_;
IRadio windows_bluetooth_radio_;
char *GetGenericBluetoothAdapterInstanceID() const;
Radio windows_bluetooth_radio_ = nullptr;
std::optional<std::string> GetGenericBluetoothAdapterInstanceID() const;
void find_and_replace(char *source, const char *strFind,
const char *strReplace) const;
ScanMode scan_mode_ = ScanMode::kNone;
@@ -183,6 +183,21 @@ TEST(BluetoothAdapter, DISABLED_IsExtendedAdvertisingSupported) {
EXPECT_TRUE(bluetooth_adapter.IsExtendedAdvertisingSupported());
}
TEST(BluetoothAdapter, DISABLED_IsCentralRoleSupported) {
BluetoothAdapter bluetooth_adapter;
EXPECT_TRUE(bluetooth_adapter.IsCentralRoleSupported());
}
TEST(BluetoothAdapter, DISABLED_IsPeripheralRoleSupported) {
BluetoothAdapter bluetooth_adapter;
EXPECT_TRUE(bluetooth_adapter.IsPeripheralRoleSupported());
}
TEST(BluetoothAdapter, DISABLED_IsLowEnergySupported) {
BluetoothAdapter bluetooth_adapter;
EXPECT_TRUE(bluetooth_adapter.IsLowEnergySupported());
}
TEST(BluetoothAdapter, DISABLED_GetNameFromComputerName) {
BluetoothAdapter bluetooth_adapter;
EXPECT_TRUE(!bluetooth_adapter.GetNameFromComputerName().empty());
@@ -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.
@@ -16,12 +16,17 @@
#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/flags/nearby_flags.h"
#include "internal/platform/flags/nearby_platform_feature_flags.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 +39,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() {}
@@ -71,10 +78,16 @@ std::string BluetoothDevice::GetMacAddress() const { return mac_address_; }
// Checks cache first, will check uncached if no result.
RfcommDeviceService BluetoothDevice::GetRfcommServiceForIdAsync(
const RfcommServiceId serviceId) {
RfcommServiceId serviceId) {
if (nearby::NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableNewBluetoothRefactor)) {
return GetRfcommServiceForIdWithRetryAsync(serviceId);
}
try {
NEARBY_LOGS(INFO) << __func__ << ": Get RF services for service id:"
<< winrt::to_string(serviceId.AsString());
LOG(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.
@@ -88,13 +101,12 @@ RfcommDeviceService BluetoothDevice::GetRfcommServiceForIdAsync(
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.";
LOG(ERROR) << __func__
<< ": Failed to get RfcommDeviceService due to timeout.";
rfcomm_device_services_async.Cancel();
return nullptr;
default:
NEARBY_LOGS(ERROR)
LOG(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to unknown reasons.";
return nullptr;
@@ -102,35 +114,106 @@ RfcommDeviceService BluetoothDevice::GetRfcommServiceForIdAsync(
if (rfcomm_device_services != nullptr &&
rfcomm_device_services.Services().Size() > 0) {
NEARBY_LOGS(INFO) << __func__ << ": Get "
<< rfcomm_device_services.Services().Size()
<< " services without cache.";
LOG(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.";
LOG(INFO) << __func__ << ": Found service from no-cache mode.";
return rfcomm_device_service;
}
}
}
LOG(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();
LOG(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());
LOG(ERROR) << __func__ << ": RfcommDeviceService: " << ex.code()
<< ", error message: " << winrt::to_string(ex.message());
return nullptr;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return nullptr;
}
}
// Checks cache first, will check uncached if no result.
RfcommDeviceService BluetoothDevice::GetRfcommServiceForIdWithRetryAsync(
RfcommServiceId serviceId) {
int check_service_count = 0;
while (check_service_count < kCheckBluetoothServiceMaxTimes) {
try {
LOG(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);
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:
LOG(ERROR) << __func__
<< ": Failed to get RfcommDeviceService due to timeout.";
rfcomm_device_services_async.Cancel();
return nullptr;
default:
LOG(ERROR)
<< __func__
<< ": Failed to get RfcommDeviceService due to unknown reasons.";
return nullptr;
}
if (rfcomm_device_services != nullptr &&
rfcomm_device_services.Services().Size() > 0) {
LOG(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_) {
LOG(INFO) << __func__ << ": Found service from no-cache mode.";
return rfcomm_device_service;
}
}
}
++check_service_count;
absl::SleepFor(kCheckBluetoothServiceInterval);
LOG(ERROR) << __func__ << ": No any services at " << check_service_count
<< "th check.";
} catch (std::exception exception) {
LOG(ERROR) << __func__
<< ": Failed to get RfcommDeviceService: " << exception.what();
return nullptr;
} catch (const winrt::hresult_error& ex) {
LOG(ERROR) << __func__ << ": RfcommDeviceService: " << ex.code()
<< ", error message: " << winrt::to_string(ex.message());
return nullptr;
} catch (...) {
LOG(ERROR) << __func__ << ": Unknown exception.";
return nullptr;
}
}
LOG(ERROR) << __func__ << ": Failed to get RfcommDeviceService.";
return nullptr;
}
} // namespace windows
} // namespace nearby
@@ -77,10 +77,12 @@ class BluetoothDevice : public api::BluetoothDevice {
void SetName(std::string name) { name_ = name; }
RfcommDeviceService GetRfcommServiceForIdAsync(
const winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId
serviceId);
winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId serviceId);
private:
RfcommDeviceService GetRfcommServiceForIdWithRetryAsync(
winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId serviceId);
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothdevice?view=winrt-20348
winrt::Windows::Devices::Bluetooth::BluetoothDevice windows_bluetooth_device_;
@@ -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,11 +14,9 @@
#include "internal/platform/implementation/windows/bluetooth_classic_medium.h"
#include <stdio.h>
#include <windows.h>
#include <codecvt>
#include <fstream>
#include <functional>
#include <ios>
#include <locale>
@@ -31,6 +29,8 @@
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/cancellation_flag_listener.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
@@ -49,12 +49,31 @@
namespace nearby {
namespace windows {
namespace {
using winrt::Windows::Foundation::IInspectable;
using winrt::Windows::Foundation::Collections::IMapView;
using ::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService;
using ::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId;
using ::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceProvider;
using ::winrt::Windows::Devices::Enumeration::DeviceAccessInformation;
using ::winrt::Windows::Devices::Enumeration::DeviceAccessStatus;
using ::winrt::Windows::Devices::Enumeration::DeviceInformation;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationKind;
using ::winrt::Windows::Devices::Enumeration::DeviceInformationUpdate;
using ::winrt::Windows::Devices::Enumeration::DeviceWatcher;
using ::winrt::Windows::Devices::Enumeration::DeviceWatcherStatus;
using ::winrt::Windows::Foundation::IInspectable;
using ::winrt::Windows::Foundation::Collections::IMapView;
using ::winrt::Windows::Storage::Streams::DataReader;
using ::winrt::Windows::Storage::Streams::DataWriter;
using ::winrt::Windows::Storage::Streams::UnicodeEncoding;
// Used to cntrol the dump output for device information. It is only for debug
// Used to control the dump output for device information. It is only for debug
// purpose.
constexpr bool kEnableDumpDeviceInfomation = false;
// The maximum length of Bluetooth device name Android can discover.
constexpr int kAndroidDiscoverableBluetoothNameMaxLength = 37; // bytes
// Used to select bluetooth devices.
constexpr wchar_t kBluetoothSelector[] =
L"System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}"
L"\"";
void DumpDeviceInformation(
const IMapView<winrt::hstring, IInspectable>& properties) {
@@ -68,31 +87,29 @@ void DumpDeviceInformation(
for (const auto& property : properties) {
if (property.Key() == L"System.ItemNameDisplay") {
NEARBY_LOGS(INFO) << "System.ItemNameDisplay: "
<< InspectableReader::ReadString(property.Value());
LOG(INFO) << "System.ItemNameDisplay: "
<< InspectableReader::ReadString(property.Value());
} else if (property.Key() == L"System.Devices.Aep.CanPair") {
NEARBY_LOGS(INFO) << "System.Devices.Aep.CanPair: "
<< InspectableReader::ReadBoolean(property.Value());
LOG(INFO) << "System.Devices.Aep.CanPair: "
<< InspectableReader::ReadBoolean(property.Value());
} else if (property.Key() == L"System.Devices.Aep.IsPaired") {
NEARBY_LOGS(INFO) << "System.Devices.Aep.IsPaired: "
<< InspectableReader::ReadBoolean(property.Value());
LOG(INFO) << "System.Devices.Aep.IsPaired: "
<< InspectableReader::ReadBoolean(property.Value());
} else if (property.Key() == L"System.Devices.Aep.IsPresent") {
NEARBY_LOGS(INFO) << "System.Devices.Aep.IsPresent: "
<< InspectableReader::ReadBoolean(property.Value());
LOG(INFO) << "System.Devices.Aep.IsPresent: "
<< InspectableReader::ReadBoolean(property.Value());
} else if (property.Key() == L"System.Devices.Aep.DeviceAddress") {
NEARBY_LOGS(INFO) << "System.Devices.Aep.DeviceAddress: "
<< InspectableReader::ReadString(property.Value());
LOG(INFO) << "System.Devices.Aep.DeviceAddress: "
<< InspectableReader::ReadString(property.Value());
}
}
}
} // namespace
constexpr uint8_t kAndroidDiscoverableBluetoothNameMaxLength = 37; // bytes
BluetoothClassicMedium::BluetoothClassicMedium(
api::BluetoothAdapter& bluetoothAdapter)
: bluetooth_adapter_(dynamic_cast<BluetoothAdapter&>(bluetoothAdapter)) {
api::BluetoothAdapter& bluetooth_adapter)
: bluetooth_adapter_(dynamic_cast<BluetoothAdapter&>(bluetooth_adapter)) {
InitializeDeviceWatcher();
bluetooth_adapter_.RestoreRadioNameIfNecessary();
@@ -103,17 +120,16 @@ BluetoothClassicMedium::BluetoothClassicMedium(
BluetoothClassicMedium::~BluetoothClassicMedium() {}
void BluetoothClassicMedium::OnScanModeChanged(
BluetoothAdapter::ScanMode scanMode) {
NEARBY_LOGS(INFO) << __func__
<< ": OnScanModeChanged is called with scanMode: "
<< static_cast<int>(scanMode);
BluetoothAdapter::ScanMode scan_mode) {
LOG(INFO) << __func__ << ": OnScanModeChanged is called with scanMode: "
<< static_cast<int>(scan_mode);
if (scanMode == scan_mode_) {
NEARBY_LOGS(INFO) << __func__ << ": No change of scan mode.";
if (scan_mode == scan_mode_) {
LOG(INFO) << __func__ << ": No change of scan mode.";
return;
}
scan_mode_ = scanMode;
scan_mode_ = scan_mode;
bool radio_discoverable =
scan_mode_ == BluetoothAdapter::ScanMode::kConnectableDiscoverable;
@@ -125,12 +141,12 @@ void BluetoothClassicMedium::OnScanModeChanged(
}
if (is_radio_discoverable_ == radio_discoverable) {
NEARBY_LOGS(INFO) << __func__ << ": No change of radio discovery.";
LOG(INFO) << __func__ << ": No change of radio discovery.";
return;
}
if (rfcomm_provider_ == nullptr) {
NEARBY_LOGS(INFO) << __func__ << ": No advertising.";
LOG(WARNING) << __func__ << ": No advertising.";
return;
}
@@ -141,23 +157,22 @@ void BluetoothClassicMedium::OnScanModeChanged(
is_radio_discoverable_ = radio_discoverable;
return;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": OnScanModeChanged exception: " << exception.what();
LOG(ERROR) << __func__
<< ": OnScanModeChanged exception: " << exception.what();
return;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": OnScanModeChanged exception: " << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": OnScanModeChanged exception: " << ex.code()
<< ": " << winrt::to_string(ex.message());
return;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return;
}
}
bool BluetoothClassicMedium::StartDiscovery(
BluetoothClassicMedium::DiscoveryCallback discovery_callback) {
NEARBY_LOGS(INFO) << "StartDiscovery is called.";
LOG(INFO) << "StartDiscovery is called.";
bool result = false;
discovery_callback_ = std::move(discovery_callback);
@@ -170,7 +185,7 @@ bool BluetoothClassicMedium::StartDiscovery(
}
bool BluetoothClassicMedium::StopDiscovery() {
NEARBY_LOGS(INFO) << "StopDiscovery is called.";
LOG(INFO) << "StopDiscovery is called.";
bool result = false;
@@ -184,14 +199,14 @@ bool BluetoothClassicMedium::StopDiscovery() {
void BluetoothClassicMedium::InitializeDeviceWatcher() {
try {
// create watcher
const winrt::param::iterable<winrt::hstring> RequestedProperties =
const winrt::param::iterable<winrt::hstring> requested_properties =
winrt::single_threaded_vector<winrt::hstring>(
{winrt::to_hstring("System.Devices.Aep.IsPresent"),
winrt::to_hstring("System.Devices.Aep.DeviceAddress")});
device_watcher_ = DeviceInformation::CreateWatcher(
BLUETOOTH_SELECTOR, // aqsFilter
RequestedProperties, // additionalProperties
kBluetoothSelector, // aqsFilter
requested_properties, // additionalProperties
DeviceInformationKind::AssociationEndpoint); // kind
// An app must subscribe to all of the added, removed, and updated events
@@ -217,14 +232,14 @@ void BluetoothClassicMedium::InitializeDeviceWatcher() {
device_watcher_.Removed(
{this, &BluetoothClassicMedium::DeviceWatcher_Removed});
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": InitializeDeviceWatcher exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": InitializeDeviceWatcher exception: " << exception.what();
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": InitializeDeviceWatcher exception: " << ex.code()
<< ": " << winrt::to_string(ex.message());
LOG(ERROR) << __func__
<< ": InitializeDeviceWatcher exception: " << ex.code() << ": "
<< winrt::to_string(ex.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
}
@@ -232,9 +247,9 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
api::BluetoothDevice& remote_device, const std::string& service_uuid,
CancellationFlag* cancellation_flag) {
try {
NEARBY_LOGS(INFO) << "ConnectToService is called.";
LOG(INFO) << "ConnectToService is called.";
if (service_uuid.empty()) {
NEARBY_LOGS(ERROR) << __func__ << ": service_uuid not specified.";
LOG(ERROR) << __func__ << ": service_uuid not specified.";
return nullptr;
}
@@ -246,83 +261,51 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
// Must check for valid pattern as the guid constructor will throw on an
// invalid format
if (!std::regex_match(service_uuid, pattern)) {
NEARBY_LOGS(ERROR) << __func__
<< ": invalid service_uuid: " << service_uuid;
LOG(ERROR) << __func__ << ": invalid service_uuid: " << service_uuid;
return nullptr;
}
winrt::guid service(service_uuid);
if (cancellation_flag == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": cancellation_flag not specified.";
LOG(ERROR) << __func__ << ": cancellation_flag not specified.";
return nullptr;
}
remote_device_to_connect_ =
std::make_unique<BluetoothDevice>(remote_device.GetMacAddress());
auto remote_device_to_connect_ = dynamic_cast<BluetoothDevice*>(
GetRemoteDevice(remote_device.GetMacAddress()));
// First try, check if the remote device that we want to request connection
// to has already been discovered by the Bluetooth Classic Device Watcher
// beforehand inside the discovered_devices_by_id_ map
std::map<winrt::hstring, std::unique_ptr<BluetoothDevice>>::const_iterator
it = discovered_devices_by_id_.find(
winrt::to_hstring(remote_device_to_connect_->GetId()));
std::unique_ptr<BluetoothDevice> device = nullptr;
BluetoothDevice* current_device = nullptr;
if (it != discovered_devices_by_id_.end()) {
current_device = it->second.get();
} else {
// The remote device was not discovered by the Bluetooth Classic Device
// Watcher beforehand.
// Second try, request Windows to scan for nearby
// bluetooth devices that has this static mac address again in this
// instance
auto remote_bluetooth_device_from_mac_address =
winrt::Windows::Devices::Bluetooth::BluetoothDevice::
FromBluetoothAddressAsync(
mac_address_string_to_uint64(remote_device.GetMacAddress()))
.get();
if (remote_bluetooth_device_from_mac_address == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Windows failed to get remote bluetooth device "
"from static mac address.";
return nullptr;
}
device = std::make_unique<BluetoothDevice>(
remote_bluetooth_device_from_mac_address);
current_device = device.get();
}
if (current_device == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get current device.";
if (remote_device_to_connect_ == nullptr ||
remote_device_to_connect_->GetId().empty()) {
LOG(ERROR) << __func__
<< ": Failed to get remote device from MAC address.";
return nullptr;
}
winrt::hstring device_id = winrt::to_hstring(current_device->GetId());
winrt::hstring device_id =
winrt::to_hstring(remote_device_to_connect_->GetId());
if (!HaveAccess(device_id)) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to gain access to device: "
<< winrt::to_string(device_id);
LOG(ERROR) << __func__ << ": Failed to gain access to device: "
<< winrt::to_string(device_id);
return nullptr;
}
RfcommDeviceService requested_service(
GetRequestedService(current_device, service));
GetRequestedService(remote_device_to_connect_, service));
if (!FeatureFlags::GetInstance()
.GetFlags()
.skip_service_discovery_before_connecting_to_rfcomm &&
!CheckSdp(requested_service)) {
NEARBY_LOGS(ERROR) << __func__ << ": Invalid SDP.";
LOG(ERROR) << __func__ << ": Invalid SDP.";
return nullptr;
}
auto rfcomm_socket = std::make_unique<BluetoothSocket>();
if (cancellation_flag->Cancelled()) {
NEARBY_LOGS(INFO)
LOG(INFO)
<< __func__
<< ": Bluetooth Classic socket connection cancelled for device: "
<< winrt::to_string(device_id) << ", service: " << service_uuid;
@@ -342,25 +325,25 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
} catch (std::exception exception) {
// We will log and eat the exception since the caller
// expects nullptr if it fails
NEARBY_LOGS(ERROR) << __func__ << ": Exception connecting bluetooth async: "
<< exception.what();
LOG(ERROR) << __func__ << ": Exception connecting bluetooth async: "
<< exception.what();
return nullptr;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Exception connecting bluetooth async, error code: "
<< ex.code()
<< ", error message: " << winrt::to_string(ex.message());
LOG(ERROR) << __func__
<< ": Exception connecting bluetooth async, error code: "
<< ex.code()
<< ", error message: " << winrt::to_string(ex.message());
return nullptr;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return nullptr;
}
}
std::unique_ptr<api::BluetoothPairing> BluetoothClassicMedium::CreatePairing(
api::BluetoothDevice& remote_device) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to createPairing with device: "
<< remote_device.GetMacAddress();
VLOG(1) << __func__ << ": Start to createPairing with device: "
<< remote_device.GetMacAddress();
try {
winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device =
winrt::Windows::Devices::Bluetooth::BluetoothDevice::
@@ -374,18 +357,15 @@ std::unique_ptr<api::BluetoothPairing> BluetoothClassicMedium::CreatePairing(
return std::make_unique<BluetoothPairing>(bluetooth_device,
custom_pairing);
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Failed to get DeviceInformationCustomPairing.";
VLOG(1) << __func__ << ": Failed to get DeviceInformationCustomPairing.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << " : Failed to create pairing. exception: "
<< exception.what();
LOG(ERROR) << __func__ << " : Failed to create pairing. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to create pairing. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": Failed to create pairing. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return nullptr;
}
@@ -420,39 +400,39 @@ bool BluetoothClassicMedium::HaveAccess(winrt::hstring device_id) {
RfcommDeviceService BluetoothClassicMedium::GetRequestedService(
BluetoothDevice* device, winrt::guid service) {
RfcommServiceId rfcommServiceId = RfcommServiceId::FromUuid(service);
return device->GetRfcommServiceForIdAsync(rfcommServiceId);
RfcommServiceId rfcomm_service_id = RfcommServiceId::FromUuid(service);
return device->GetRfcommServiceForIdAsync(rfcomm_service_id);
}
bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requested_service) {
// Do various checks of the SDP record to make sure you are talking to a
// device that actually supports the Bluetooth Rfcomm Service
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommdeviceservice.getsdprawattributesasync?view=winrt-20348
try {
if (requestedService == nullptr) {
if (requested_service == nullptr) {
LOG(WARNING) << __func__ << ": Request service is empty.";
return false;
}
auto attributes = requestedService.GetSdpRawAttributesAsync().get();
auto attributes = requested_service.GetSdpRawAttributesAsync().get();
if (!attributes.HasKey(Constants::SdpServiceNameAttributeId)) {
NEARBY_LOGS(ERROR) << __func__ << ": Missing SdpServiceNameAttributeId.";
LOG(ERROR) << __func__ << ": Missing SdpServiceNameAttributeId.";
return false;
}
auto attributeReader = DataReader::FromBuffer(
auto attribute_reader = DataReader::FromBuffer(
attributes.Lookup(Constants::SdpServiceNameAttributeId));
auto attributeType = attributeReader.ReadByte();
auto attribute_type = attribute_reader.ReadByte();
if (attributeType != Constants::SdpServiceNameAttributeType) {
NEARBY_LOGS(ERROR) << __func__
<< ": Missing SdpServiceNameAttributeType.";
if (attribute_type != Constants::SdpServiceNameAttributeType) {
LOG(ERROR) << __func__ << ": Missing SdpServiceNameAttributeType.";
return false;
}
return true;
} catch (...) {
NEARBY_LOGS(ERROR) << "Failed to get SDP information.";
LOG(ERROR) << "Failed to get SDP information.";
return false;
}
}
@@ -469,15 +449,15 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
std::unique_ptr<api::BluetoothServerSocket>
BluetoothClassicMedium::ListenForService(const std::string& service_name,
const std::string& service_uuid) {
NEARBY_LOGS(INFO) << "ListenForService is called with service name: "
<< service_name << ".";
LOG(INFO) << "ListenForService is called with service name: " << service_name
<< ".";
if (service_uuid.empty()) {
NEARBY_LOGS(ERROR) << __func__ << ": service_uuid was empty.";
LOG(ERROR) << __func__ << ": service_uuid was empty.";
return nullptr;
}
if (service_name.empty()) {
NEARBY_LOGS(ERROR) << __func__ << ": service_name was empty.";
LOG(ERROR) << __func__ << ": service_name was empty.";
return nullptr;
}
@@ -486,15 +466,14 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name,
scan_mode_ = bluetooth_adapter_.GetScanMode();
NEARBY_LOGS(INFO) << __func__
<< ": scan_mode: " << static_cast<int>(scan_mode_);
LOG(INFO) << __func__ << ": scan_mode: " << static_cast<int>(scan_mode_);
bool radio_discoverable =
scan_mode_ == BluetoothAdapter::ScanMode::kConnectableDiscoverable;
bool result = StartAdvertising(radio_discoverable);
if (!result) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to start listening.";
LOG(ERROR) << __func__ << ": Failed to start listening.";
return nullptr;
}
@@ -503,19 +482,34 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name,
api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
const std::string& mac_address) {
return new BluetoothDevice(mac_address);
auto it = mac_address_to_bluetooth_device_map_.find(mac_address);
if (it == mac_address_to_bluetooth_device_map_.end()) {
LOG(WARNING) << __func__ << ": Bluetooth device " << mac_address
<< " is not in list. create it";
auto bluetooth_device = std::make_unique<BluetoothDevice>(mac_address);
mac_address_to_bluetooth_device_map_[mac_address] =
std::move(bluetooth_device);
return mac_address_to_bluetooth_device_map_[mac_address].get();
}
LOG(INFO) << __func__ << ": Bluetooth device " << mac_address
<< " is in cache";
return it->second.get();
}
bool BluetoothClassicMedium::StartScanning() {
if (!IsWatcherStarted()) {
if (device_watcher_ == nullptr) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to start scanning due to no available watcher.";
LOG(ERROR) << __func__
<< ": Failed to start scanning due to no available watcher.";
return false;
}
discovered_devices_by_id_.clear();
mac_address_to_bluetooth_device_map_.clear();
removed_bluetooth_devices_map_.clear();
// The Start method can only be called when the DeviceWatcher is in the
// Created, Stopped or Aborted state.
@@ -530,9 +524,8 @@ bool BluetoothClassicMedium::StartScanning() {
}
}
NEARBY_LOGS(ERROR)
<< __func__
<< ": Attempted to start scanning when watcher already started.";
LOG(ERROR) << __func__
<< ": Attempted to start scanning when watcher already started.";
return false;
}
@@ -541,16 +534,15 @@ bool BluetoothClassicMedium::StopScanning() {
device_watcher_.Stop();
return true;
}
NEARBY_LOGS(ERROR)
<< __func__
<< ": Attempted to stop scanning when watcher already stopped.";
LOG(ERROR) << __func__
<< ": Attempted to stop scanning when watcher already stopped.";
return false;
}
winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Added(
DeviceWatcher sender, DeviceInformation deviceInfo) {
NEARBY_LOGS(INFO) << "Device added " << winrt::to_string(deviceInfo.Id());
IMapView<winrt::hstring, IInspectable> properties = deviceInfo.Properties();
DeviceWatcher sender, DeviceInformation device_info) {
LOG(INFO) << "Device added " << winrt::to_string(device_info.Id());
IMapView<winrt::hstring, IInspectable> properties = device_info.Properties();
DumpDeviceInformation(properties);
if (!IsWatcherStarted()) {
@@ -559,85 +551,93 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Added(
// If device no item name, ignore it.
if (!properties.HasKey(L"System.ItemNameDisplay")) {
NEARBY_LOGS(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(deviceInfo.Id())
<< " due to no name.";
LOG(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(device_info.Id()) << " due to no name.";
return winrt::fire_and_forget();
}
if (properties.Lookup(L"System.ItemNameDisplay") == nullptr) {
NEARBY_LOGS(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(deviceInfo.Id())
<< " due to empty name.";
LOG(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(device_info.Id()) << " due to empty name.";
return winrt::fire_and_forget();
}
// If device doesn't support pair, ignore it.
if (!properties.HasKey(L"System.Devices.Aep.CanPair")) {
NEARBY_LOGS(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(deviceInfo.Id())
<< " due to no pair property.";
LOG(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(device_info.Id())
<< " due to no pair property.";
return winrt::fire_and_forget();
}
if (!InspectableReader::ReadBoolean(
properties.Lookup(L"System.Devices.Aep.CanPair"))) {
NEARBY_LOGS(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(deviceInfo.Id())
<< " due to not support pair.";
return winrt::fire_and_forget();
}
// Create an iterator for the internal list
std::map<winrt::hstring, std::unique_ptr<BluetoothDevice>>::const_iterator
it = discovered_devices_by_id_.find(deviceInfo.Id());
// Add to our internal list if necessary
if (it != discovered_devices_by_id_.end()) {
// We're already tracking this one
NEARBY_LOGS(WARNING) << __func__ << ": Bluetooth device "
<< winrt::to_string(deviceInfo.Id())
<< " is alreay added.";
LOG(WARNING) << __func__ << ": Ignore the Bluetooth device "
<< winrt::to_string(device_info.Id())
<< " due to not support pair.";
return winrt::fire_and_forget();
}
// Create a bluetooth device out of this id
auto bluetoothDevice =
winrt::Windows::Devices::Bluetooth::BluetoothDevice::FromIdAsync(
deviceInfo.Id())
auto native_bluetooth_device =
::winrt::Windows::Devices::Bluetooth::BluetoothDevice::FromIdAsync(
device_info.Id())
.get();
auto bluetoothDeviceP = std::make_unique<BluetoothDevice>(bluetoothDevice);
discovered_devices_by_id_[deviceInfo.Id()] = std::move(bluetoothDeviceP);
std::string mac_address =
uint64_to_mac_address_string(native_bluetooth_device.BluetoothAddress());
NEARBY_LOGS(INFO) << __func__ << ": Notifying bluetooth device added";
// Create an iterator for the internal list
auto it = mac_address_to_bluetooth_device_map_.find(mac_address);
// Add to our internal list if necessary
if (it != mac_address_to_bluetooth_device_map_.end()) {
// We're already tracking this one
LOG(WARNING) << __func__ << ": Bluetooth device " << mac_address
<< " is alreay added.";
return winrt::fire_and_forget();
}
auto bluetooth_device =
std::make_unique<BluetoothDevice>(native_bluetooth_device);
mac_address_to_bluetooth_device_map_[mac_address] =
std::move(bluetooth_device);
LOG(INFO) << __func__ << ": Notifying bluetooth device " << mac_address
<< " added";
if (discovery_callback_.device_discovered_cb != nullptr) {
discovery_callback_.device_discovered_cb(
*discovered_devices_by_id_[deviceInfo.Id()]);
*mac_address_to_bluetooth_device_map_[mac_address]);
}
for (auto& observer : observers_.GetObservers()) {
observer->DeviceAdded(*discovered_devices_by_id_[deviceInfo.Id()]);
observer->DeviceAdded(*mac_address_to_bluetooth_device_map_[mac_address]);
}
return winrt::fire_and_forget();
}
winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
auto it = discovered_devices_by_id_.find(deviceInfoUpdate.Id());
DeviceWatcher sender, DeviceInformationUpdate device_update_info) {
auto native_bluetooth_device =
::winrt::Windows::Devices::Bluetooth::BluetoothDevice::FromIdAsync(
device_update_info.Id())
.get();
std::string mac_address =
uint64_to_mac_address_string(native_bluetooth_device.BluetoothAddress());
if (it == discovered_devices_by_id_.end()) {
NEARBY_LOGS(WARNING) << __func__ << ": Bluetooth device "
<< winrt::to_string(deviceInfoUpdate.Id())
<< " is not in list.";
auto it = mac_address_to_bluetooth_device_map_.find(mac_address);
if (it == mac_address_to_bluetooth_device_map_.end()) {
LOG(WARNING) << __func__ << ": Bluetooth device " << mac_address
<< " is not in list.";
return winrt::fire_and_forget();
}
NEARBY_LOGS(INFO)
<< "Device updated name: "
<< discovered_devices_by_id_[deviceInfoUpdate.Id()]->GetName() << " ("
<< winrt::to_string(deviceInfoUpdate.Id()) << ")";
LOG(INFO) << "Device updated name: "
<< mac_address_to_bluetooth_device_map_[mac_address]->GetName()
<< " (" << mac_address << ")";
IMapView<winrt::hstring, IInspectable> properties =
deviceInfoUpdate.Properties();
device_update_info.Properties();
DumpDeviceInformation(properties);
if (!IsWatcherStarted()) {
@@ -652,17 +652,15 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
properties.Lookup(L"System.ItemNameDisplay"));
if (it->second->GetName() == new_device_name) {
NEARBY_LOGS(INFO)
<< "Device name is same as old name, ignore the update.";
LOG(INFO) << "Device name is same as old name, ignore the update.";
} else {
it->second->SetName(new_device_name);
NEARBY_LOGS(INFO)
<< "Updated device name:"
<< discovered_devices_by_id_[deviceInfoUpdate.Id()]->GetName();
LOG(INFO) << "Updated device name:"
<< mac_address_to_bluetooth_device_map_[mac_address]->GetName();
discovery_callback_.device_name_changed_cb(
*discovered_devices_by_id_[deviceInfoUpdate.Id()]);
*mac_address_to_bluetooth_device_map_[mac_address]);
}
}
@@ -670,12 +668,13 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
if (properties.HasKey(L"System.Devices.Aep.IsPaired")) {
bool new_paired_status = InspectableReader::ReadBoolean(
properties.Lookup(L"System.Devices.Aep.IsPaired"));
NEARBY_LOGS(INFO) << __func__
<< ": Notifying device paired changed: " << std::boolalpha
<< new_paired_status;
LOG(INFO) << __func__
<< ": Notifying device paired changed: " << std::boolalpha
<< new_paired_status;
for (auto& observer : observers_.GetObservers()) {
observer->DevicePairedChanged(
*discovered_devices_by_id_[deviceInfoUpdate.Id()], new_paired_status);
*mac_address_to_bluetooth_device_map_[mac_address],
new_paired_status);
}
}
@@ -683,35 +682,47 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
}
winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Removed(
DeviceWatcher sender, DeviceInformationUpdate deviceInfo) {
auto it = discovered_devices_by_id_.find(deviceInfo.Id());
DeviceWatcher sender, DeviceInformationUpdate device_update_info) {
auto native_bluetooth_device =
::winrt::Windows::Devices::Bluetooth::BluetoothDevice::FromIdAsync(
device_update_info.Id())
.get();
if (it == discovered_devices_by_id_.end()) {
NEARBY_LOGS(WARNING) << __func__ << ": Bluetooth device "
<< winrt::to_string(deviceInfo.Id())
<< " is not in list.";
if (native_bluetooth_device == nullptr) {
LOG(WARNING) << __func__ << ": cannot get native bluetooth device.";
return winrt::fire_and_forget();
}
NEARBY_LOGS(INFO) << "Device removed "
<< discovered_devices_by_id_[deviceInfo.Id()]->GetName()
<< " (" << winrt::to_string(deviceInfo.Id()) << ")";
std::string mac_address =
uint64_to_mac_address_string(native_bluetooth_device.BluetoothAddress());
auto it = mac_address_to_bluetooth_device_map_.find(mac_address);
if (it == mac_address_to_bluetooth_device_map_.end()) {
LOG(WARNING) << __func__ << ": Bluetooth device " << mac_address
<< " is not in list.";
return winrt::fire_and_forget();
}
LOG(INFO) << "Device removed "
<< mac_address_to_bluetooth_device_map_[mac_address]->GetName()
<< " (" << mac_address << ")";
if (!IsWatcherStarted()) {
return winrt::fire_and_forget();
}
NEARBY_LOGS(INFO) << __func__ << ": Notifying bluetooth device removed";
LOG(INFO) << __func__ << ": Notifying bluetooth device removed";
if (discovery_callback_.device_lost_cb != nullptr) {
discovery_callback_.device_lost_cb(
*discovered_devices_by_id_[deviceInfo.Id()]);
*mac_address_to_bluetooth_device_map_[mac_address]);
}
for (auto& observer : observers_.GetObservers()) {
observer->DeviceRemoved(*discovered_devices_by_id_[deviceInfo.Id()]);
observer->DeviceRemoved(*mac_address_to_bluetooth_device_map_[mac_address]);
}
discovered_devices_by_id_.erase(deviceInfo.Id());
auto node = mac_address_to_bluetooth_device_map_.extract(mac_address);
removed_bluetooth_devices_map_[mac_address] = std::move(node.mapped());
return winrt::fire_and_forget();
}
@@ -738,23 +749,23 @@ bool BluetoothClassicMedium::IsWatcherRunning() {
}
bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
NEARBY_LOGS(INFO) << __func__
<< ": StartAdvertising is called with radio_discoverable: "
<< radio_discoverable << ".";
LOG(INFO) << __func__
<< ": StartAdvertising is called with radio_discoverable: "
<< radio_discoverable << ".";
try {
if (rfcomm_provider_ != nullptr &&
is_radio_discoverable_ == radio_discoverable) {
NEARBY_LOGS(WARNING) << __func__
<< ": Ignore StartAdvertising due to no change to "
"current advertising.";
LOG(WARNING) << __func__
<< ": Ignore StartAdvertising due to no change to "
"current advertising.";
return true;
}
if (rfcomm_provider_ != nullptr && !StopAdvertising()) {
NEARBY_LOGS(WARNING) << __func__
<< ": Failed to StartAdvertising due to cannot stop "
"running advertising.";
LOG(WARNING) << __func__
<< ": Failed to StartAdvertising due to cannot stop "
"running advertising.";
return false;
}
@@ -769,9 +780,8 @@ bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
raw_server_socket_ = server_socket_.get();
if (!server_socket_->listen()) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to StartAdvertising due to cannot start socket.";
LOG(ERROR) << __func__
<< ": Failed to StartAdvertising due to cannot start socket.";
server_socket_->Close();
server_socket_ = nullptr;
rfcomm_provider_ = nullptr;
@@ -788,13 +798,13 @@ bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
radio_discoverable);
is_radio_discoverable_ = radio_discoverable;
NEARBY_LOGS(INFO) << ": StartListening completed successfully.";
LOG(INFO) << ": StartListening completed successfully.";
return true;
} catch (std::exception exception) {
// We will log and eat the exception since the caller
// expects nullptr if it fails
NEARBY_LOGS(ERROR) << __func__ << ": Exception setting up for listen: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Exception setting up for listen: " << exception.what();
if (server_socket_ != nullptr) {
server_socket_->Close();
@@ -807,9 +817,8 @@ bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
return false;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": Exception setting up for listen: " << ex.code()
<< ": " << winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": Exception setting up for listen: " << ex.code()
<< ": " << winrt::to_string(ex.message());
if (server_socket_ != nullptr) {
server_socket_->Close();
server_socket_ = nullptr;
@@ -821,7 +830,7 @@ bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
if (server_socket_ != nullptr) {
server_socket_->Close();
server_socket_ = nullptr;
@@ -836,12 +845,12 @@ bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
}
bool BluetoothClassicMedium::StopAdvertising() {
NEARBY_LOGS(INFO) << __func__ << ": StopAdvertising is called";
LOG(INFO) << __func__ << ": StopAdvertising is called";
try {
if (rfcomm_provider_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Ignore StopAdvertising due to no advertising.";
LOG(ERROR) << __func__
<< ": Ignore StopAdvertising due to no advertising.";
return true;
}
@@ -850,19 +859,18 @@ bool BluetoothClassicMedium::StopAdvertising() {
raw_server_socket_ = nullptr;
server_socket_ = nullptr;
NEARBY_LOGS(INFO) << ": StopAdvertising completed successfully.";
LOG(INFO) << ": StopAdvertising completed successfully.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": StopAdvertising exception: " << exception.what();
LOG(ERROR) << __func__
<< ": StopAdvertising exception: " << exception.what();
return false;
} catch (const winrt::hresult_error& ex) {
NEARBY_LOGS(ERROR) << __func__
<< ": StopAdvertising exception: " << ex.code() << ": "
<< winrt::to_string(ex.message());
LOG(ERROR) << __func__ << ": StopAdvertising exception: " << ex.code()
<< ": " << winrt::to_string(ex.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return false;
}
}
@@ -870,26 +878,25 @@ bool BluetoothClassicMedium::StopAdvertising() {
bool BluetoothClassicMedium::InitializeServiceSdpAttributes(
RfcommServiceProvider rfcomm_provider, std::string service_name) {
try {
auto sdpWriter = DataWriter();
auto sdp_writer = DataWriter();
// Write the Service Name Attribute.
sdpWriter.WriteByte(Constants::SdpServiceNameAttributeType);
sdp_writer.WriteByte(Constants::SdpServiceNameAttributeType);
// The length of the UTF-8 encoded Service Name SDP Attribute.
sdpWriter.WriteByte(service_name.size());
sdp_writer.WriteByte(service_name.size());
// The UTF-8 encoded Service Name value.
sdpWriter.UnicodeEncoding(UnicodeEncoding::Utf8);
sdpWriter.WriteString(winrt::to_hstring(service_name));
sdp_writer.UnicodeEncoding(UnicodeEncoding::Utf8);
sdp_writer.WriteString(winrt::to_hstring(service_name));
// Set the SDP Attribute on the RFCOMM Service Provider.
rfcomm_provider.SdpRawAttributes().Insert(
Constants::SdpServiceNameAttributeId, sdpWriter.DetachBuffer());
Constants::SdpServiceNameAttributeId, sdp_writer.DetachBuffer());
return true;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to InitializeServiceSdpAttributes.";
LOG(ERROR) << __func__ << ": Failed to InitializeServiceSdpAttributes.";
return false;
}
}
@@ -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,11 +15,15 @@
#ifndef PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
#define PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
#include <list>
#include <map>
#include <memory>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "internal/base/observer_list.h"
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
@@ -32,76 +36,11 @@
namespace nearby {
namespace windows {
// Represents a device. This class allows access to well-known device properties
// as well as additional properties specified during device enumeration.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceinformation?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceInformation;
// Represents the kind of DeviceInformation object.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceinformationkind?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceInformationKind;
// Contains updated properties for a DeviceInformation object.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceinformationupdate?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceInformationUpdate;
// Enumerates devices dynamically, so that the app receives notifications if
// devices are added, removed, or changed after the initial enumeration is
// complete.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceWatcher;
// Writes data to an output stream.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.datawriter?view=winrt-20348
using winrt::Windows::Storage::Streams::DataWriter;
// Specifies the type of character encoding for a stream.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.unicodeencoding?view=winrt-20348
using winrt::Windows::Storage::Streams::UnicodeEncoding;
// Describes the state of a DeviceWatcher object.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcherstatus?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceWatcherStatus;
// Represents an instance of a service on a Bluetooth basic rate device.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommdeviceservice?view=winrt-20348
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService;
// Indicates the status of the access to a device.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceaccessstatus?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceAccessStatus;
// Contains the information about access to a device.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceaccessinformation?view=winrt-20348
using winrt::Windows::Devices::Enumeration::DeviceAccessInformation;
// Represents an RFCOMM service ID.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommserviceid?view=winrt-20348
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId;
// Represents an instance of a local RFCOMM service.
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommserviceprovider?view=winrt-20348
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceProvider;
// 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;
// Writes data to an output stream.
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.datawriter?view=winrt-20348
using winrt::Windows::Storage::Streams::DataWriter;
// Bluetooth protocol ID = \"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\"
// https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/aep-service-class-ids
#define BLUETOOTH_SELECTOR \
L"System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\""
// Container of operations that can be performed over the Bluetooth Classic
// medium.
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
public:
explicit BluetoothClassicMedium(api::BluetoothAdapter& bluetoothAdapter);
explicit BluetoothClassicMedium(api::BluetoothAdapter& bluetooth_adapter);
~BluetoothClassicMedium() override;
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery()
@@ -166,56 +105,67 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
bool StopScanning();
bool StartAdvertising(bool radio_discoverable);
bool StopAdvertising();
bool InitializeServiceSdpAttributes(RfcommServiceProvider rfcomm_provider,
std::string service_name);
bool InitializeServiceSdpAttributes(
::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceProvider
rfcomm_provider,
std::string service_name);
bool IsWatcherStarted();
bool IsWatcherRunning();
void InitializeDeviceWatcher();
void OnScanModeChanged(BluetoothAdapter::ScanMode scanMode);
void OnScanModeChanged(BluetoothAdapter::ScanMode scan_mode);
// This is for a coroutine whose return type is winrt::fire_and_forget, which
// handles async operations which don't have any dependencies.
// https://docs.microsoft.com/en-us/uwp/cpp-ref-for-winrt/fire-and-forget
winrt::fire_and_forget DeviceWatcher_Added(DeviceWatcher sender,
DeviceInformation deviceInfo);
winrt::fire_and_forget DeviceWatcher_Added(
::winrt::Windows::Devices::Enumeration::DeviceWatcher sender,
::winrt::Windows::Devices::Enumeration::DeviceInformation device_info);
winrt::fire_and_forget DeviceWatcher_Updated(
DeviceWatcher sender, DeviceInformationUpdate deviceInfo);
::winrt::Windows::Devices::Enumeration::DeviceWatcher sender,
::winrt::Windows::Devices::Enumeration::DeviceInformationUpdate
device_update_info);
winrt::fire_and_forget DeviceWatcher_Removed(
DeviceWatcher sender, DeviceInformationUpdate deviceInfo);
::winrt::Windows::Devices::Enumeration::DeviceWatcher sender,
::winrt::Windows::Devices::Enumeration::DeviceInformationUpdate
device_update_info);
// Check to make sure we can connect if we try
bool HaveAccess(winrt::hstring deviceId);
bool HaveAccess(::winrt::hstring device_id);
// Get the service requested
RfcommDeviceService GetRequestedService(BluetoothDevice* device,
winrt::guid service);
::winrt::guid service);
// Check to see that the device actually handles the requested service
bool CheckSdp(RfcommDeviceService requestedService);
bool CheckSdp(RfcommDeviceService requested_service);
BluetoothClassicMedium::DiscoveryCallback discovery_callback_;
DeviceWatcher device_watcher_ = nullptr;
::winrt::Windows::Devices::Enumeration::DeviceWatcher device_watcher_ =
nullptr;
std::unique_ptr<BluetoothSocket> bluetooth_socket_;
std::string service_name_;
std::string service_uuid_;
// hstring is the only type of string winrt understands.
// https://docs.microsoft.com/en-us/uwp/cpp-ref-for-winrt/hstring
std::map<winrt::hstring, std::unique_ptr<BluetoothDevice>>
discovered_devices_by_id_;
// Map MAC address to bluetooth device.
absl::flat_hash_map<std::string, std::unique_ptr<BluetoothDevice>>
mac_address_to_bluetooth_device_map_;
// Track removed devices.
absl::flat_hash_map<std::string, std::unique_ptr<BluetoothDevice>>
removed_bluetooth_devices_map_;
BluetoothAdapter& bluetooth_adapter_;
BluetoothAdapter::ScanMode scan_mode_ = BluetoothAdapter::ScanMode::kUnknown;
std::unique_ptr<BluetoothDevice> remote_device_to_connect_;
// Used for advertising.
RfcommServiceProvider rfcomm_provider_ = nullptr;
::winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceProvider
rfcomm_provider_ = nullptr;
std::unique_ptr<BluetoothServerSocket> server_socket_ = nullptr;
BluetoothServerSocket* raw_server_socket_ = nullptr;
bool is_radio_discoverable_ = false;
@@ -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.
@@ -20,12 +20,24 @@
#include <memory>
#include <string>
#include "absl/functional/any_invocable.h"
#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/logging.h"
namespace nearby {
namespace windows {
namespace {
using ::winrt::Windows::Networking::Sockets::SocketProtectionLevel;
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
using ::winrt::Windows::Networking::Sockets::StreamSocket;
using ::winrt::Windows::Networking::Sockets::StreamSocketListener;
using ::winrt::Windows::Networking::Sockets::
StreamSocketListenerConnectionReceivedEventArgs;
} // namespace
BluetoothServerSocket::BluetoothServerSocket(absl::string_view service_name)
: service_name_(service_name) {}
@@ -40,7 +52,7 @@ BluetoothServerSocket::~BluetoothServerSocket() { Close(); }
// Once error is reported, it is permanent, and ServerSocket has to be closed.
std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << __func__ << ": Accept is called.";
LOG(INFO) << __func__ << ": Accept is called.";
while (!closed_ && pending_sockets_.empty()) {
cond_.Wait(&mutex_);
@@ -50,7 +62,7 @@ std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
StreamSocket bluetooth_socket = pending_sockets_.front();
pending_sockets_.pop_front();
NEARBY_LOGS(INFO) << __func__ << ": Accepted a remote connection.";
LOG(INFO) << __func__ << ": Accepted a remote connection.";
return std::make_unique<BluetoothSocket>(bluetooth_socket);
}
@@ -63,7 +75,7 @@ void BluetoothServerSocket::SetCloseNotifier(
Exception BluetoothServerSocket::Close() {
try {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << __func__ << ": Close is called.";
LOG(INFO) << __func__ << ": Close is called.";
if (closed_) {
return {Exception::kSuccess};
@@ -87,23 +99,23 @@ Exception BluetoothServerSocket::Close() {
close_notifier_();
}
NEARBY_LOGS(INFO) << __func__ << ": Close completed succesfully.";
LOG(INFO) << __func__ << ": Close completed succesfully.";
return {Exception::kSuccess};
} catch (std::exception exception) {
closed_ = true;
cond_.SignalAll();
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
closed_ = true;
cond_.SignalAll();
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
closed_ = true;
cond_.SignalAll();
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
@@ -129,12 +141,12 @@ bool BluetoothServerSocket::listen() {
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
}
return false;
@@ -144,7 +156,7 @@ bool BluetoothServerSocket::listen() {
StreamSocketListener listener,
StreamSocketListenerConnectionReceivedEventArgs const& args) {
absl::MutexLock lock(&mutex_);
NEARBY_LOGS(INFO) << __func__ << ": Received connection.";
LOG(INFO) << __func__ << ": Received connection.";
if (closed_) {
return ::winrt::fire_and_forget{};
@@ -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,6 +14,7 @@
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
#include <cstdint>
#include <cstring>
#include <exception>
#include <memory>
@@ -21,32 +22,46 @@
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/feature_flags.h"
#include "internal/platform/flags/nearby_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;
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;
constexpr int kMaxConnectRetryCount = 3;
constexpr absl::Duration kConnectInterval = absl::Seconds(3);
} // namespace
BluetoothSocket::BluetoothSocket(StreamSocket streamSocket)
: windows_socket_(streamSocket) {
NEARBY_LOGS(INFO) << __func__ << ": Initialize bluetooth socket.";
BluetoothSocket::BluetoothSocket(StreamSocket stream_socket)
: windows_socket_(stream_socket) {
LOG(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()
.GetFlags()
.enable_bluetooth_connection_status_track) {
NEARBY_LOGS(INFO)
<< "Flag enable_bluetooth_connection_status_track is enabled.";
LOG(INFO) << "Flag enable_bluetooth_connection_status_track is enabled.";
connection_status_changed_token_ =
native_bluetooth_device_.ConnectionStatusChanged(
{this, &BluetoothSocket::Listener_ConnectionStatusChanged});
@@ -78,7 +93,7 @@ OutputStream& BluetoothSocket::GetOutputStream() { return output_stream_; }
// After this call object should be treated as not connected.
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
Exception BluetoothSocket::Close() {
NEARBY_LOGS(INFO) << __func__ << ": Close bluetooth socket.";
LOG(INFO) << __func__ << ": Close bluetooth socket.";
// The Close method aborts any pending operations and releases all unmanaged
// resources associated with the StreamSocket object, including the Input and
@@ -103,14 +118,14 @@ Exception BluetoothSocket::Close() {
is_bluetooth_socket_closed_ = true;
return {Exception::kSuccess};
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
@@ -125,26 +140,37 @@ 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) {
NEARBY_LOGS(INFO) << __func__ << ": start to connect to bluetooth service:"
<< winrt::to_string(connectionServiceName);
bool BluetoothSocket::Connect(HostName connection_host_name,
::winrt::hstring connection_service_name) {
LOG(INFO) << __func__ << ": start to connect to bluetooth service:"
<< winrt::to_string(connection_service_name);
connect_called_count_ = 0;
while (connect_called_count_ < kMaxConnectRetryCount) {
connect_called_count_ += 1;
if (nearby::NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableNewBluetoothRefactor)) {
bool connect_result =
InternalConnect(connectionHostName, connectionServiceName);
InternalConnect(connection_host_name, connection_service_name);
if (connect_result) {
return connect_result;
}
} else {
int connect_called_count = 0;
while (connect_called_count < kMaxConnectRetryCount) {
connect_called_count += 1;
bool connect_result =
InternalConnect(connection_host_name, connection_service_name);
if (connect_result) {
return connect_result;
}
NEARBY_LOGS(WARNING) << __func__ << ": Failed to connect bluetooth at the "
<< connect_called_count_ << "th call.";
LOG(WARNING) << __func__ << ": Failed to connect bluetooth at the "
<< connect_called_count << "th call.";
absl::SleepFor(kConnectInterval);
absl::SleepFor(kConnectInterval);
}
}
LOG(WARNING) << __func__ << ": Failed to connect bluetooth";
return false;
}
@@ -157,14 +183,13 @@ ExceptionOr<ByteArray> BluetoothSocket::BluetoothInputStream::Read(
std::int64_t size) {
try {
if (size <= 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Invalid transmit packet size: " << size;
LOG(ERROR) << __func__ << ": Invalid transmit packet size: " << size;
return {Exception::kIo};
}
if (size > read_buffer_.Capacity()) {
NEARBY_LOGS(WARNING) << __func__
<< ": resize receive buffer to packet size: " << size;
LOG(WARNING) << __func__
<< ": resize receive buffer to packet size: " << size;
read_buffer_ = Buffer(size);
}
@@ -176,27 +201,27 @@ ExceptionOr<ByteArray> BluetoothSocket::BluetoothInputStream::Read(
.get();
if (ibuffer.Length() != size) {
NEARBY_LOGS(WARNING) << __func__ << ": Got " << ibuffer.Length()
<< " bytes of total " << size << " bytes.";
LOG(WARNING) << __func__ << ": Got " << ibuffer.Length()
<< " bytes of total " << size << " bytes.";
}
ByteArray data((char*)ibuffer.data(), ibuffer.Length());
return ExceptionOr(data);
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
Exception BluetoothSocket::BluetoothInputStream::Close() {
NEARBY_LOGS(INFO) << __func__ << ": Close bluetooth input stream.";
LOG(INFO) << __func__ << ": Close bluetooth input stream.";
try {
if (winrt_input_stream_ != nullptr) {
@@ -204,14 +229,14 @@ Exception BluetoothSocket::BluetoothInputStream::Close() {
}
return {Exception::kSuccess};
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
@@ -224,9 +249,8 @@ BluetoothSocket::BluetoothOutputStream::BluetoothOutputStream(
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();
LOG(WARNING) << __func__
<< ": resize write buffer to packet size: " << data.size();
write_buffer_ = Buffer(data.size());
}
@@ -237,14 +261,14 @@ Exception BluetoothSocket::BluetoothOutputStream::Write(const ByteArray& data) {
winrt_output_stream_.WriteAsync(write_buffer_).get();
return {Exception::kSuccess};
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
@@ -258,59 +282,56 @@ Exception BluetoothSocket::BluetoothOutputStream::Flush() {
winrt_output_stream_.FlushAsync().get();
return {Exception::kSuccess};
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
Exception BluetoothSocket::BluetoothOutputStream::Close() {
NEARBY_LOGS(INFO) << __func__ << ": Close bluetooth output stream.";
LOG(INFO) << __func__ << ": Close bluetooth output stream.";
try {
if (winrt_output_stream_ != nullptr) {
winrt_output_stream_.Close();
}
return {Exception::kSuccess};
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return {Exception::kIo};
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return {Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return {Exception::kIo};
}
}
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()) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Bluetooth socket connection failed. Attempting to "
"connect to empty HostName/MAC address or ServiceName.";
if (connection_host_name == nullptr || connection_service_name.empty()) {
LOG(ERROR) << __func__
<< ": Bluetooth socket connection failed. Attempting to "
"connect to empty HostName/MAC address or ServiceName.";
return false;
}
NEARBY_LOGS(INFO) << __func__
<< ": Bluetooth socket connection to host name:"
<< winrt::to_string(connectionHostName.DisplayName())
<< ", service name:"
<< winrt::to_string(connectionServiceName);
LOG(INFO) << __func__ << ": Bluetooth socket connection to host name:"
<< winrt::to_string(connection_host_name.DisplayName())
<< ", service name:" << 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();
@@ -324,8 +345,7 @@ bool BluetoothSocket::InternalConnect(HostName connectionHostName,
if (FeatureFlags::GetInstance()
.GetFlags()
.enable_bluetooth_connection_status_track) {
NEARBY_LOGS(INFO)
<< "Flag enable_bluetooth_connection_status_track is enabled.";
LOG(INFO) << "Flag enable_bluetooth_connection_status_track is enabled.";
connection_status_changed_token_ =
native_bluetooth_device_.ConnectionStatusChanged(
{this, &BluetoothSocket::Listener_ConnectionStatusChanged});
@@ -337,19 +357,18 @@ bool BluetoothSocket::InternalConnect(HostName connectionHostName,
input_stream_ = BluetoothInputStream(windows_socket_.InputStream());
output_stream_ = BluetoothOutputStream(windows_socket_.OutputStream());
NEARBY_LOGS(INFO) << __func__
<< ": Bluetooth socket successfully connected to "
<< bluetooth_device_->GetName();
LOG(INFO) << __func__ << ": Bluetooth socket successfully connected to "
<< bluetooth_device_->GetName();
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Exception: " << exception.what();
LOG(ERROR) << __func__ << ": Exception: " << exception.what();
return false;
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exeption.";
LOG(ERROR) << __func__ << ": Unknown exeption.";
return false;
}
}
@@ -362,12 +381,10 @@ winrt::fire_and_forget BluetoothSocket::Listener_ConnectionStatusChanged(
// Based on the test, the args are empty, so cannot provide more information
// on the status change.
BluetoothConnectionStatus connection_status = device.ConnectionStatus();
NEARBY_LOGS(WARNING) << __func__
<< ": Bluetooth connection status changed to:"
<< ((connection_status ==
BluetoothConnectionStatus::Connected)
? "Connected"
: "Disconnected");
LOG(WARNING) << __func__ << ": Bluetooth connection status changed to:"
<< ((connection_status == BluetoothConnectionStatus::Connected)
? "Connected"
: "Disconnected");
return {};
}
@@ -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
@@ -21,7 +21,6 @@
#include <string>
#include <utility>
#include "absl/log/check.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "internal/platform/implementation/bluetooth_classic.h"
@@ -54,8 +53,7 @@ BluetoothPairing::BluetoothPairing(
BluetoothDevice bluetooth_device,
DeviceInformationCustomPairing custom_pairing)
: bluetooth_device_(bluetooth_device), custom_pairing_(custom_pairing) {
NEARBY_LOGS(VERBOSE) << __func__
<< ": BluetoothPairing is created for device.";
VLOG(1) << __func__ << ": BluetoothPairing is created for device.";
}
BluetoothPairing::~BluetoothPairing() {
@@ -64,19 +62,17 @@ BluetoothPairing::~BluetoothPairing() {
std::exchange(pairing_requested_token_, {}));
}
CancelPairing();
NEARBY_LOGS(VERBOSE) << __func__
<< ": BluetoothPairing is destroyed for device.";
VLOG(1) << __func__ << ": BluetoothPairing is destroyed for device.";
}
bool BluetoothPairing::InitiatePairing(
api::BluetoothPairingCallback pairing_cb) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to initiate pairing process.";
VLOG(1) << __func__ << ": Start to initiate pairing process.";
try {
pairing_requested_token_ = custom_pairing_.PairingRequested(
{this, &BluetoothPairing::OnPairingRequested});
if (!pairing_requested_token_) {
NEARBY_LOGS(VERBOSE) << __func__
<< " Failed to registered pairing callback.";
VLOG(1) << __func__ << " Failed to registered pairing callback.";
return false;
}
pairing_callback_ = std::move(pairing_cb);
@@ -91,35 +87,32 @@ bool BluetoothPairing::InitiatePairing(
OnPair(pairing_result);
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to initiate pairing. exception: "
<< exception.what();
LOG(ERROR) << __func__ << ": Failed to initiate pairing. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to initiate pairing. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": Failed to initiate pairing. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return false;
}
bool BluetoothPairing::FinishPairing(
std::optional<absl::string_view> pin_code) {
NEARBY_LOGS(VERBOSE) << __func__ << "Start to finish pairing.";
VLOG(1) << __func__ << "Start to finish pairing.";
try {
if (!pairing_requested_) {
NEARBY_LOGS(VERBOSE) << __func__ << "No pairing requested.";
VLOG(1) << __func__ << "No pairing requested.";
return false;
}
if (!pairing_deferral_) {
NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process.";
VLOG(1) << __func__ << "No ongoing pairing process.";
return false;
}
if (expecting_pin_code_) {
if (!pin_code.has_value()) {
NEARBY_LOGS(INFO) << __func__ << " Failed to get pin code";
LOG(INFO) << __func__ << " Failed to get pin code";
return false;
}
expecting_pin_code_ = false;
@@ -129,28 +122,25 @@ bool BluetoothPairing::FinishPairing(
pairing_requested_.Accept();
}
pairing_deferral_.Complete();
NEARBY_LOGS(VERBOSE) << "Successfully finished pairing.";
VLOG(1) << "Successfully finished pairing.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to finish pairing. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to finish pairing. exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to finish pairing. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": Failed to finish pairing. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return false;
}
bool BluetoothPairing::CancelPairing() {
NEARBY_LOGS(VERBOSE) << __func__
<< " Start to cancel ongoing pairing process.";
VLOG(1) << __func__ << " Start to cancel ongoing pairing process.";
try {
if (!pairing_deferral_) {
NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process.";
VLOG(1) << __func__ << "No ongoing pairing process.";
return true;
}
// There is no way to explicitly cancel an in-progress pairing on Windows as
@@ -161,48 +151,44 @@ bool BluetoothPairing::CancelPairing() {
// deferral is completed, will know that cancellation was the actual result.
was_cancelled_ = true;
pairing_deferral_.Close();
NEARBY_LOGS(VERBOSE) << __func__ << "Canceled ongoing pairing process.";
VLOG(1) << __func__ << "Canceled ongoing pairing process.";
return true;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to cancel ongoing pairing "
<< "process. exception: " << exception.what();
LOG(ERROR) << __func__ << ": Failed to cancel ongoing pairing "
<< "process. exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to cancel ongoing pairing process. "
<< "WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": Failed to cancel ongoing pairing process. "
<< "WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return false;
}
bool BluetoothPairing::Unpair() {
NEARBY_LOGS(VERBOSE) << __func__ << ": Start to unpair with remote device.";
VLOG(1) << __func__ << ": Start to unpair with remote device.";
try {
if (!IsPaired()) {
NEARBY_LOGS(VERBOSE) << __func__ << " : Remote device Was not paired.";
VLOG(1) << __func__ << " : Remote device Was not paired.";
return true;
}
DeviceUnpairingResult unpairing_result =
bluetooth_device_.DeviceInformation().Pairing().UnpairAsync().get();
if (unpairing_result.Status() == DeviceUnpairingResultStatus::Unpaired) {
NEARBY_LOGS(VERBOSE) << __func__ << ": Unpaired with remote device.";
VLOG(1) << __func__ << ": Unpaired with remote device.";
return true;
}
NEARBY_LOGS(VERBOSE) << __func__
<< ": Failed to unpaired with remote device.";
VLOG(1) << __func__ << ": Failed to unpaired with remote device.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to unpaired with device. exception: "
<< exception.what();
LOG(ERROR) << __func__ << ": Failed to unpaired with device. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to unpaired with device. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to unpaired with device. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return false;
}
@@ -210,18 +196,17 @@ bool BluetoothPairing::Unpair() {
bool BluetoothPairing::IsPaired() {
try {
bool is_paired = bluetooth_device_.DeviceInformation().Pairing().IsPaired();
NEARBY_LOGS(INFO) << __func__ << (is_paired ? " True" : " False");
LOG(INFO) << __func__ << (is_paired ? " True" : " False");
return is_paired;
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get IsPaired. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to get IsPaired. exception: " << exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get IsPaired. WinRT exception: "
<< error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to get IsPaired. WinRT exception: " << error.code()
<< ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
return false;
}
@@ -229,7 +214,7 @@ bool BluetoothPairing::IsPaired() {
void BluetoothPairing::OnPairingRequested(
DeviceInformationCustomPairing custom_pairing,
DevicePairingRequestedEventArgs pairing_requested) {
NEARBY_LOGS(VERBOSE) << __func__ << "Requested to pair.";
VLOG(1) << __func__ << "Requested to pair.";
try {
DevicePairingKinds pairing_kind = pairing_requested.PairingKind();
pairing_requested_ = pairing_requested;
@@ -237,40 +222,38 @@ void BluetoothPairing::OnPairingRequested(
api::PairingParams params;
switch (pairing_kind) {
case DevicePairingKinds::ProvidePin:
NEARBY_LOGS(INFO) << __func__ << "DevicePairingKind: RequestPinCode.";
LOG(INFO) << __func__ << "DevicePairingKind: RequestPinCode.";
expecting_pin_code_ = true;
params.pairing_type = PairingType::kRequestPin;
pairing_callback_.on_pairing_initiated_cb(params);
return;
case DevicePairingKinds::ConfirmOnly:
NEARBY_LOGS(INFO) << __func__ << "DevicePairingKind: ConfirmOnly.";
LOG(INFO) << __func__ << "DevicePairingKind: ConfirmOnly.";
params.pairing_type = PairingType::kConsent;
pairing_callback_.on_pairing_initiated_cb(params);
return;
case DevicePairingKinds::ConfirmPinMatch:
NEARBY_LOGS(INFO) << __func__
<< "DevicePairingKind: Confirm Pin Match.";
LOG(INFO) << __func__ << "DevicePairingKind: Confirm Pin Match.";
params.pairing_type = PairingType::kConfirmPasskey;
params.passkey = winrt::to_string(pairing_requested.Pin());
pairing_callback_.on_pairing_initiated_cb(params);
return;
default:
params.pairing_type = PairingType::kUnknown;
NEARBY_LOGS(INFO) << __func__ << "Unsupported DevicePairingKind:"
<< static_cast<int>(pairing_kind);
LOG(INFO) << __func__ << "Unsupported DevicePairingKind:"
<< static_cast<int>(pairing_kind);
break;
}
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to request to pair with device. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to request to pair with device. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Failed to request to pair with device. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
LOG(ERROR) << __func__
<< ": Failed to request to pair with device. WinRT exception: "
<< error.code() << ": " << winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
pairing_callback_.on_pairing_error_cb(PairingError::kFailed);
}
@@ -278,8 +261,8 @@ void BluetoothPairing::OnPairingRequested(
void BluetoothPairing::OnPair(DevicePairingResult& pairing_result) {
try {
DevicePairingResultStatus status = pairing_result.Status();
NEARBY_LOGS(INFO) << __func__
<< "Pairing Result Status: " << static_cast<int>(status);
LOG(INFO) << __func__
<< "Pairing Result Status: " << static_cast<int>(status);
if (was_cancelled_ &&
status == DevicePairingResultStatus::RejectedByHandler) {
// See comment in CancelPairing() for explanation of why was_cancelled_
@@ -289,53 +272,52 @@ void BluetoothPairing::OnPair(DevicePairingResult& pairing_result) {
switch (status) {
case DevicePairingResultStatus::AlreadyPaired:
case DevicePairingResultStatus::Paired:
NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Paired.";
LOG(ERROR) << __func__ << "Pairing Result Status: Paired.";
pairing_callback_.on_paired_cb();
return;
case DevicePairingResultStatus::PairingCanceled:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Pairing Canceled.";
LOG(ERROR) << __func__ << "Pairing Result Status: Pairing Canceled.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthCanceled);
return;
case DevicePairingResultStatus::AuthenticationFailure:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Authentication Failure.";
LOG(ERROR) << __func__
<< "Pairing Result Status: Authentication Failure.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthFailed);
return;
case DevicePairingResultStatus::ConnectionRejected:
case DevicePairingResultStatus::RejectedByHandler:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Authentication Rejected.";
LOG(ERROR) << __func__
<< "Pairing Result Status: Authentication Rejected.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthRejected);
return;
case DevicePairingResultStatus::AuthenticationTimeout:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Authentication Timeout.";
LOG(ERROR) << __func__
<< "Pairing Result Status: Authentication Timeout.";
pairing_callback_.on_pairing_error_cb(PairingError::kAuthTimeout);
return;
case DevicePairingResultStatus::Failed:
NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Failed.";
LOG(ERROR) << __func__ << "Pairing Result Status: Failed.";
pairing_callback_.on_pairing_error_cb(PairingError::kFailed);
return;
case DevicePairingResultStatus::OperationAlreadyInProgress:
NEARBY_LOGS(ERROR) << __func__
<< "Pairing Result Status: Operation In Progress.";
LOG(ERROR) << __func__
<< "Pairing Result Status: Operation In Progress.";
pairing_callback_.on_pairing_error_cb(PairingError::kRepeatedAttempts);
return;
default:
break;
}
NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Failed.";
LOG(ERROR) << __func__ << "Pairing Result Status: Failed.";
} catch (std::exception exception) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to get Pairing Result Status. exception: "
<< exception.what();
LOG(ERROR) << __func__
<< ": Failed to get Pairing Result Status. exception: "
<< exception.what();
} catch (const winrt::hresult_error& error) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to get Pairing Result Status."
<< " WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
LOG(ERROR) << __func__ << ": Failed to get Pairing Result Status."
<< " WinRT exception: " << error.code() << ": "
<< winrt::to_string(error.message());
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
}
pairing_callback_.on_pairing_error_cb(PairingError::kFailed);
}
@@ -18,19 +18,16 @@
#include <windows.h>
#include <wtsapi32.h>
#include <array>
#include <filesystem>
#include <filesystem> // NOLINT
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "internal/base/bluetooth_address.h"
#include "internal/base/files.h"
#include "internal/platform/implementation/device_info.h"
#include "internal/platform/implementation/windows/session_manager.h"
#include "internal/platform/implementation/windows/generated/winrt/base.h"
#include "internal/platform/logging.h"
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Windows.Foundation.h"
@@ -56,25 +53,25 @@ constexpr char logs_relative_path[] = "Google\\Nearby\\Sharing\\Logs";
constexpr char crash_dumps_relative_path[] =
"Google\\Nearby\\Sharing\\CrashDumps";
std::optional<std::u16string> DeviceInfo::GetOsDeviceName() const {
std::optional<std::string> DeviceInfo::GetOsDeviceName() const {
DWORD size = 0;
// Get length of the computer name.
if (!GetComputerNameExW(ComputerNameDnsHostname, nullptr, &size)) {
if (GetLastError() != ERROR_MORE_DATA) {
NEARBY_LOGS(ERROR) << ": Failed to get device name size, error:"
<< GetLastError();
LOG(ERROR) << ": Failed to get device name size, error:"
<< GetLastError();
return std::nullopt;
}
}
WCHAR device_name[size];
if (GetComputerNameExW(ComputerNameDnsHostname, device_name, &size)) {
std::wstring wide_name(device_name);
return std::u16string(wide_name.begin(), wide_name.end());
std::wstring device_name(size, L' ');
if (GetComputerNameExW(ComputerNameDnsHostname, device_name.data(), &size)) {
winrt::hstring device_name_str(device_name);
return winrt::to_string(device_name_str);
}
NEARBY_LOGS(ERROR) << ": Failed to get device name, error:" << GetLastError();
LOG(ERROR) << ": Failed to get device name, error:" << GetLastError();
return std::nullopt;
}
@@ -87,7 +84,7 @@ api::DeviceInfo::OsType DeviceInfo::GetOsType() const {
return api::DeviceInfo::OsType::kWindows;
}
std::optional<std::u16string> DeviceInfo::GetFullName() const {
std::optional<std::string> DeviceInfo::GetGivenName() const {
// FindAllAsync finds all users that are using this app. When we "Switch User"
// on Desktop,FindAllAsync() will still return the current user instead of all
// of them because the users who are switched out are not using the apps of
@@ -100,52 +97,7 @@ std::optional<std::u16string> DeviceInfo::GetFullName() const {
UserAuthenticationStatus::LocallyAuthenticated)
.get();
if (users == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error retrieving locally authenticated user.";
return std::nullopt;
}
// On Windows Desktop apps, the first Windows.System.User instance
// returned in the IVectorView is always the current user.
// https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md
User current_user = users.GetAt(0);
// Retrieve the human-readable properties for the current user
IAsyncOperation<IInspectable> full_name_obj_async =
current_user.GetPropertyAsync(KnownUserProperties::DisplayName());
IInspectable full_name_obj = full_name_obj_async.get();
if (full_name_obj == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving full name of user.";
return std::nullopt;
}
winrt::hstring full_name = full_name_obj.as<winrt::hstring>();
std::wstring wstr(full_name);
std::u16string u16str(wstr.begin(), wstr.end());
if (u16str.empty()) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Error unboxing string value for full name of user.";
return std::nullopt;
}
return u16str;
}
std::optional<std::u16string> DeviceInfo::GetGivenName() const {
// FindAllAsync finds all users that are using this app. When we "Switch User"
// on Desktop,FindAllAsync() will still return the current user instead of all
// of them because the users who are switched out are not using the apps of
// the user who is switched in, so FindAllAsync() will not find them. (Under
// the UWP application model, each process runs under its own user account.
// That user account is different from the user account of the logged-in user.
// Processes aren't owned by the logged-in user for purposes of isolation.)
IVectorView<User> users =
User::FindAllAsync(UserType::LocalUser,
UserAuthenticationStatus::LocallyAuthenticated)
.get();
if (users == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error retrieving locally authenticated user.";
LOG(ERROR) << __func__ << ": Error retrieving locally authenticated user.";
return std::nullopt;
}
@@ -159,109 +111,19 @@ std::optional<std::u16string> DeviceInfo::GetGivenName() const {
current_user.GetPropertyAsync(KnownUserProperties::FirstName());
IInspectable given_name_obj = given_name_obj_async.get();
if (given_name_obj == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving first name of user.";
LOG(ERROR) << __func__ << ": Error retrieving first name of user.";
return std::nullopt;
}
winrt::hstring given_name = given_name_obj.as<winrt::hstring>();
std::wstring wstr(given_name);
std::u16string u16str(wstr.begin(), wstr.end());
std::string given_name_str = winrt::to_string(given_name);
if (u16str.empty()) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Error unboxing string value for first name of user.";
if (given_name_str.empty()) {
LOG(ERROR) << __func__
<< ": Error unboxing string value for first name of user.";
return std::nullopt;
}
return u16str;
}
std::optional<std::u16string> DeviceInfo::GetLastName() const {
// FindAllAsync finds all users that are using this app. When we "Switch User"
// on Desktop,FindAllAsync() will still return the current user instead of all
// of them because the users who are switched out are not using the apps of
// the user who is switched in, so FindAllAsync() will not find them. (Under
// the UWP application model, each process runs under its own user account.
// That user account is different from the user account of the logged-in user.
// Processes aren't owned by the logged-in user for purposes of isolation.)
IVectorView<User> users =
User::FindAllAsync(UserType::LocalUser,
UserAuthenticationStatus::LocallyAuthenticated)
.get();
if (users == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error retrieving locally authenticated user.";
return std::nullopt;
}
// On Windows Desktop apps, the first Windows.System.User instance
// returned in the IVectorView is always the current user.
// https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md
User current_user = users.GetAt(0);
// Retrieve the human-readable properties for the current user
IAsyncOperation<IInspectable> last_name_obj_async =
current_user.GetPropertyAsync(KnownUserProperties::LastName());
IInspectable last_name_obj = last_name_obj_async.get();
if (last_name_obj == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving last name of user.";
return std::nullopt;
}
winrt::hstring last_name = last_name_obj.as<winrt::hstring>();
std::wstring wstr(last_name);
std::u16string u16str(wstr.begin(), wstr.end());
if (u16str.empty()) {
NEARBY_LOGS(ERROR)
<< __func__ << ": Error unboxing string value for last name of user.";
return std::nullopt;
}
return u16str;
}
std::optional<std::string> DeviceInfo::GetProfileUserName() const {
// FindAllAsync finds all users that are using this app. When we "Switch User"
// on Desktop,FindAllAsync() will still return the current user instead of all
// of them because the users who are switched out are not using the apps of
// the user who is switched in, so FindAllAsync() will not find them. (Under
// the UWP application model, each process runs under its own user account.
// That user account is different from the user account of the logged-in user.
// Processes aren't owned by the logged-in user for purposes of isolation.)
IVectorView<User> users =
User::FindAllAsync(UserType::LocalUser,
UserAuthenticationStatus::LocallyAuthenticated)
.get();
if (users == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error retrieving locally authenticated user.";
return std::nullopt;
}
// On Windows Desktop apps, the first Windows.System.User instance
// returned in the IVectorView is always the current user.
// https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md
User current_user = users.GetAt(0);
// Retrieve the human-readable properties for the current user
IAsyncOperation<IInspectable> account_name_obj_async =
current_user.GetPropertyAsync(KnownUserProperties::AccountName());
IInspectable account_name_obj = account_name_obj_async.get();
if (account_name_obj == nullptr) {
NEARBY_LOGS(ERROR) << __func__
<< ": Error retrieving account name of user.";
return std::nullopt;
}
winrt::hstring account_name = account_name_obj.as<winrt::hstring>();
std::string account_name_string = winrt::to_string(account_name);
if (account_name_string.empty()) {
NEARBY_LOGS(ERROR)
<< __func__
<< ": Error unboxing string value for profile username of user.";
return std::nullopt;
}
return account_name_string;
return given_name_str;
}
std::optional<std::filesystem::path> DeviceInfo::GetDownloadPath() const {
@@ -307,7 +169,7 @@ std::optional<std::filesystem::path> DeviceInfo::GetCommonAppDataPath() const {
}
std::optional<std::filesystem::path> DeviceInfo::GetTemporaryPath() const {
return std::filesystem::temp_directory_path();
return nearby::sharing::GetTemporaryDirectory();
}
std::optional<std::filesystem::path> DeviceInfo::GetLogPath() const {
@@ -31,13 +31,10 @@ class DeviceInfo : public api::DeviceInfo {
public:
~DeviceInfo() override = default;
std::optional<std::u16string> GetOsDeviceName() const override;
std::optional<std::string> GetOsDeviceName() const override;
api::DeviceInfo::DeviceType GetDeviceType() const override;
api::DeviceInfo::OsType GetOsType() const override;
std::optional<std::u16string> GetFullName() const override;
std::optional<std::u16string> GetGivenName() const override;
std::optional<std::u16string> GetLastName() const override;
std::optional<std::string> GetProfileUserName() const override;
std::optional<std::string> GetGivenName() const override;
std::optional<std::filesystem::path> GetDownloadPath() const override;
std::optional<std::filesystem::path> GetLocalAppDataPath() const override;
@@ -14,11 +14,8 @@
#include "internal/platform/implementation/windows/device_info.h"
#include <functional>
#include <string>
#include "gtest/gtest.h"
#include "absl/synchronization/notification.h"
#include "internal/platform/implementation/device_info.h"
namespace nearby {
@@ -37,21 +34,10 @@ TEST(DeviceInfo, GetOsType) {
EXPECT_EQ(DeviceInfo().GetOsType(), api::DeviceInfo::OsType::kWindows);
}
TEST(DeviceInfo, DISABLED_GetFullName) {
EXPECT_TRUE(DeviceInfo().GetFullName().has_value());
}
TEST(DeviceInfo, DISABLED_GetGivenName) {
EXPECT_TRUE(DeviceInfo().GetGivenName().has_value());
}
TEST(DeviceInfo, DISABLED_GetLastName) {
EXPECT_TRUE(DeviceInfo().GetLastName().has_value());
}
TEST(DeviceInfo, DISABLED_GetProfileUserName) {
EXPECT_TRUE(DeviceInfo().GetProfileUserName().has_value());
}
TEST(DeviceInfo, DISABLED_GetLocalAppDataPath) {
EXPECT_TRUE(DeviceInfo().GetLocalAppDataPath().has_value());
@@ -15,8 +15,10 @@
#include "internal/platform/implementation/windows/executor.h"
#include <cassert>
#include <cstdint>
#include "internal/platform/logging.h"
#include "internal/platform/runnable.h"
namespace nearby {
namespace windows {
@@ -32,13 +34,13 @@ Executor::Executor(int32_t max_concurrency)
void Executor::Execute(Runnable&& runnable) {
if (shut_down_) {
NEARBY_LOGS(VERBOSE) << "Warning: " << __func__
<< ": Attempt to execute on a shut down pool.";
VLOG(1) << "Warning: " << __func__
<< ": Attempt to execute on a shut down pool.";
return;
}
if (runnable == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Runnable was null.";
LOG(ERROR) << __func__ << ": Runnable was null.";
return;
}
@@ -14,45 +14,54 @@
#include "internal/platform/implementation/windows/file.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <ios>
#include <memory>
#include <string>
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/implementation/windows/string_utils.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace windows {
// InputFile
std::unique_ptr<IOFile> IOFile::CreateInputFile(
const absl::string_view file_path, size_t size) {
std::unique_ptr<IOFile> IOFile::CreateInputFile(absl::string_view file_path,
size_t size) {
return absl::WrapUnique(new IOFile(file_path, size));
}
IOFile::IOFile(const absl::string_view file_path, size_t size)
: path_(file_path) {
IOFile::IOFile(absl::string_view file_path, size_t size) : path_(file_path) {
// Always open input file path as wide string on Windows platform.
std::wstring wide_path = string_to_wstring(std::string(file_path));
std::wstring wide_path = string_utils::StringToWideString(
std::string(file_path));
file_.open(wide_path, std::ios::binary | std::ios::in | std::ios::ate);
total_size_ = file_.tellg();
if (total_size_ == -1) {
// Unsure why it consistently returns -1 when the file size exceeds 2GB. If
// obtaining the file size through tellg fails, use the size provided
// in the parameters.
total_size_ = size;
}
file_.seekg(0);
}
std::unique_ptr<IOFile> IOFile::CreateOutputFile(const absl::string_view path) {
std::unique_ptr<IOFile> IOFile::CreateOutputFile(absl::string_view path) {
return std::unique_ptr<IOFile>(new IOFile(path));
}
IOFile::IOFile(const absl::string_view file_path)
IOFile::IOFile(absl::string_view file_path)
: file_(), path_(file_path), total_size_(0) {
// Always open input file path as wide string on Windows platform.
std::wstring wide_path = string_to_wstring(path_);
std::wstring wide_path =
string_utils::StringToWideString(path_);
file_.open(wide_path, std::ios::binary | std::ios::out);
}
@@ -66,20 +75,22 @@ ExceptionOr<ByteArray> IOFile::Read(std::int64_t size) {
return ExceptionOr<ByteArray>{Exception::kIo};
}
if (file_.peek() == EOF) {
if (file_.eof()) {
return ExceptionOr<ByteArray>{ByteArray{}};
}
ByteArray bytes(size);
std::unique_ptr<char[]> read_bytes{new char[size]};
file_.read(read_bytes.get(), static_cast<ptrdiff_t>(size));
if (buffer_.size() < size) {
buffer_.resize(size);
}
file_.read(buffer_.data(), static_cast<ptrdiff_t>(size));
auto num_bytes_read = file_.gcount();
if (num_bytes_read == 0) {
return ExceptionOr<ByteArray>{Exception::kIo};
}
return ExceptionOr<ByteArray>(ByteArray(read_bytes.get(), num_bytes_read));
return ExceptionOr<ByteArray>(ByteArray(buffer_.data(), num_bytes_read));
} catch (...) {
NEARBY_LOGS(ERROR) << "Fail to read";
LOG(ERROR) << "Fail to read";
return ExceptionOr<ByteArray>{Exception::kIo};
}
}
@@ -105,7 +116,7 @@ Exception IOFile::Write(const ByteArray& data) {
file_.flush();
return {file_.good() ? Exception::kSuccess : Exception::kIo};
} catch (...) {
NEARBY_LOGS(ERROR) << "Fail to write";
LOG(ERROR) << "Fail to write";
return {Exception::kIo};
}
}
@@ -15,12 +15,14 @@
#ifndef PLATFORM_IMPL_WINDOWS_FILE_H_
#define PLATFORM_IMPL_WINDOWS_FILE_H_
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
#include "internal/platform/byte_array.h"
#include "internal/platform/exception.h"
#include "internal/platform/implementation/input_file.h"
#include "internal/platform/implementation/output_file.h"
@@ -30,10 +32,10 @@ namespace windows {
class IOFile final : public api::InputFile, public api::OutputFile {
public:
static std::unique_ptr<IOFile> CreateInputFile(
const absl::string_view file_path, size_t size);
static std::unique_ptr<IOFile> CreateInputFile(absl::string_view file_path,
size_t size);
static std::unique_ptr<IOFile> CreateOutputFile(const absl::string_view path);
static std::unique_ptr<IOFile> CreateOutputFile(absl::string_view path);
ExceptionOr<ByteArray> Read(std::int64_t size) override;
@@ -46,11 +48,12 @@ class IOFile final : public api::InputFile, public api::OutputFile {
Exception Flush() override;
private:
explicit IOFile(const absl::string_view file_path, size_t size);
explicit IOFile(const absl::string_view file_path);
explicit IOFile(absl::string_view file_path, size_t size);
explicit IOFile(absl::string_view file_path);
std::fstream file_;
std::string path_;
std::string buffer_;
std::int64_t total_size_;
};
@@ -1,4 +1,4 @@
// Copyright 2022 Google LLC
// Copyright 2022-2024 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,6 +14,7 @@
#include "internal/platform/implementation/windows/file_path.h"
// clang-format off
#include <windows.h>
#include <winver.h>
#include <PathCch.h>
@@ -22,28 +23,36 @@
#include <shlobj.h>
#include <shlwapi.h>
#include <strsafe.h>
#include <wchar.h>
// clang-format on
#include <algorithm>
#include <cctype>
#include <fstream>
#include <iterator>
#include <string>
#include <string_view>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/types/span.h"
#include "connections/implementation/flags/nearby_connections_feature_flags.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/implementation/windows/string_utils.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/logging.h"
namespace nearby {
namespace windows {
const wchar_t* kUpOneLevel = L"/..";
const wchar_t* kUpOneLevel = L"..";
constexpr wchar_t kDot = L'.';
constexpr wchar_t kPathDelimiter = L'/';
constexpr wchar_t kReplacementChar = L'_';
constexpr wchar_t kForwardSlash = L'/';
constexpr wchar_t kBackSlash = L'\\';
wchar_t const* kForbiddenPathNames[] = {
constexpr std::wstring_view kForbiddenPathNames[] = {
L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", L"COM3", L"COM4",
L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3",
L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9"};
@@ -51,12 +60,14 @@ wchar_t const* kForbiddenPathNames[] = {
std::wstring FilePath::GetCustomSavePath(std::wstring parent_folder,
std::wstring file_name) {
std::wstring path;
SanitizeFileName(file_name);
path += parent_folder + kPathDelimiter + file_name;
return CreateOutputFileWithRename(path);
}
std::wstring FilePath::GetDownloadPath(std::wstring parent_folder,
std::wstring file_name) {
SanitizeFileName(file_name);
return CreateOutputFileWithRename(
GetDownloadPathInternal(parent_folder, file_name));
}
@@ -167,8 +178,8 @@ std::wstring FilePath::CreateOutputFileWithRename(std::wstring path) {
}
if (count > 0) {
NEARBY_LOGS(INFO) << "Renamed " << wstring_to_string(path) << " to "
<< wstring_to_string(target);
LOG(INFO) << "Renamed " << string_utils::WideStringToString(path) << " to "
<< string_utils::WideStringToString(target);
}
// The above leaves the file open, so close it.
@@ -198,23 +209,30 @@ std::wstring FilePath::MutateForbiddenPathElements(std::wstring& str) {
if (lastToken.length() > 0) path_elements.push_back(lastToken);
std::wstring processed_path;
absl::Span<const std::wstring_view> forbidden(kForbiddenPathNames);
for (auto& path_element : path_elements) {
auto tmp_path_element = path_element;
if (tmp_path_element.size() == 1 && tmp_path_element[0] == kDot) {
// Change the dot path name to an underscore.
tmp_path_element[0] = kReplacementChar;
LOG(INFO) << "Renamed path element "
<< string_utils::WideStringToString(path_element) << " to "
<< string_utils::WideStringToString(tmp_path_element);
path_element[0] = kReplacementChar;
}
std::transform(tmp_path_element.begin(), tmp_path_element.end(),
tmp_path_element.begin(),
[](wchar_t c) { return std::toupper(c); });
std::vector<std::wstring> forbidden(std::begin(kForbiddenPathNames),
std::end(kForbiddenPathNames));
while (std::find(forbidden.begin(), forbidden.end(), tmp_path_element) !=
forbidden.end()) {
tmp_path_element.insert(tmp_path_element.begin(), kReplacementChar);
NEARBY_LOGS(INFO) << "Renamed path element "
<< wstring_to_string(path_element) << " to "
<< wstring_to_string(tmp_path_element);
LOG(INFO) << "Renamed path element "
<< string_utils::WideStringToString(path_element) << " to "
<< string_utils::WideStringToString(tmp_path_element);
path_element.insert(path_element.begin(), kReplacementChar);
}
@@ -227,16 +245,15 @@ std::wstring FilePath::MutateForbiddenPathElements(std::wstring& str) {
return processed_path;
}
void FilePath::SanitizePath(std::wstring& path) {
size_t pos = std::wstring::npos;
// Search for the substring in string in a loop until nothing is found
while ((pos = path.find(kUpOneLevel)) != std::string::npos) {
// If found then erase it from string
path.erase(pos, wcslen(kUpOneLevel));
void FilePath::SanitizeFileName(std::wstring& file_name) {
if (!file_name.empty() && file_name[file_name.size() - 1] == kDot) {
// Change the last dot to an underscore.
file_name[file_name.size() - 1] = kReplacementChar;
}
}
void FilePath::SanitizePath(std::wstring& path) {
path = MutateForbiddenPathElements(path);
ReplaceInvalidCharacters(path);
}
@@ -249,16 +266,22 @@ void FilePath::ReplaceInvalidCharacters(std::wstring& path) {
for (; it != path.end(); it++) {
// If 0 < character < 32, it's illegal, replace it
if (*it > 0 && *it < 32) {
NEARBY_LOGS(INFO) << "In path " << wstring_to_string(path)
<< " replaced \'" << std::string(1, *it) << "\' with \'"
<< std::string(1, kReplacementChar);
LOG(INFO) << "In path " << string_utils::WideStringToString(path)
<< " replaced \'" << std::string(1, *it) << "\' with \'"
<< std::string(1, kReplacementChar);
*it = kReplacementChar;
}
if (*it == 0) { // character is null
LOG(INFO) << "In path " << string_utils::WideStringToString(path)
<< " replaced \'NULL\' with \'"
<< std::string(1, kReplacementChar) << "\'";
*it = kReplacementChar;
}
for (auto illegal_character : kIllegalFileCharacters) {
if (*it == illegal_character) {
NEARBY_LOGS(INFO) << "In path " << wstring_to_string(path)
<< " replaced \'" << std::string(1, *it)
<< "\' with \'" << std::string(1, kReplacementChar);
LOG(INFO) << "In path " << string_utils::WideStringToString(path)
<< " replaced \'" << std::string(1, *it) << "\' with \'"
<< std::string(1, kReplacementChar);
*it = kReplacementChar;
}
}
@@ -41,6 +41,7 @@ class FilePath {
static std::wstring MutateForbiddenPathElements(std::wstring& str);
static std::wstring GetDownloadPathInternal(std::wstring parent_folder,
std::wstring file_name);
static void SanitizeFileName(std::wstring& file_name);
};
} // namespace windows
@@ -22,7 +22,6 @@
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include "gtest/gtest.h"
@@ -39,6 +38,7 @@ const wchar_t* kFileName(L"increment_file_test.txt");
const wchar_t* kFirstIterationFileName(L"/increment_file_test (1).txt");
const wchar_t* kSecondIterationFileName(L"/increment_file_test (2).txt");
const wchar_t* kThirdIterationFileName(L"/increment_file_test (3).txt");
const wchar_t* kFileNameWithNullReplaced(L"/increment_file_test.txt_.txt");
const wchar_t* kNoDotsFileName(L"incrementfiletesttxt");
const wchar_t* kOneIterationNoDotsFileName(L"/incrementfiletesttxt (1)");
const wchar_t* kMultipleDotsFileName(L"increment.file.test.txt");
@@ -52,6 +52,8 @@ const wchar_t* kLongEscapeMixedSlash(L"../test\\..\\../test");
const wchar_t* kLongEscapeEndingEscape(L"../test/../../test/..");
const wchar_t* kLongEscapeEndingEscapeWithSlash(
L"../test/../../test/../../../");
const wchar_t* kFileNameWithThreeDots(L"...");
const wchar_t* kFileNameWithFrontTwoDots(L"..file.name.txt");
} // namespace
// Can't run on google 3, I presume the SHGetKnownFolderPath
@@ -124,71 +126,6 @@ FolderArgumentsShouldReturnBaseDownloadPath) {
EXPECT_EQ(actual, default_download_path_);
} // NOLINT false lint error here
TEST_F(FilePathTests, GetDownloadPathWithAttemptToEscape\
UsersDownloadFolderShouldReturnDownloadPathNotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kImmediateEscape);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithBackslashShouldReturnDownloadPath\
NotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeBackSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderShouldReturnDownloadPathNotEscapingUsers\
DownloadFolder) {
std::wstring parent_folder(kLongEscapeSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithMixedSlashShouldReturnDownloadPath\
NotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeMixedSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithEndingEscapeShouldReturnDownload\
PathNotEscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeEndingEscape);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithMultiple\
AttemptsToEscapeUsersDownloadFolderWithEndingSlashShouldReturnDownloadPathNot\
EscapingUsersDownloadFolder) {
std::wstring parent_folder(kLongEscapeEndingEscapeWithSlash);
std::wstring file_name(L"");
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, default_download_path_ + kTwoLevelFolder);
}
TEST_F(FilePathTests, GetDownloadPathWithSlashFileName\
ArgumentsShouldReturnBaseDownloadPath) {
std::wstring parent_folder(L"");
@@ -852,5 +789,88 @@ AHoleBetweenRenamedFiles) {
input_file.open(output_file3_path, std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
TEST_F(FilePathTests, GetDownloadPathWithFileName\
FileNameTwoDotsFrontShouldReturnBaseDownloadPathWithFileNameTwoDotsFront) {
std::wstring parent_folder(L"");
std::wstring file_name(kFileNameWithFrontTwoDots);
std::wstringstream path(L"");
path << default_download_path_ << L"/" << file_name;
std::wstring expected = path.str();
auto actual = FilePath::GetDownloadPath(parent_folder, file_name);
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPathWithFileName\
FileNameThreeDotsShouldReturnBaseDownloadPathWithUnderscore) {
std::wstring parent_folder(L"");
std::wstring file_name(kFileNameWithThreeDots);
std::wstringstream path(L"");
path << default_download_path_ << L"/.._";
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
TEST_F(FilePathTests, GetDownloadPath_FileExistsReturns\
FileWithIncrementedNameWithNull) {
std::wstring file_name(kFileName);
int size = file_name.size();
file_name.append(L"1.txt");
file_name[size] = L'\x00';
std::wstring renamed_file_name(kFileNameWithNullReplaced);
std::wstring parent_folder(L"");
std::wstring output_file_path(default_download_path_);
output_file_path.append(L"/");
output_file_path.append(file_name);
std::wstring expected(default_download_path_);
expected += renamed_file_name;
std::wifstream input_file;
std::wofstream output_file;
output_file.open(output_file_path,
std::ofstream::binary | std::ofstream::out);
ASSERT_TRUE(output_file.rdstate() == std::ofstream::goodbit);
output_file.close();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
// Remove the file and check that it is removed
// File 1
_wremove(output_file_path.c_str());
input_file.open(output_file_path, std::ifstream::binary | std::ifstream::in);
ASSERT_FALSE(input_file.rdstate() == std::ifstream::goodbit);
}
TEST_F(FilePathTests, GetDownloadPathWithFileName\
ParentFolderWithADotShouldBeReplaceedWithUnderscore) {
std::wstring parent_folder(L"test/./folder/");
std::wstring file_name(kFileName);
std::wstringstream path(L"");
path << default_download_path_ << L"/test/_/folder" << L"/" << kFileName;
std::wstring expected = path.str();
auto actual(FilePath::GetDownloadPath(parent_folder, file_name));
EXPECT_EQ(actual, expected);
}
} // namespace windows
} // namespace nearby
@@ -15,10 +15,13 @@ licenses(["notice"])
cc_library(
name = "types",
hdrs = glob(["**/*.h"]),
includes = ["."],
linkopts = [
"wininet.lib",
"advapi32.lib",
"bcrypt.lib",
"cfgmgr32.lib",
"comdlg32.lib",
"gdi32.lib",
"kernel32.lib",
@@ -38,12 +41,11 @@ cc_library(
"wlanapi.lib",
"shlwapi.lib",
],
textual_hdrs = glob(["**/*.h"]),
visibility = [
"//fastpair:__subpackages__",
"//internal:__subpackages__",
"//internal/platform/implementation/windows:__subpackages__",
"//location/nearby/cpp/sharing/implementation/internal:__subpackages__",
"//third_party/nearby/sharing:__subpackages__",
"//location/nearby/apps/better_together/plugins:__subpackages__",
"//sharing:__subpackages__",
],
)
@@ -22,6 +22,8 @@
#include "absl/strings/ascii.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/http_loader.h"
#include "internal/platform/logging.h"
namespace nearby {
@@ -202,8 +204,8 @@ absl::Status HttpLoader::ConnectWebServer() {
0); /*Flags*/
if (internet_handle_ == nullptr) {
NEARBY_LOGS(ERROR) << "Failed to open internet with error "
<< GetLastError() << ".";
LOG(ERROR) << "Failed to open internet with error " << GetLastError()
<< ".";
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
@@ -217,8 +219,8 @@ absl::Status HttpLoader::ConnectWebServer() {
0); /*Context*/
if (connect_handle_ == nullptr) {
NEARBY_LOGS(ERROR) << "Failed to connect remote web server with error "
<< GetLastError() << ".";
LOG(ERROR) << "Failed to connect remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(internet_handle_);
return absl::FailedPreconditionError(absl::StrCat(GetLastError()));
}
@@ -242,9 +244,8 @@ absl::Status HttpLoader::SendRequest() {
0);
if (request_handle_ == nullptr) {
NEARBY_LOGS(ERROR)
<< "Failed to open request to remote web server with error "
<< GetLastError() << ".";
LOG(ERROR) << "Failed to open request to remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(internet_handle_);
InternetCloseHandle(connect_handle_);
@@ -284,9 +285,8 @@ absl::Status HttpLoader::SendRequest() {
data_size); /*Data size*/
if (result == FALSE) {
NEARBY_LOGS(ERROR)
<< "Failed to send request to remote web server with error "
<< GetLastError() << ".";
LOG(ERROR) << "Failed to send request to remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(request_handle_);
InternetCloseHandle(connect_handle_);
InternetCloseHandle(internet_handle_);
@@ -334,9 +334,8 @@ absl::StatusOr<WebResponse> HttpLoader::ProcessResponse() {
web_response.body.append(buffer, read_size);
}
} else {
NEARBY_LOGS(ERROR)
<< "Failed to read response from remote web server with error "
<< GetLastError() << ".";
LOG(ERROR) << "Failed to read response from remote web server with error "
<< GetLastError() << ".";
InternetCloseHandle(request_handle_);
InternetCloseHandle(connect_handle_);
InternetCloseHandle(internet_handle_);
@@ -1,71 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/log_message.h"
#include <algorithm>
#include "strings/strappendv.h"
namespace nearby {
namespace windows {
api::LogMessage::Severity min_log_severity_ = api::LogMessage::Severity::kInfo;
inline absl::LogSeverity ConvertSeverity(api::LogMessage::Severity severity) {
switch (severity) {
// api::LogMessage::Severity kVerbose and kInfo is mapped to
// absl::LogSeverity kInfo since absl::LogSeverity doesn't have kVerbose
// level.
case api::LogMessage::Severity::kVerbose:
case api::LogMessage::Severity::kInfo:
return absl::LogSeverity::kInfo;
case api::LogMessage::Severity::kWarning:
return absl::LogSeverity::kWarning;
case api::LogMessage::Severity::kError:
return absl::LogSeverity::kError;
case api::LogMessage::Severity::kFatal:
return absl::LogSeverity::kFatal;
}
}
LogMessage::LogMessage(const char* file, int line, Severity severity)
: log_streamer_(ConvertSeverity(severity), file, line) {}
LogMessage::~LogMessage() = default;
void LogMessage::Print(const char* format, ...) {
va_list ap;
va_start(ap, format);
std::string result;
strings::StrAppendV(&result, format, ap);
log_streamer_.stream() << result;
va_end(ap);
}
std::ostream& LogMessage::Stream() { return log_streamer_.stream(); }
} // namespace windows
namespace api {
void LogMessage::SetMinLogSeverity(Severity severity) {
windows::min_log_severity_ = severity;
}
bool LogMessage::ShouldCreateLogMessage(Severity severity) {
return severity >= windows::min_log_severity_;
}
} // namespace api
} // namespace nearby
@@ -1,43 +0,0 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PLATFORM_IMPL_WINDOWS_LOG_MESSAGE_H_
#define PLATFORM_IMPL_WINDOWS_LOG_MESSAGE_H_
#include "glog/logging.h"
#include "internal/platform/implementation/log_message.h"
namespace nearby {
namespace windows {
// See documentation in
// cpp/platform/api/log_message.h
class LogMessage : public api::LogMessage {
public:
LogMessage(const char* file, int line, Severity severity);
~LogMessage() override;
void Print(const char* format, ...) override;
std::ostream& Stream() override;
private:
google::LogMessage log_streamer_;
static api::LogMessage::Severity min_log_severity_;
};
} // namespace windows
} // namespace nearby
#endif // PLATFORM_IMPL_WINDOWS_LOG_MESSAGE_H_
@@ -14,12 +14,9 @@
#ifndef PLATFORM_IMPL_WINDOWS_MUTEX_H_
#define PLATFORM_IMPL_WINDOWS_MUTEX_H_
#include <stdio.h>
#include <synchapi.h>
#include <memory>
#include <mutex> // NOLINT
#include "absl/memory/memory.h"
#include "absl/synchronization/mutex.h"
#include "internal/platform/implementation/mutex.h"
@@ -59,7 +56,7 @@ class ABSL_LOCKABLE Mutex : public api::Mutex {
std::recursive_mutex& GetRecursiveMutex() { return recursive_mutex_; }
private:
friend class ConditionVariable;
friend class ::nearby::ConditionVariable;
absl::Mutex mutex_;
std::recursive_mutex recursive_mutex_; // The actual mutex allocation
Mode mode_;
@@ -27,44 +27,57 @@
#include <algorithm>
#include <cstddef>
#include <fstream>
#include <cstdint>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include "absl/base/attributes.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "internal/platform/implementation/atomic_boolean.h"
#include "internal/platform/implementation/atomic_reference.h"
#include "internal/platform/implementation/ble.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/implementation/bluetooth_classic.h"
#include "internal/platform/implementation/condition_variable.h"
#include "internal/platform/implementation/count_down_latch.h"
#include "internal/platform/implementation/credential_storage.h"
#include "internal/platform/implementation/http_loader.h"
#include "internal/platform/implementation/input_file.h"
#include "internal/platform/implementation/mutex.h"
#include "internal/platform/implementation/output_file.h"
#include "internal/platform/implementation/scheduled_executor.h"
#include "internal/platform/implementation/server_sync.h"
#include "internal/platform/implementation/shared/count_down_latch.h"
#include "internal/platform/implementation/submittable_executor.h"
#include "internal/platform/implementation/wifi.h"
#include "internal/platform/implementation/wifi_lan.h"
#include "internal/platform/implementation/windows/atomic_boolean.h"
#include "internal/platform/implementation/windows/atomic_reference.h"
#include "internal/platform/implementation/windows/ble.h"
#include "internal/platform/implementation/windows/ble_medium.h"
#include "internal/platform/implementation/windows/ble_v2.h"
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
#include "internal/platform/implementation/windows/bluetooth_classic_medium.h"
#include "internal/platform/implementation/windows/condition_variable.h"
#include "internal/platform/implementation/windows/device_info.h"
#include "internal/platform/implementation/windows/executor.h"
#include "internal/platform/implementation/windows/file.h"
#include "internal/platform/implementation/windows/file_path.h"
#include "internal/platform/implementation/windows/future.h"
#include "internal/platform/implementation/windows/http_loader.h"
#include "internal/platform/implementation/windows/listenable_future.h"
#include "internal/platform/implementation/windows/log_message.h"
#include "internal/platform/implementation/windows/mutex.h"
#include "internal/platform/implementation/windows/preferences_manager.h"
#include "internal/platform/implementation/windows/scheduled_executor.h"
#include "internal/platform/implementation/windows/server_sync.h"
#include "internal/platform/implementation/windows/settable_future.h"
#include "internal/platform/implementation/windows/string_utils.h"
#include "internal/platform/implementation/windows/submittable_executor.h"
#include "internal/platform/implementation/windows/timer.h"
#include "internal/platform/implementation/windows/utils.h"
#include "internal/platform/implementation/windows/webrtc.h"
#include "internal/platform/implementation/windows/wifi.h"
#include "internal/platform/implementation/windows/wifi_hotspot.h"
#include "internal/platform/implementation/windows/wifi_lan.h"
#include "internal/platform/logging.h"
#include "internal/platform/os_name.h"
#include "internal/platform/payload_id.h"
namespace nearby {
namespace api {
@@ -102,28 +115,28 @@ std::string GetApplicationName(DWORD pid) {
std::string ImplementationPlatform::GetCustomSavePath(
const std::string& parent_folder, const std::string& file_name) {
auto parent = windows::string_to_wstring(parent_folder);
auto file = windows::string_to_wstring(file_name);
auto parent = windows::string_utils::StringToWideString(parent_folder);
auto file = windows::string_utils::StringToWideString(file_name);
return windows::wstring_to_string(
return windows::string_utils::WideStringToString(
windows::FilePath::GetCustomSavePath(parent, file));
}
std::string ImplementationPlatform::GetDownloadPath(
const std::string& parent_folder, const std::string& file_name) {
auto parent = windows::string_to_wstring(std::string(parent_folder));
auto file = windows::string_to_wstring(std::string(file_name));
auto parent = windows::string_utils::StringToWideString(parent_folder);
auto file = windows::string_utils::StringToWideString(file_name);
return windows::wstring_to_string(
return windows::string_utils::WideStringToString(
windows::FilePath::GetDownloadPath(parent, file));
}
std::string ImplementationPlatform::GetDownloadPath(
const std::string& file_name) {
std::wstring fake_parent_path;
auto file = windows::string_to_wstring(std::string(file_name));
auto file = windows::string_utils::StringToWideString(file_name);
return windows::wstring_to_string(
return windows::string_utils::WideStringToString(
windows::FilePath::GetDownloadPath(fake_parent_path, file));
}
@@ -166,29 +179,29 @@ OSName ImplementationPlatform::GetCurrentOS() { return OSName::kWindows; }
std::unique_ptr<AtomicBoolean> ImplementationPlatform::CreateAtomicBoolean(
bool initial_value) {
return absl::make_unique<windows::AtomicBoolean>();
return std::make_unique<windows::AtomicBoolean>(initial_value);
}
std::unique_ptr<AtomicUint32> ImplementationPlatform::CreateAtomicUint32(
std::uint32_t value) {
return absl::make_unique<windows::AtomicUint32>();
return std::make_unique<windows::AtomicUint32>(value);
}
std::unique_ptr<CountDownLatch> ImplementationPlatform::CreateCountDownLatch(
std::int32_t count) {
return absl::make_unique<shared::CountDownLatch>(count);
return std::make_unique<shared::CountDownLatch>(count);
}
#pragma push_macro("CreateMutex")
#undef CreateMutex
std::unique_ptr<Mutex> ImplementationPlatform::CreateMutex(Mutex::Mode mode) {
return absl::make_unique<windows::Mutex>(mode);
return std::make_unique<windows::Mutex>(mode);
}
#pragma pop_macro("CreateMutex")
std::unique_ptr<ConditionVariable>
ImplementationPlatform::CreateConditionVariable(Mutex* mutex) {
return absl::make_unique<windows::ConditionVariable>(mutex);
return std::make_unique<windows::ConditionVariable>(mutex);
}
ABSL_DEPRECATED("This interface will be deleted in the near future.")
@@ -217,8 +230,8 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
const std::string& file_path) {
std::string path(file_path);
auto folder_path =
windows::string_to_wstring(path.substr(0, path.find_last_of('/')));
auto folder_path = windows::string_utils::StringToWideString(
path.substr(0, path.find_last_of('/')));
// Verifies that a path is a valid directory.
// https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-pathisdirectoryw
if (!PathIsDirectoryW(folder_path.data())) {
@@ -232,42 +245,36 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
return windows::IOFile::CreateOutputFile(file_path);
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<LogMessage> ImplementationPlatform::CreateLogMessage(
const char* file, int line, LogMessage::Severity severity) {
return absl::make_unique<windows::LogMessage>(file, line, severity);
}
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateSingleThreadExecutor() {
return absl::make_unique<windows::SubmittableExecutor>();
return std::make_unique<windows::SubmittableExecutor>();
}
std::unique_ptr<SubmittableExecutor>
ImplementationPlatform::CreateMultiThreadExecutor(
std::int32_t max_concurrency) {
return absl::make_unique<windows::SubmittableExecutor>(max_concurrency);
return std::make_unique<windows::SubmittableExecutor>(max_concurrency);
}
std::unique_ptr<ScheduledExecutor>
ImplementationPlatform::CreateScheduledExecutor() {
return absl::make_unique<windows::ScheduledExecutor>();
return std::make_unique<windows::ScheduledExecutor>();
}
std::unique_ptr<BluetoothAdapter>
ImplementationPlatform::CreateBluetoothAdapter() {
return absl::make_unique<windows::BluetoothAdapter>();
return std::make_unique<windows::BluetoothAdapter>();
}
std::unique_ptr<BluetoothClassicMedium>
ImplementationPlatform::CreateBluetoothClassicMedium(
nearby::api::BluetoothAdapter& adapter) {
return absl::make_unique<windows::BluetoothClassicMedium>(adapter);
return std::make_unique<windows::BluetoothClassicMedium>(adapter);
}
std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(
BluetoothAdapter& adapter) {
return absl::make_unique<windows::BleMedium>(adapter);
return std::make_unique<windows::BleMedium>(adapter);
}
// TODO(b/184975123): replace with real implementation.
@@ -276,6 +283,11 @@ ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter& adapter) {
return std::make_unique<windows::BleV2Medium>(adapter);
}
std::unique_ptr<api::CredentialStorage>
ImplementationPlatform::CreateCredentialStorage() {
return nullptr;
}
// TODO(b/184975123): replace with real implementation.
std::unique_ptr<ServerSyncMedium>
ImplementationPlatform::CreateServerSyncMedium() {
@@ -288,7 +300,7 @@ std::unique_ptr<WifiMedium> ImplementationPlatform::CreateWifiMedium() {
}
std::unique_ptr<WifiLanMedium> ImplementationPlatform::CreateWifiLanMedium() {
return absl::make_unique<windows::WifiLanMedium>();
return std::make_unique<windows::WifiLanMedium>();
}
std::unique_ptr<WifiHotspotMedium>
@@ -14,6 +14,7 @@
#include "internal/platform/implementation/windows/preferences_manager.h"
#include <cstdint>
#include <filesystem> // NOLINT(build/c++17)
#include <memory>
#include <optional>
@@ -21,9 +22,16 @@
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "nlohmann/json.hpp"
#include "nlohmann/json_fwd.hpp"
#include "internal/base/files.h"
#include "internal/platform/implementation/platform.h"
#include "internal/platform/implementation/preferences_manager.h"
#include "internal/platform/implementation/windows/preferences_repository.h"
#include "internal/platform/logging.h"
@@ -39,7 +47,8 @@ PreferencesManager::PreferencesManager(absl::string_view file_path)
nearby::api::ImplementationPlatform::CreateDeviceInfo()
->GetLocalAppDataPath();
if (!path.has_value()) {
path = std::filesystem::temp_directory_path();
path = nearby::sharing::GetTemporaryDirectory().value_or(
nearby::sharing::CurrentDirectory());
}
std::filesystem::path full_path = *path / std::string(file_path);
@@ -187,7 +196,7 @@ void PreferencesManager::Remove(absl::string_view key) {
// Writes data to storage.
bool PreferencesManager::Commit() {
if (!preferences_repository_->SavePreferences(value_)) {
NEARBY_LOGS(ERROR) << "Failed to save preference." << std::endl;
LOG(ERROR) << "Failed to save preference." << std::endl;
return false;
}
return true;
@@ -195,8 +204,8 @@ bool PreferencesManager::Commit() {
bool PreferencesManager::SetValue(absl::string_view key, const json& value) {
if (!value_.is_object()) {
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
LOG(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
value_ = json::object();
}
@@ -212,8 +221,8 @@ template <typename T>
T PreferencesManager::GetValue(absl::string_view key,
const T& default_value) const {
if (!value_.is_object()) {
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
LOG(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
return default_value;
}
@@ -228,8 +237,8 @@ template <typename T>
bool PreferencesManager::SetArrayValue(absl::string_view key,
absl::Span<const T> value) {
if (!value_.is_object()) {
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
LOG(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
value_ = json::object();
}
@@ -252,8 +261,8 @@ std::vector<T> PreferencesManager::GetArrayValue(
std::vector<T> result;
if (!value_.is_object()) {
NEARBY_LOGS(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
LOG(ERROR) << "Preferences is no longer an object! value_="
<< value_.dump(4);
for (const T& value : default_value) {
result.push_back(value);
@@ -41,26 +41,23 @@ constexpr absl::Duration kTimeOut = absl::Milliseconds(200);
constexpr char kPreferencesFilePath[] = "Google/Nearby/Sharing";
} // namespace
TEST(PreferencesManager, CorruptedConfigFile) {
std::filesystem::path settingsPath =
std::filesystem::temp_directory_path();
std::filesystem::path settingsPath = std::filesystem::temp_directory_path();
std::ofstream output_stream{settingsPath / "preferences.json"};
output_stream << "CORRUPTED" << std::endl;
NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string();
LOG(INFO) << "Loading preferences from: " << settingsPath.string();
EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100),
100);
}
TEST(PreferencesManager, ValidConfigFile) {
std::filesystem::path settingsPath =
std::filesystem::temp_directory_path();
std::filesystem::path settingsPath = std::filesystem::temp_directory_path();
std::ofstream output_stream{settingsPath / "preferences.json"};
output_stream << "{\"data\":8, \"name\": \"Valid\"}" << std::endl;
output_stream.close();
NEARBY_LOGS(INFO) << "Loading preferences from: " << settingsPath.string();
LOG(INFO) << "Loading preferences from: " << settingsPath.string();
EXPECT_EQ(PreferencesManager(settingsPath.string()).GetInteger("data", 100),
8);
}
@@ -19,8 +19,10 @@
#include <fstream>
#include <optional>
#include "absl/synchronization/mutex.h"
#include "nlohmann/json.hpp"
#include "nlohmann/json_fwd.hpp"
#include "internal/base/files.h"
#include "internal/platform/logging.h"
namespace nearby {
@@ -40,8 +42,8 @@ json PreferencesRepository::LoadPreferences() {
// The top level root should be an object, if it's not then something went
// wrong or the file was corrupted.
if (!preferences.value().is_object()) {
NEARBY_LOGS(ERROR) << "Preferences loaded was not a valid object: "
<< preferences.value().dump(4);
LOG(ERROR) << "Preferences loaded was not a valid object: "
<< preferences.value().dump(4);
return json::object();
}
@@ -49,17 +51,17 @@ json PreferencesRepository::LoadPreferences() {
return preferences.value();
}
NEARBY_LOGS(ERROR) << "Could not load preferences file, trying backup.";
LOG(ERROR) << "Could not load preferences file, trying backup.";
// In the future we should switch to using a transaction log or another
// stable method which doesn't pose a risk of losing settings
preferences = RestoreFromBackup();
if (preferences.has_value()) {
NEARBY_LOGS(ERROR) << "Successfully recovered from backup.";
LOG(ERROR) << "Successfully recovered from backup.";
return preferences.value();
}
NEARBY_LOGS(ERROR) << "Failed to load preferences file from back up.";
LOG(ERROR) << "Failed to load preferences file from back up.";
return json::object();
}
@@ -68,9 +70,9 @@ bool PreferencesRepository::SavePreferences(json preferences) {
absl::MutexLock lock(&mutex_);
try {
std::filesystem::path path = path_;
if (!std::filesystem::exists(path) &&
!std::filesystem::create_directories(path)) {
NEARBY_LOGS(ERROR) << "Failed to create preferences path.";
if (!nearby::sharing::FileExists(path) &&
!nearby::sharing::CreateDirectories(path)) {
LOG(ERROR) << "Failed to create preferences path.";
return false;
}
@@ -78,30 +80,32 @@ bool PreferencesRepository::SavePreferences(json preferences) {
std::filesystem::path full_name_backup = path / kPreferencesBackupFileName;
// Create a backup without moving the bytes on disk
if (std::filesystem::exists(full_name)) {
NEARBY_LOGS(INFO) << "Making backup of preferences file.";
std::filesystem::rename(full_name, full_name_backup);
if (nearby::sharing::FileExists(full_name)) {
LOG(INFO) << "Making backup of preferences file.";
if (!nearby::sharing::Rename(full_name, full_name_backup)) {
LOG(ERROR) << "Failed to rename preferences backup file.";
}
}
std::ofstream preferences_file(full_name.c_str());
std::ofstream preferences_file(full_name);
preferences_file << preferences;
preferences_file.close();
// Make sure the file wasn't saved in a corrupted state
if (!AttemptLoad().has_value()) {
NEARBY_LOGS(ERROR) << "Preferences saved to disk in corrupted state. "
"Restoring from backup.";
LOG(ERROR) << "Preferences saved to disk in corrupted state. "
"Restoring from backup.";
if (!RestoreFromBackup().has_value()) {
NEARBY_LOGS(ERROR) << "Failed to restore preferences file.";
LOG(ERROR) << "Failed to restore preferences file.";
return false;
}
}
} catch (const std::exception& e) {
NEARBY_LOGS(ERROR) << "Failed to save preferences file: " << e.what();
LOG(ERROR) << "Failed to save preferences file: " << e.what();
return false;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return false;
}
@@ -111,12 +115,13 @@ bool PreferencesRepository::SavePreferences(json preferences) {
std::optional<json> PreferencesRepository::AttemptLoad() {
std::filesystem::path path = path_;
std::filesystem::path full_name = path / kPreferencesFileName;
if (!std::filesystem::exists(path) || !std::filesystem::exists(full_name)) {
if (!nearby::sharing::DirectoryExists(path) ||
!nearby::sharing::FileExists(full_name)) {
return std::nullopt;
}
try {
std::ifstream preferences_file(full_name.c_str());
std::ifstream preferences_file(full_name);
if (!preferences_file.good()) {
return std::nullopt;
}
@@ -125,16 +130,16 @@ std::optional<json> PreferencesRepository::AttemptLoad() {
preferences_file.close();
if (preferences.is_discarded()) {
NEARBY_LOGS(ERROR) << "Preferences file corrupted.";
LOG(ERROR) << "Preferences file corrupted.";
return std::nullopt;
}
return preferences;
} catch (const std::exception& e) {
NEARBY_LOGS(ERROR) << "Exception while loading preferences: " << e.what();
LOG(ERROR) << "Exception while loading preferences: " << e.what();
return std::nullopt;
} catch (...) {
NEARBY_LOGS(ERROR) << __func__ << ": Unknown exception.";
LOG(ERROR) << __func__ << ": Unknown exception.";
return std::nullopt;
}
}
@@ -144,15 +149,16 @@ std::optional<json> PreferencesRepository::RestoreFromBackup() {
std::filesystem::path full_name = path / kPreferencesFileName;
std::filesystem::path full_name_backup = path / kPreferencesBackupFileName;
if (!std::filesystem::exists(full_name_backup)) {
NEARBY_LOGS(WARNING)
<< "Backup requested but no backup preferences file found.";
if (!nearby::sharing::FileExists(full_name_backup)) {
LOG(WARNING) << "Backup requested but no backup preferences file found.";
return std::nullopt;
}
std::filesystem::rename(full_name_backup, full_name);
if (!nearby::sharing::Rename(full_name_backup, full_name)) {
LOG(ERROR) << "Failed to rename preferences backup file.";
}
NEARBY_LOGS(INFO) << "Attempting load from backup preferences.";
LOG(INFO) << "Attempting load from backup preferences.";
return AttemptLoad();
}
@@ -16,19 +16,25 @@
#include <crtdbg.h>
#include <algorithm>
#include <memory>
#include <utility>
#include "absl/time/time.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/flags/nearby_platform_feature_flags.h"
#include "internal/platform/implementation/cancelable.h"
#include "internal/platform/logging.h"
#include "internal/platform/runnable.h"
namespace nearby {
namespace windows {
ScheduledExecutor::ScheduledExecutor()
: executor_(std::make_unique<nearby::windows::Executor>()),
shut_down_(false) {}
shut_down_(false),
use_task_scheduler_(NearbyFlags::GetInstance().GetBoolFlag(
platform::config_package_nearby::nearby_platform_feature::
kEnableTaskScheduler)) {}
// Cancelable is kept both in the executor context, and in the caller context.
// We want Cancelable to live until both caller and executor are done with it.
@@ -36,30 +42,44 @@ ScheduledExecutor::ScheduledExecutor()
// using std:shared_ptr<> instead of std::unique_ptr<>.
std::shared_ptr<api::Cancelable> ScheduledExecutor::Schedule(
Runnable&& runnable, absl::Duration duration) {
if (shut_down_) {
NEARBY_LOGS(ERROR) << __func__
<< ": Attempt to Schedule on a shut down executor.";
if (use_task_scheduler_) {
if (shut_down_) {
LOG(ERROR) << __func__
<< ": Attempt to Schedule on a shut down executor.";
return nullptr;
return nullptr;
}
return task_scheduler_.Schedule(std::move(runnable), duration);
} else {
if (shut_down_) {
LOG(ERROR) << __func__
<< ": Attempt to Schedule on a shut down executor.";
return nullptr;
}
// Cleans completed tasks
auto it = scheduled_tasks_.begin();
while (it != scheduled_tasks_.end()) {
if ((*it)->IsDone()) {
it = scheduled_tasks_.erase(it);
} else {
++it;
}
}
std::shared_ptr<ScheduledTask> task =
std::make_shared<ScheduledTask>(std::move(runnable), duration);
scheduled_tasks_.push_back(task);
executor_->Execute([task]() { task->Start(); });
return task;
}
// Cleans completed tasks
std::remove_if(
scheduled_tasks_.begin(), scheduled_tasks_.end(),
[](std::shared_ptr<ScheduledTask>& task) { return task->IsDone(); });
std::shared_ptr<ScheduledTask> task =
std::make_shared<ScheduledTask>(std::move(runnable), duration);
scheduled_tasks_.push_back(task);
executor_->Execute([task]() { task->Start(); });
return task;
}
void ScheduledExecutor::Execute(Runnable&& runnable) {
if (shut_down_) {
NEARBY_LOGS(ERROR) << __func__
<< ": Attempt to Execute on a shut down executor.";
LOG(ERROR) << __func__ << ": Attempt to Execute on a shut down executor.";
return;
}
@@ -67,18 +87,26 @@ void ScheduledExecutor::Execute(Runnable&& runnable) {
}
void ScheduledExecutor::Shutdown() {
if (!shut_down_) {
shut_down_ = true;
for (auto& task : scheduled_tasks_) {
task->Cancel();
if (use_task_scheduler_) {
if (!shut_down_) {
shut_down_ = true;
executor_->Shutdown();
task_scheduler_.Shutdown();
return;
}
} else {
if (!shut_down_) {
shut_down_ = true;
for (auto& task : scheduled_tasks_) {
task->Cancel();
}
scheduled_tasks_.clear();
executor_->Shutdown();
return;
scheduled_tasks_.clear();
executor_->Shutdown();
return;
}
}
NEARBY_LOGS(ERROR) << __func__
<< ": Attempt to Shutdown on a shut down executor.";
LOG(ERROR) << __func__ << ": Attempt to Shutdown on a shut down executor.";
}
} // namespace windows
} // namespace nearby
@@ -17,8 +17,8 @@
#include <windows.h>
#include <atomic>
#include <memory>
#include <utility>
#include <vector>
#include "absl/synchronization/notification.h"
@@ -26,6 +26,8 @@
#include "internal/platform/implementation/cancelable.h"
#include "internal/platform/implementation/scheduled_executor.h"
#include "internal/platform/implementation/windows/executor.h"
#include "internal/platform/implementation/windows/task_scheduler.h"
#include "internal/platform/runnable.h"
namespace nearby {
namespace windows {
@@ -49,7 +51,7 @@ class ScheduledExecutor : public api::ScheduledExecutor {
std::shared_ptr<api::Cancelable> Schedule(Runnable&& runnable,
absl::Duration duration) override;
// Executes the runnable task immedately.
// Executes the runnable task immediately.
void Execute(Runnable&& runnable) override;
// Shutdowns the executor, all scheduled task will be cancelled.
@@ -94,6 +96,9 @@ class ScheduledExecutor : public api::ScheduledExecutor {
std::unique_ptr<nearby::windows::Executor> executor_ = nullptr;
std::vector<std::shared_ptr<ScheduledTask>> scheduled_tasks_;
std::atomic_bool shut_down_ = false;
const bool use_task_scheduler_;
TaskScheduler task_scheduler_;
};
} // namespace windows
@@ -14,6 +14,7 @@
#include "internal/platform/implementation/windows/scheduled_executor.h"
#include <chrono> // NOLINT
#include <memory>
#include <utility>
@@ -21,13 +22,31 @@
#include "absl/synchronization/notification.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/flags/nearby_platform_feature_flags.h"
#include "internal/platform/implementation/windows/test_data.h"
namespace nearby {
namespace windows {
namespace {
TEST(ScheduledExecutorTests, ExecuteSucceeds) {
constexpr absl::Duration kWaitTimeout = absl::Milliseconds(2000);
class ScheduledExecutorTest : public ::testing::TestWithParam<bool> {
public:
void SetUp() override {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
platform::config_package_nearby::nearby_platform_feature::
kEnableTaskScheduler,
GetParam());
}
void TearDown() override {
NearbyFlags::GetInstance().ResetOverridedValues();
}
};
TEST_P(ScheduledExecutorTest, ExecuteSucceeds) {
absl::Notification notification;
// Arrange
std::string expected(RUNNABLE_0_TEXT.c_str());
@@ -47,8 +66,7 @@ TEST(ScheduledExecutorTests, ExecuteSucceeds) {
notification.Notify();
});
ASSERT_TRUE(
notification.WaitForNotificationWithTimeout(absl::Milliseconds(200)));
ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
submittableExecutor->Shutdown();
// Assert
@@ -61,7 +79,7 @@ TEST(ScheduledExecutorTests, ExecuteSucceeds) {
ASSERT_EQ(output, expected);
}
TEST(ScheduledExecutorTests, ScheduleSucceeds) {
TEST_P(ScheduledExecutorTest, ScheduleSucceeds) {
absl::Notification notification;
// Arrange
std::string expected(RUNNABLE_0_TEXT.c_str());
@@ -88,8 +106,7 @@ TEST(ScheduledExecutorTests, ScheduleSucceeds) {
},
absl::Milliseconds(50));
ASSERT_TRUE(
notification.WaitForNotificationWithTimeout(absl::Milliseconds(200)));
ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
submittableExecutor->Shutdown();
ASSERT_EQ(threadIds->size(), 2);
@@ -99,7 +116,7 @@ TEST(ScheduledExecutorTests, ScheduleSucceeds) {
ASSERT_EQ(output, expected);
}
TEST(ScheduledExecutorTests, CancelSucceeds) {
TEST_P(ScheduledExecutorTest, CancelSucceeds) {
absl::Notification notification;
// Arrange
std::string expected("");
@@ -123,8 +140,7 @@ TEST(ScheduledExecutorTests, CancelSucceeds) {
auto actual = cancelable->Cancel();
EXPECT_FALSE(
notification.WaitForNotificationWithTimeout(absl::Milliseconds(2000)));
EXPECT_FALSE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
submittableExecutor->Shutdown();
// Assert
@@ -136,7 +152,7 @@ TEST(ScheduledExecutorTests, CancelSucceeds) {
ASSERT_EQ(output, expected);
}
TEST(ScheduledExecutorTests, CancelAfterStartedFails) {
TEST_P(ScheduledExecutorTest, CancelAfterStartedFails) {
absl::Notification notification;
// Arrange
std::string expected(RUNNABLE_0_TEXT.c_str());
@@ -158,11 +174,10 @@ TEST(ScheduledExecutorTests, CancelAfterStartedFails) {
},
absl::Milliseconds(100));
absl::SleepFor(absl::Milliseconds(200));
absl::SleepFor(absl::Milliseconds(500));
auto actual = cancelable->Cancel();
ASSERT_TRUE(
notification.WaitForNotificationWithTimeout(absl::Milliseconds(2000)));
ASSERT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
submittableExecutor->Shutdown();
// Assert
@@ -174,6 +189,9 @@ TEST(ScheduledExecutorTests, CancelAfterStartedFails) {
ASSERT_EQ(output, expected);
}
INSTANTIATE_TEST_SUITE_P(ScheduledExecutorTaskSchedulerFlagTest,
ScheduledExecutorTest, testing::Bool());
} // namespace
} // namespace windows
} // namespace nearby
@@ -24,6 +24,7 @@
#include "absl/base/const_init.h"
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "internal/platform/implementation/windows/submittable_executor.h"
@@ -91,7 +92,7 @@ bool SessionManager::RegisterSessionListener(
absl::string_view listener_name,
absl::AnyInvocable<void(SessionState)> callback) {
absl::MutexLock lock(&session_mutex_);
NEARBY_LOGS(INFO) << __func__ << ": Registering listener: " << listener_name;
LOG(INFO) << __func__ << ": Registering listener: " << listener_name;
// Create session thread if no running thread.
if (session_thread_ == nullptr) {
@@ -114,38 +115,36 @@ bool SessionManager::RegisterSessionListener(
session_callbacks_->emplace(listener_name, std::move(callback));
listeners_.emplace(listener_name);
NEARBY_LOGS(INFO) << __func__ << ": Session listener: " << listener_name
<< " is registered.";
LOG(INFO) << __func__ << ": Session listener: " << listener_name
<< " is registered.";
return true;
}
bool SessionManager::UnregisterSessionListener(
absl::string_view listener_name) {
absl::MutexLock lock(&session_mutex_);
NEARBY_LOGS(INFO) << __func__
<< ": Unregistering listener: " << listener_name;
LOG(INFO) << __func__ << ": Unregistering listener: " << listener_name;
if (session_thread_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": No running listener.";
LOG(ERROR) << __func__ << ": No running listener.";
return false;
}
if (!session_callbacks_->contains(listener_name) ||
!listeners_.contains(listener_name)) {
NEARBY_LOGS(ERROR) << __func__
<< ": No listener with name:" << listener_name;
LOG(ERROR) << __func__ << ": No listener with name:" << listener_name;
return false;
}
session_callbacks_->erase(listener_name);
listeners_.erase(listener_name);
if (!session_callbacks_->empty()) {
NEARBY_LOGS(INFO) << __func__ << ": Session listener: " << listener_name
<< " is unregistered.";
LOG(INFO) << __func__ << ": Session listener: " << listener_name
<< " is unregistered.";
return true;
}
CleanUp();
NEARBY_LOGS(INFO) << __func__ << ": Session listener: " << listener_name
<< " is unregistered.";
LOG(INFO) << __func__ << ": Session listener: " << listener_name
<< " is unregistered.";
return true;
}
@@ -178,8 +177,7 @@ bool SessionManager::PreventSleep() const {
EXECUTION_STATE execution_state =
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
if (execution_state == 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set execution state of the thread.";
LOG(ERROR) << __func__ << ": Failed to set execution state of the thread.";
return false;
}
return true;
@@ -188,16 +186,15 @@ bool SessionManager::PreventSleep() const {
bool SessionManager::AllowSleep() const {
EXECUTION_STATE execution_state = SetThreadExecutionState(ES_CONTINUOUS);
if (execution_state == 0) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to set execution state of the thread.";
LOG(ERROR) << __func__ << ": Failed to set execution state of the thread.";
return false;
}
return true;
}
void SessionManager::NotifySessionState(SessionState state) {
NEARBY_LOGS(INFO) << __func__
<< ": Notifying session state: " << static_cast<int>(state);
LOG(INFO) << __func__
<< ": Notifying session state: " << static_cast<int>(state);
if (state == SessionManager::SessionState::kLock) {
absl::MutexLock lock(&session_mutex_);
for (auto& it : *SessionManager::session_callbacks_) {
@@ -214,19 +211,18 @@ void SessionManager::NotifySessionState(SessionState state) {
void SessionManager::StartSession(absl::Notification& notification) {
session_hwnd_ = CreateNearbyWindow();
if (session_hwnd_ == nullptr) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to create session Window.";
LOG(ERROR) << __func__ << ": Failed to create session Window.";
return;
}
if (!WTSRegisterSessionNotification(session_hwnd_, NOTIFY_FOR_THIS_SESSION)) {
NEARBY_LOGS(ERROR) << __func__
<< ":Failed to register session notification.";
LOG(ERROR) << __func__ << ":Failed to register session notification.";
return;
}
notification.Notify();
NEARBY_LOGS(INFO) << __func__ << ": Session thread started.";
LOG(INFO) << __func__ << ": Session thread started.";
// Main message loop
MSG msg = {};
@@ -237,17 +233,16 @@ void SessionManager::StartSession(absl::Notification& notification) {
}
if (!WTSUnRegisterSessionNotification(session_hwnd_)) {
NEARBY_LOGS(ERROR) << __func__
<< ": Failed to register session notification.";
LOG(ERROR) << __func__ << ": Failed to register session notification.";
return;
}
if (!UnregisterClassA(/*lpClassName=*/kMessageWindowClass,
/*hInstance=*/(HINSTANCE)GetModuleHandle(nullptr))) {
NEARBY_LOGS(ERROR) << __func__ << ": Failed to unregister window class.";
LOG(ERROR) << __func__ << ": Failed to unregister window class.";
}
NEARBY_LOGS(INFO) << __func__ << ": Completed Message loop.";
LOG(INFO) << __func__ << ": Completed Message loop.";
}
void SessionManager::StopSession() {
@@ -0,0 +1,113 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/platform/implementation/windows/string_utils.h"
#include <windows.h>
#include <string>
#include "internal/platform/logging.h"
namespace nearby::windows::string_utils {
// Converts std::string to wstring
std::wstring StringToWideString(std::string str) {
if (str.empty()) {
return L"";
}
// https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar
int output_length =
MultiByteToWideChar(/*CodePage=*/CP_UTF8,
/*dwFlags=*/0,
/*lpMultiByteStr=*/str.c_str(),
/*cbMultiByte=*/static_cast<int>(str.length()),
/*lpWideCharStr=*/nullptr,
/*cchWideChar=*/0);
if (output_length == 0) {
return L"";
}
std::wstring output(output_length, L'\0');
int result = MultiByteToWideChar(
/*CodePage=*/CP_UTF8, /*dwFlags=*/0, /*lpMultiByteStr=*/str.c_str(),
/*cbMultiByte=*/static_cast<int>(str.length()),
/*lpWideCharStr=*/&output[0],
/*cchWideChar=*/output_length);
if (result == 0) {
LOG(INFO) << "Error converting String to Wstring. Error code: "
<< GetLastError();
return L"";
}
return output;
}
// Converts wstring to std::string
std::string WideStringToString(std::wstring wstr) {
if (wstr.empty()) {
return "";
}
std::string output;
size_t start = 0;
size_t index = 0;
// Iterate over the wstring buffer, chop it into wchar chunks and convert them
// one-by-one
do {
index = wstr.find(L'\0', start);
if (index == std::wstring::npos) index = wstr.length();
if (start <= wstr.length()) {
// https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte
int size =
WideCharToMultiByte(/*CodePage=*/CP_UTF8,
/*dwFlags=*/WC_ERR_INVALID_CHARS,
/*lpWideCharStr=*/&wstr[start],
/*cchWideChar=*/static_cast<int>(index - start),
/*lpMultiByteStr=*/nullptr,
/*cbMultiByte=*/0,
/*lpDefaultChar=*/nullptr,
/*lpUsedDefaultChar=*/nullptr);
if (size == 0) {
return "";
}
std::string converted_chunk = std::string(size, '\0');
int result = WideCharToMultiByte(
/*CodePage=*/CP_UTF8, /*dwFlags=*/WC_ERR_INVALID_CHARS,
/*lpWideCharStr=*/&wstr[start],
/*cchWideChar=*/static_cast<int>(index - start),
/*lpMultiByteStr=*/&converted_chunk[0],
/*cbMultiByte=*/static_cast<int>(converted_chunk.size()),
/*lpDefaultChar=*/nullptr,
/*lpUsedDefaultChar=*/nullptr);
if (result == 0) {
LOG(INFO) << "Error converting Wstring to String. Error code: "
<< GetLastError();
return "";
}
output.append(converted_chunk);
// Append '\0' to handle the case of {wstring \0 wstring \0 wstring} ->
// {string \0 string \0 string}
if (index < wstr.length()) {
LOG(INFO) << "Appending a null byte to string";
output.append(1, '\0');
}
}
start = index + 1;
} while (index != std::wstring::npos && start < wstr.length());
return output;
}
} // namespace nearby::windows::string_utils
@@ -0,0 +1,29 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_STRING_UTILS_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_STRING_UTILS_H_
#include <string>
namespace nearby::windows::string_utils {
// Converts UTF-8 encoded string to wstring
std::wstring StringToWideString(std::string str);
// Converts wstring to UTF-8 encoded string
std::string WideStringToString(std::wstring wstr);
} // namespace nearby::windows::string_utils
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_STRING_UTILS_H_

Some files were not shown because too many files have changed in this diff Show More