diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index cafc5b01..15eeba14 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -105,14 +105,15 @@ jobs: --cxxopt='-fvisibility-inlines-hidden' \ //sharing/linux:nearby_sharing_api_shared - build-rust-linux: - name: Build Rust on Linux - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - submodules: recursive - - - name: Build FPP - run: cargo build --manifest-path presence/fpp/fpp/Cargo.toml +# building presence is unsupported now :( +# build-rust-linux: +# name: Build Rust on Linux +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v6 +# with: +# submodules: recursive +# +# - name: Build FPP +# run: cargo build --manifest-path presence/fpp/fpp/Cargo.toml diff --git a/sharing/proto/analytics/BUILD b/BUILD.bazel similarity index 57% rename from sharing/proto/analytics/BUILD rename to BUILD.bazel index 3a8e26d8..82473d02 100644 --- a/sharing/proto/analytics/BUILD +++ b/BUILD.bazel @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2026 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,25 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") -load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") - -licenses(["notice"]) +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") package(default_visibility = ["//visibility:public"]) -proto_library( - name = "sharing_log_proto", - srcs = [ - "nearby_sharing_log.proto", - ], - deps = [ - "//proto:sharing_enums_proto", - "@com_google_protobuf//:duration_proto", - ], +licenses(["notice"]) + +bool_flag( + name = "enable_webrtc", + build_setting_default = False, ) -cc_proto_library( - name = "sharing_log_cc_proto", - deps = [":sharing_log_proto"], +config_setting( + name = "webrtc_enabled", + flag_values = {":enable_webrtc": "True"}, ) diff --git a/Package.swift b/Package.swift index 6d3d5326..d96c9aa4 100644 --- a/Package.swift +++ b/Package.swift @@ -92,7 +92,7 @@ let package = Package( .target( name: "protobuf-utf8", dependencies: [ - .product(name: "abseil", package: "abseil-cpp-SwiftPM"), + .product(name: "abseil", package: "abseil-cpp-SwiftPM") ], path: "third_party/protobuf/third_party/utf8_range", sources: [ @@ -102,13 +102,13 @@ let package = Package( ], publicHeadersPath: ".", cSettings: [ - .headerSearchPath("./"), + .headerSearchPath("./") ], ), .target( name: "protobuf", dependencies: [ - "protobuf-utf8", + "protobuf-utf8" ], path: "third_party/protobuf/src", exclude: [ @@ -282,11 +282,11 @@ let package = Package( "google/protobuf/io/zero_copy_sink_test.cc", ], sources: [ - "google/protobuf", + "google/protobuf" ], publicHeadersPath: ".", cSettings: [ - .headerSearchPath("./"), + .headerSearchPath("./") ] ), .target( @@ -321,7 +321,6 @@ let package = Package( "connections/implementation/flags/BUILD", "connections/implementation/mediums/advertisements/BUILD", "connections/implementation/mediums/ble/BUILD", - "connections/implementation/mediums/multiplex/BUILD", "connections/implementation/mediums/BUILD", "connections/implementation/BUILD", "connections/implementation/fuzzers", @@ -346,7 +345,6 @@ let package = Package( "internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD", "internal/platform/implementation/BUILD", "internal/platform/BUILD", - "internal/analytics/BUILD", "internal/flags/BUILD", "internal/network/BUILD", "internal/rpc/BUILD", @@ -369,16 +367,12 @@ let package = Package( "connections/implementation/payload_manager_test.cc", "connections/implementation/offline_frames_validator_test.cc", "connections/implementation/service_controller_router_test.cc", - "connections/implementation/bluetooth_bwu_test.cc", - "connections/implementation/wifi_direct_bwu_test.cc", - "connections/implementation/wifi_hotspot_bwu_test.cc", - "connections/implementation/wifi_lan_bwu_handler_test.cc", - "connections/implementation/analytics/analytics_recorder_test.cc", - "connections/implementation/analytics/throughput_recorder_test.cc", + "connections/implementation/analytics/analytics_recorder_impl_test.cc", "connections/implementation/mediums/advertisements/data_element_test.cc", "connections/implementation/mediums/advertisements/dct_advertisement_test.cc", "connections/implementation/mediums/advertisements/advertisement_util_test.cc", "connections/implementation/mediums/awdl_test.cc", + "connections/implementation/mediums/awdl_bwu_handler_test.cc", "connections/implementation/mediums/ble_test.cc", "connections/implementation/mediums/ble/bloom_filter_test.cc", "connections/implementation/mediums/ble/ble_l2cap_packet_test.cc", @@ -391,18 +385,19 @@ let package = Package( "connections/implementation/mediums/ble/discovered_peripheral_tracker_test.cc", "connections/implementation/mediums/ble/instant_on_lost_advertisement_test.cc", "connections/implementation/mediums/ble/instant_on_lost_manager_test.cc", - "connections/implementation/mediums/multiplex/multiplex_frames_test.cc", - "connections/implementation/mediums/multiplex/multiplex_socket_test.cc", - "connections/implementation/mediums/multiplex/multiplex_output_stream_test.cc", - "connections/implementation/mediums/webrtc_peer_id_test.cc", - "connections/implementation/mediums/wifi_lan_test.cc", - "connections/implementation/mediums/bluetooth_classic_test.cc", "connections/implementation/mediums/ble_test.cc", - "connections/implementation/mediums/webrtc_test.cc", - "connections/implementation/mediums/lost_entity_tracker_test.cc", + "connections/implementation/mediums/bluetooth_bwu_handler_test.cc", + "connections/implementation/mediums/bluetooth_classic_test.cc", "connections/implementation/mediums/bluetooth_radio_test.cc", + "connections/implementation/mediums/lost_entity_tracker_test.cc", + "connections/implementation/mediums/webrtc_peer_id_test.cc", + "connections/implementation/mediums/webrtc_test.cc", + "connections/implementation/mediums/wifi_direct_bwu_handler_test.cc", "connections/implementation/mediums/wifi_direct_test.cc", + "connections/implementation/mediums/wifi_hotspot_bwu_handler_test.cc", "connections/implementation/mediums/wifi_hotspot_test.cc", + "connections/implementation/mediums/wifi_lan_bwu_handler_test.cc", + "connections/implementation/mediums/wifi_lan_test.cc", "connections/implementation/mediums/wifi_test.cc", "connections/implementation/endpoint_channel_manager_test.cc", "connections/implementation/bwu_manager_test.cc", @@ -437,13 +432,13 @@ let package = Package( "internal/encoding/base85_test.cc", "internal/data/leveldb_data_set_test.cc", "internal/flags/nearby_flags_test.cc", - "internal/proto/analytics/connections_log_test.cc", "internal/platform/feature_flags_test.cc", "internal/platform/file_test.cc", "internal/platform/cancelable_alarm_test.cc", "internal/platform/crypto_test.cc", "internal/platform/byte_array_test.cc", "internal/platform/credential_storage_impl_test.cc", + "internal/platform/implementation/device_info_test.cc", "internal/platform/implementation/g3/awdl_test.cc", "internal/platform/implementation/g3/ble_test.cc", "internal/platform/input_stream_test.cc", @@ -478,6 +473,7 @@ let package = Package( "internal/platform/implementation/apple/mutex_test.cc", "internal/platform/implementation/apple/atomic_boolean_test.cc", "internal/platform/implementation/apple/atomic_uint32_test.cc", + "internal/platform/implementation/apple/webrtc_platform.mm", "internal/platform/implementation/shared/file_test.cc", "internal/platform/implementation/wifi_utils_test.cc", "internal/platform/atomic_boolean_test.cc", @@ -500,7 +496,6 @@ let package = Package( "internal/network/http_client_impl_test.cc", "internal/network/http_status_code_test.cc", "internal/test/fake_clock_test.cc", - "internal/test/fake_webrtc.cc", "internal/test/fake_timer_test.cc", "internal/test/fake_device_info_test.cc", "internal/test/fake_task_runner_test.cc", @@ -522,16 +517,9 @@ let package = Package( "proto", "internal/data/leveldb_data_set_test.proto", // webrtc - "connections/implementation/webrtc_bwu_handler.cc", - "connections/implementation/webrtc_endpoint_channel.cc", - "connections/implementation/mediums/webrtc.cc", - "connections/implementation/mediums/webrtc_peer_id.cc", - "connections/implementation/mediums/webrtc", - "internal/platform/tachyon_express_signaling_messenger.cc", - "internal/platform/tachyon_express_signaling_messenger.h", "internal/platform/implementation/apple/webrtc.h", "internal/platform/implementation/apple/webrtc.mm", - // This breaks the build, but seems to work fine without it? + // Only used in tests "internal/platform/medium_environment.cc", ], sources: [ @@ -564,6 +552,7 @@ let package = Package( .headerSearchPath("./"), .headerSearchPath("compiled_proto/"), .define("NO_WEBRTC"), + .define("NC_OSS_BUILD"), ] ), .target( diff --git a/connections/BUILD b/connections/BUILD index 1bf50743..9725036d 100644 --- a/connections/BUILD +++ b/connections/BUILD @@ -44,9 +44,11 @@ cc_library( ], deps = [ ":core_types", + "//connections/implementation:client_proxy", "//connections/implementation:internal", + "//connections/implementation:service_id_constants", + "//connections/implementation/analytics", "//connections/v3:v3_types", - "//internal/analytics:event_logger", "//internal/interop:device", "//internal/platform:base", "//internal/platform:logging", @@ -95,9 +97,9 @@ cc_library( "//connections/implementation/proto:offline_wire_formats_cc_proto", "//internal/interop:authentication_status", "//internal/platform:base", + "//internal/platform:comm", "//internal/platform:logging", "//internal/platform:mac_address", - "//internal/platform:types", "//internal/platform:util", "//proto:connections_enums_cc_proto", "@com_google_absl//absl/functional:any_invocable", @@ -124,6 +126,7 @@ cc_test( "//connections/implementation:internal_test", "//connections/v3:v3_types", "//internal/platform:base", + "//internal/platform:comm", "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep diff --git a/connections/c/BUILD b/connections/c/BUILD index a9ce6b37..c745e9c9 100644 --- a/connections/c/BUILD +++ b/connections/c/BUILD @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_apple//apple:apple.bzl", "apple_static_xcframework") +load("@rules_apple//apple:apple_xcframework.bzl", "apple_static_xcframework") load("@rules_apple//apple:macos.bzl", "macos_dylib") load("@rules_cc//cc:cc_library.bzl", "cc_library") load("//third_party/cpptoolchains/portable_llvm/build_defs:windows.bzl", "windows") @@ -51,16 +51,18 @@ cc_library( ":nc_types", "//connections:core", "//connections:core_types", + "//connections/implementation/analytics:analytics_recorder_impl", "//connections/implementation/flags:connections_flags", - "//internal/analytics:event_logger", "//internal/flags:flag_reader", "//internal/flags:nearby_flags", "//internal/platform:base", + "//internal/platform:comm", "//internal/platform:logging", "//internal/platform:mac_address", "//internal/platform:types", - "//internal/proto/analytics:connections_log_cc_proto", - "//sharing/proto/analytics:sharing_log_cc_proto", + "//location/nearby/analytics/cpp/logging:event_logger", + "//location/nearby/analytics/cpp/proto:connections_log_cc_proto", + "//location/nearby/analytics/cpp/proto:sharing_log_cc_proto", "@com_google_absl//absl/base:no_destructor", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", @@ -73,6 +75,7 @@ cc_library( ], "//conditions:default": [], }), + alwayslink = True, ) # iOS only. diff --git a/connections/c/nc.cc b/connections/c/nc.cc index e251f77c..2c975cb9 100644 --- a/connections/c/nc.cc +++ b/connections/c/nc.cc @@ -20,10 +20,16 @@ #include #include #include +#include #include #include #include +#if !defined(NC_OSS_BUILD) +#include "location/nearby/analytics/cpp/logging/event_logger.h" +#include "location/nearby/analytics/cpp/proto/connections_log.pb.h" +#include "location/nearby/analytics/cpp/proto/nearby_sharing_log.pb.h" +#endif // !defined(NC_OSS_BUILD) #include "absl/base/no_destructor.h" #include "absl/container/flat_hash_map.h" #include "absl/strings/str_cat.h" @@ -34,6 +40,9 @@ #include "connections/connection_options.h" #include "connections/core.h" #include "connections/discovery_options.h" +#if !defined(NC_OSS_BUILD) +#include "connections/implementation/analytics/analytics_recorder_impl.h" +#endif // !defined(NC_OSS_BUILD) #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/out_of_band_connection_metadata.h" @@ -41,7 +50,6 @@ #include "connections/payload.h" #include "connections/status.h" #include "connections/strategy.h" -#include "internal/analytics/event_logger.h" #include "internal/flags/flag.h" #include "internal/flags/flag_reader.h" #include "internal/flags/nearby_flags.h" @@ -49,8 +57,6 @@ #include "internal/platform/file.h" #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" -#include "internal/proto/analytics/connections_log.pb.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" #if TARGET_OS_IOS #include "internal/platform/implementation/apple/nearby_logger.h" #endif // TARGET_OS_IOS @@ -118,6 +124,7 @@ class FlagReaderWrapper : public nearby::flags::FlagReader { NC_PHENOTYPE_FLAG_READER phenotype_flag_reader_; }; +#if !defined(NC_OSS_BUILD) // This is a bridging class between the C API and the C++ EventLogger interface. class NcEventLogger : public ::nearby::analytics::EventLogger { public: @@ -145,6 +152,10 @@ class NcEventLogger : public ::nearby::analytics::EventLogger { private: const NC_EVENT_LOGGER* event_logger_; }; +#else // !defined(NC_OSS_BUILD) +class NcEventLogger; +#endif // !defined(NC_OSS_BUILD) + } // namespace typedef struct NcContext { @@ -244,6 +255,7 @@ NcContext* GetContext(NC_INSTANCE instance) { return cpp_connection_request_info; } +#if !defined(NC_OSS_BUILD) NC_INSTANCE NcCreateService() { return NcCreateServiceWithEventLogger(nullptr); } @@ -259,12 +271,24 @@ NcCreateServiceWithEventLogger(const NC_EVENT_LOGGER* event_logger) { nc_context.router = new ::nearby::connections::ServiceControllerRouter(); nc_context.event_logger = event_logger == nullptr ? nullptr : new NcEventLogger(event_logger); - nc_context.core = new ::nearby::connections::Core(nc_context.event_logger, - nc_context.router); + nc_context.core = new ::nearby::connections::Core( + std::make_unique<::nearby::analytics::AnalyticsRecorderImpl>( + nc_context.event_logger), + nc_context.router); kNcContextMap->insert({nc_context.core, nc_context}); return nc_context.core; } +#else // !defined(NC_OSS_BUILD) +NC_INSTANCE NcCreateService() { + NcContext nc_context; + nc_context.router = new ::nearby::connections::ServiceControllerRouter(); + nc_context.core = new ::nearby::connections::Core(nc_context.router); + + kNcContextMap->insert({nc_context.core, nc_context}); + return nc_context.core; +} +#endif // !defined(NC_OSS_BUILD) void NcCloseService(NC_INSTANCE instance) { NcContext* nc_context = GetContext(instance); diff --git a/connections/c/nc.h b/connections/c/nc.h index b3dd2505..cc00735f 100644 --- a/connections/c/nc.h +++ b/connections/c/nc.h @@ -27,11 +27,13 @@ extern "C" { // Creates a new Nearby Connections service. NC_API NC_INSTANCE NcCreateService(); +#if !defined(NC_OSS_BUILD) // Creates a new Nearby Connections service with an event logger. // The passed-in |event_logger| must remain valid until NcCloseService() is // called. NC_API NC_INSTANCE NcCreateServiceWithEventLogger(const NC_EVENT_LOGGER* event_logger); +#endif // !defined(NC_OSS_BUILD) // Closes a Nearby Connections service. NC_API void NcCloseService(NC_INSTANCE instance); diff --git a/connections/core.h b/connections/core.h index 69edb815..b72ebc6d 100644 --- a/connections/core.h +++ b/connections/core.h @@ -25,6 +25,7 @@ #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/service_controller_router.h" #include "connections/listeners.h" @@ -37,7 +38,6 @@ #include "connections/v3/discovery_options.h" #include "connections/v3/listeners.h" #include "connections/v3/listening_result.h" -#include "internal/analytics/event_logger.h" #include "internal/interop/device.h" #include "internal/interop/device_provider.h" @@ -49,9 +49,9 @@ class Core { public: explicit Core(ServiceControllerRouter* router); // Client needs to call this constructor if analytics logger is needed. - Core(::nearby::analytics::EventLogger* event_logger, + Core(std::unique_ptr analytics_recorder, ServiceControllerRouter* router) - : client_(event_logger), router_(router) {} + : client_(std::move(analytics_recorder)), router_(router) {} ~Core(); Core(Core&&); Core& operator=(Core&&); diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index ec42c3d2..334a3149 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -49,30 +49,143 @@ cc_library( ], ) +cc_library( + name = "service_id_constants", + hdrs = ["service_id_constants.h"], + visibility = ["//connections:__subpackages__"], + deps = [ + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:string_view", + ], +) + +cc_library( + name = "bwu_handler", + srcs = ["base_bwu_handler.cc"], + hdrs = [ + "base_bwu_handler.h", + "bwu_handler.h", + ], + visibility = ["//connections:__subpackages__"], + deps = [ + ":client_proxy", + ":endpoint_channel", + ":service_id_constants", + "//internal/platform:base", + "//internal/platform:logging", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:any_invocable", + ], +) + +cc_library( + name = "offline_frames", + srcs = [ + "offline_frames.cc", + "offline_frames_validator.cc", + ], + hdrs = [ + "internal_payload.h", + "offline_frames.h", + "offline_frames_validator.h", + ], + visibility = ["//connections:__subpackages__"], + deps = [ + "//connections:core_types", + "//connections/implementation/flags:connections_flags", + "//connections/implementation/proto:offline_wire_formats_cc_proto", + "//internal/flags:nearby_flags", + "//internal/platform:base", + "//internal/platform:logging", + "//internal/platform:mac_address", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "client_proxy", + srcs = ["client_proxy.cc"], + hdrs = ["client_proxy.h"], + visibility = ["//connections:__subpackages__"], + deps = [ + "//connections:core_types", + "//connections/implementation/analytics", + "//connections/implementation/flags:connections_flags", + "//connections/implementation/mediums/advertisements:dct_advertisement", + "//connections/implementation/proto:offline_wire_formats_cc_proto", + "//connections/v3:v3_types", + "//internal/base:file_path", + "//internal/base:files", + "//internal/flags:nearby_flags", + "//internal/interop:device", + "//internal/platform:base", + "//internal/platform:cancellation_flag", + "//internal/platform:error_code_recorder", + "//internal/platform:logging", + "//internal/platform:mac_address", + "//internal/platform:types", + "//internal/platform/implementation:comm", + "//internal/platform/implementation:platform", + "//internal/platform/implementation:types", + "//proto:connections_enums_cc_proto", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/random", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "endpoint_channel", + srcs = [ + "base_endpoint_channel.cc", + "endpoint_channel_manager.cc", + ], + hdrs = [ + "base_endpoint_channel.h", + "endpoint_channel.h", + "endpoint_channel_manager.h", + ], + visibility = ["//connections:__subpackages__"], + deps = [ + ":client_proxy", + ":offline_frames", + "//connections:core_types", + "//connections/implementation/analytics", + "//connections/implementation/flags:connections_flags", + "//internal/flags:nearby_flags", + "//internal/platform:base", + "//internal/platform:logging", + "//internal/platform:types", + "//internal/platform/implementation:types", + "//proto:connections_enums_cc_proto", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/time", + "@com_google_ukey2//:ukey2", + ], +) + cc_library( name = "internal", srcs = [ - "awdl_bwu_handler.cc", - "awdl_endpoint_channel.cc", - "base_bwu_handler.cc", - "base_endpoint_channel.cc", "base_pcp_handler.cc", - "ble_endpoint_channel.cc", - "ble_l2cap_endpoint_channel.cc", - "bluetooth_bwu_handler.cc", "bluetooth_device_name.cc", - "bluetooth_endpoint_channel.cc", "bwu_manager.cc", - "client_proxy.cc", "connections_authentication_transport.cc", "encryption_runner.cc", - "endpoint_channel_manager.cc", "endpoint_manager.cc", "injected_bluetooth_device_store.cc", "internal_payload.cc", "internal_payload_factory.cc", - "offline_frames.cc", - "offline_frames_validator.cc", "offline_service_controller.cc", "p2p_cluster_pcp_handler.cc", "p2p_point_to_point_pcp_handler.cc", @@ -80,41 +193,17 @@ cc_library( "payload_manager.cc", "pcp_manager.cc", "service_controller_router.cc", - "webrtc_bwu_handler.cc", - "webrtc_bwu_handler_stub.cc", - "webrtc_endpoint_channel.cc", - "wifi_direct_bwu_handler.cc", - "wifi_direct_endpoint_channel.cc", - "wifi_hotspot_bwu_handler.cc", - "wifi_hotspot_endpoint_channel.cc", - "wifi_lan_bwu_handler.cc", - "wifi_lan_endpoint_channel.cc", "wifi_lan_service_info.cc", ], hdrs = [ - "awdl_bwu_handler.h", - "awdl_endpoint_channel.h", - "base_bwu_handler.h", - "base_endpoint_channel.h", "base_pcp_handler.h", - "ble_endpoint_channel.h", - "ble_l2cap_endpoint_channel.h", - "bluetooth_bwu_handler.h", "bluetooth_device_name.h", - "bluetooth_endpoint_channel.h", - "bwu_handler.h", "bwu_manager.h", - "client_proxy.h", "connections_authentication_transport.h", "encryption_runner.h", - "endpoint_channel.h", - "endpoint_channel_manager.h", "endpoint_manager.h", "injected_bluetooth_device_store.h", - "internal_payload.h", "internal_payload_factory.h", - "offline_frames.h", - "offline_frames_validator.h", "offline_service_controller.h", "p2p_cluster_pcp_handler.h", "p2p_point_to_point_pcp_handler.h", @@ -124,49 +213,37 @@ cc_library( "pcp_manager.h", "service_controller.h", "service_controller_router.h", - "service_id_constants.h", - "webrtc_bwu_handler.h", - "webrtc_bwu_handler_stub.h", - "webrtc_endpoint_channel.h", - "wifi_direct_bwu_handler.h", - "wifi_direct_endpoint_channel.h", - "wifi_hotspot_bwu_handler.h", - "wifi_hotspot_endpoint_channel.h", - "wifi_lan_bwu_handler.h", - "wifi_lan_endpoint_channel.h", "wifi_lan_service_info.h", ], - copts = [ - "-DCORE_ADAPTER_DLL", - "-DNO_WEBRTC", - ], + copts = ["-DCORE_ADAPTER_DLL"], visibility = [ "//chrome/chromeos/assistant/data_migration/lib:__pkg__", "//connections:__pkg__", "//connections:partners", "//connections/implementation/fuzzers:__pkg__", - "//connections/implementation/mediums/multiplex:__pkg__", "//sharing:__subpackages__", ], deps = [ ":ble_advertisement", + ":bwu_handler", + ":client_proxy", + ":endpoint_channel", + ":offline_frames", + ":service_id_constants", ":types", "//connections:core_types", "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", "//connections/implementation/mediums", "//connections/implementation/mediums:utils", - "//connections/implementation/mediums:webrtc_utils", + "//connections/implementation/mediums:webrtc", + "//connections/implementation/mediums:webrtc_peer_id", "//connections/implementation/mediums/advertisements:dct_advertisement", "//connections/implementation/mediums/advertisements:util", "//connections/implementation/mediums/ble:ble_advertisement_header", "//connections/implementation/mediums/ble:ble_socket", "//connections/implementation/proto:offline_wire_formats_cc_proto", "//connections/v3:v3_types", - "//internal/analytics:event_logger", - "//internal/base:file_path", - "//internal/base:files", - "//internal/base:masker", "//internal/flags:nearby_flags", "//internal/interop:authentication_status", "//internal/interop:authentication_transport_interface", @@ -175,7 +252,6 @@ cc_library( "//internal/platform:cancellation_flag", "//internal/platform:comm", "//internal/platform:connection_info", - "//internal/platform:error_code_recorder", "//internal/platform:logging", "//internal/platform:mac_address", "//internal/platform:types", @@ -184,7 +260,6 @@ cc_library( "//internal/platform/implementation:platform", "//internal/platform/implementation:types", "//internal/platform/implementation:wifi_utils", - "//internal/proto/analytics:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:btree", @@ -192,7 +267,6 @@ cc_library( "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", - "@com_google_absl//absl/random", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", @@ -214,6 +288,7 @@ cc_library( "fake_bwu_handler.h", "fake_endpoint_channel.h", "mock_device.h", + "mock_endpoint_channel.h", "mock_service_controller.h", "mock_service_controller_router.h", "offline_simulation_user.h", @@ -223,7 +298,11 @@ cc_library( "//connections:__subpackages__", ], deps = [ + ":bwu_handler", + ":client_proxy", + ":endpoint_channel", ":internal", + ":offline_frames", "//connections:core_types", "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", @@ -247,30 +326,29 @@ cc_test( name = "bwu_test", srcs = [ "base_bwu_handler_test.cc", - "bluetooth_bwu_test.cc", "bwu_manager_test.cc", - "wifi_direct_bwu_test.cc", - "wifi_hotspot_bwu_test.cc", ], deps = [ + ":bwu_handler", + ":client_proxy", + ":endpoint_channel", ":internal", ":internal_test", + ":offline_frames", + ":service_id_constants", "//connections:core_types", + "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", "//connections/implementation/mediums", "//internal/flags:nearby_flags", "//internal/platform:base", - "//internal/platform:logging", - "//internal/platform:test_util", "//internal/platform:types", - "//internal/platform/flags:platform_flags", + "//internal/platform/implementation:platform", # build_cleaner: keep "//internal/platform/implementation/g3", # build_cleaner: keep - "//internal/proto/analytics:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", - "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) @@ -279,6 +357,7 @@ cc_test( name = "pcp_manager_test", srcs = ["pcp_manager_test.cc"], deps = [ + ":endpoint_channel", ":internal", ":internal_test", "//connections:core_types", @@ -304,17 +383,20 @@ cc_test( ], shard_count = 8, deps = [ + ":client_proxy", + ":endpoint_channel", ":internal", ":internal_test", + ":offline_frames", ":types", "//connections:core_types", "//connections/implementation/analytics", + "//connections/implementation/analytics:mock_analytics_recorder", "//connections/implementation/flags:connections_flags", "//connections/implementation/mediums", - "//connections/implementation/mediums:webrtc_utils", + "//connections/implementation/mediums:webrtc_peer_id", "//connections/implementation/proto:offline_wire_formats_cc_proto", "//connections/v3:v3_types", - "//internal/analytics:mock_event_logger", "//internal/flags:nearby_flags", "//internal/interop:authentication_status", "//internal/interop:authentication_transport_interface", @@ -325,7 +407,6 @@ cc_test( "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep - "//internal/proto/analytics:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/base:core_headers", @@ -362,7 +443,7 @@ cc_test( name = "offline_frames_test", srcs = ["offline_frames_validator_test.cc"], deps = [ - ":internal", + ":offline_frames", "//connections:core_types", "//connections/implementation/flags:connections_flags", "//connections/implementation/proto:offline_wire_formats_cc_proto", @@ -382,12 +463,11 @@ cc_test( "client_proxy_test.cc", ], deps = [ - ":internal", - "//base:casts", + ":client_proxy", "//connections:core_types", + "//connections/implementation/analytics:mock_analytics_recorder", "//connections/implementation/flags:connections_flags", "//connections/v3:v3_types", - "//internal/analytics:mock_event_logger", "//internal/flags:nearby_flags", "//internal/interop:device", "//internal/platform:base", @@ -411,6 +491,8 @@ cc_test( "encryption_runner_test.cc", ], deps = [ + ":client_proxy", + ":endpoint_channel", ":internal", "//connections/implementation/analytics", "//internal/platform:base", @@ -432,9 +514,12 @@ cc_test( "endpoint_manager_test.cc", ], deps = [ + ":client_proxy", + ":endpoint_channel", ":internal", + ":internal_test", + ":offline_frames", "//connections:core_types", - "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", "//internal/flags:nearby_flags", "//internal/platform:base", @@ -459,14 +544,17 @@ cc_test( "endpoint_channel_manager_test.cc", ], deps = [ + ":client_proxy", + ":endpoint_channel", ":internal", + ":offline_frames", + "//connections/implementation/analytics", "//connections/implementation/flags:connections_flags", "//internal/flags:nearby_flags", "//internal/platform:base", "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep - "//internal/proto/analytics:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/strings", @@ -484,13 +572,11 @@ cc_test( ], deps = [ ":internal", - "//connections/implementation/analytics", + ":internal_test", "//internal/platform:base", "//internal/platform/implementation/g3", # build_cleaner: keep - "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/strings:string_view", - "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) @@ -503,8 +589,8 @@ cc_test( deps = [ ":internal", ":internal_test", + ":offline_frames", "//connections:core_types", - "//connections/implementation/analytics", "//internal/platform:base", "//internal/platform:logging", "//internal/platform:test_util", @@ -525,6 +611,7 @@ cc_test( "service_controller_router_test.cc", ], deps = [ + ":client_proxy", ":internal", ":internal_test", "//connections:core_types", @@ -575,9 +662,11 @@ cc_test( ], deps = [ ":internal", + ":offline_frames", "//connections:core_types", "//connections/implementation/proto:offline_wire_formats_cc_proto", "//internal/platform:base", + "//internal/platform:comm", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", @@ -586,26 +675,3 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) - -cc_test( - name = "wifi_lan_bwu_handler_test", - srcs = [ - "wifi_lan_bwu_handler_test.cc", - ], - deps = [ - ":internal", - "//connections:core_types", - "//connections/implementation/mediums", - "//internal/analytics:mock_event_logger", - "//internal/platform:base", - "//internal/platform:mock_platform", - "//internal/platform:test_util", - "//internal/platform/implementation:comm", - "//internal/platform/implementation:platform", - "//internal/platform/implementation:platform_impl", - "//internal/proto/analytics:connections_log_cc_proto", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/strings:string_view", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/connections/implementation/analytics/BUILD b/connections/implementation/analytics/BUILD index 903272ff..d893305c 100644 --- a/connections/implementation/analytics/BUILD +++ b/connections/implementation/analytics/BUILD @@ -20,59 +20,92 @@ cc_library( name = "analytics", srcs = [ "analytics_recorder.cc", - "throughput_recorder.cc", ], hdrs = [ "advertising_metadata_params.h", "analytics_recorder.h", "connection_attempt_metadata_params.h", "discovery_metadata_params.h", - "packet_meta_data.h", - "throughput_recorder.h", + "operation_result_with_medium.h", ], copts = ["-DCORE_ADAPTER_DLL"], visibility = ["//connections:__subpackages__"], deps = [ "//connections:core_types", - "//internal/analytics:event_logger", + "//internal/platform:error_code_recorder", + "//proto:connections_enums_cc_proto", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "analytics_recorder_impl", + srcs = [ + "analytics_recorder_impl.cc", + ], + hdrs = [ + "analytics_recorder_impl.h", + ], + copts = ["-DCORE_ADAPTER_DLL"], + visibility = [ + "//connections/c:__pkg__", + "//sharing:__pkg__", + ], + deps = [ + ":analytics", + "//connections:core_types", "//internal/platform:error_code_recorder", "//internal/platform:logging", "//internal/platform:types", "//internal/platform/implementation:types", - "//internal/proto/analytics:connections_log_cc_proto", + "//location/nearby/analytics/cpp/logging:event_logger", + "//location/nearby/analytics/cpp/proto:connections_log_cc_proto", "//proto:connections_enums_cc_proto", "@com_google_absl//absl/algorithm:container", "@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/meta:type_traits", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/strings:string_view", "@com_google_absl//absl/time", "@com_google_protobuf//:protobuf_lite", ], ) +cc_library( + name = "mock_analytics_recorder", + testonly = True, + hdrs = [ + "mock_analytics_recorder.h", + ], + compatible_with = ["//buildenv/target:non_prod"], + visibility = ["//connections:__subpackages__"], + deps = [ + ":analytics", + "//connections:core_types", + "//internal/platform:error_code_recorder", + "//proto:connections_enums_cc_proto", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_for_library_testonly", + ], +) + cc_test( name = "analytics_test", size = "small", srcs = [ - "analytics_recorder_test.cc", - "throughput_recorder_test.cc", + "analytics_recorder_impl_test.cc", ], shard_count = 16, deps = [ ":analytics", + ":analytics_recorder_impl", "//connections:core_types", - "//internal/analytics:mock_event_logger", "//internal/platform:base", "//internal/platform:error_code_recorder", - "//internal/platform:logging", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep - "//internal/proto/analytics:connections_log_cc_proto", - "//internal/test", + "//location/nearby/analytics/cpp/logging:mock_event_logger", + "//location/nearby/analytics/cpp/proto:connections_log_cc_proto", "//net/proto2/contrib/parse_proto:parse_text_proto", "//proto:connections_enums_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", diff --git a/connections/implementation/analytics/advertising_metadata_params.h b/connections/implementation/analytics/advertising_metadata_params.h index 2b3b3372..2b40864b 100644 --- a/connections/implementation/analytics/advertising_metadata_params.h +++ b/connections/implementation/analytics/advertising_metadata_params.h @@ -17,7 +17,7 @@ #include -#include "internal/proto/analytics/connections_log.pb.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" namespace nearby { @@ -26,8 +26,7 @@ struct AdvertisingMetadataParams { bool is_extended_advertisement_supported = false; int connected_ap_frequency = 0; bool is_nfc_available = false; - std::vector + std::vector operation_result_with_mediums = {}; }; diff --git a/connections/implementation/analytics/analytics_recorder.cc b/connections/implementation/analytics/analytics_recorder.cc index f91edcef..67649104 100644 --- a/connections/implementation/analytics/analytics_recorder.cc +++ b/connections/implementation/analytics/analytics_recorder.cc @@ -14,921 +14,35 @@ #include "connections/implementation/analytics/analytics_recorder.h" -#include -#include -#include #include #include -#include #include -#include "absl/algorithm/container.h" -#include "absl/container/btree_map.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" #include "connections/implementation/analytics/advertising_metadata_params.h" #include "connections/implementation/analytics/connection_attempt_metadata_params.h" #include "connections/implementation/analytics/discovery_metadata_params.h" -#include "connections/payload_type.h" -#include "connections/strategy.h" -#include "internal/analytics/event_logger.h" -#include "internal/platform/error_code_params.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" -#include "internal/proto/analytics/connections_log.pb.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "proto/connections_enums.pb.h" -#include "google/protobuf/repeated_ptr_field.h" -namespace nearby { -namespace analytics { +namespace nearby::analytics { -namespace { -// const char kVersion_1_0_0[] = "v1.0.0"; -const char kVersion[] = "v1.5.0"; -constexpr absl::string_view kOnStartClientSession = "OnStartClientSession"; -const absl::Duration kConnectionTokenMaxLife = absl::Hours(24); - -using ::location::nearby::analytics::proto::ConnectionsLog; -using ::location::nearby::proto::connections::ACCEPTED; -using ::location::nearby::proto::connections::ADVERTISER; -using ::location::nearby::proto::connections::BandwidthUpgradeErrorStage; -using ::location::nearby::proto::connections::BandwidthUpgradeResult; -using ::location::nearby::proto::connections::BYTES; -using ::location::nearby::proto::connections::CLIENT_SESSION; -using ::location::nearby::proto::connections::CONNECTION_CLOSED; -using ::location::nearby::proto::connections::ConnectionAttemptDirection; -using ::location::nearby::proto::connections::ConnectionAttemptResult; -using ::location::nearby::proto::connections::ConnectionAttemptType; using ::location::nearby::proto::connections::ConnectionBand; -using ::location::nearby::proto::connections::ConnectionRequestResponse; -using ::location::nearby::proto::connections::ConnectionsStrategy; using ::location::nearby::proto::connections::ConnectionTechnology; -using ::location::nearby::proto::connections::DisconnectionReason; -using ::location::nearby::proto::connections::DISCOVERER; -using ::location::nearby::proto::connections::ERROR_CODE; -using ::location::nearby::proto::connections::EventType; -using ::location::nearby::proto::connections::FILE; -using ::location::nearby::proto::connections::IGNORED; -using ::location::nearby::proto::connections::INCOMING; -using ::location::nearby::proto::connections::INITIAL; using ::location::nearby::proto::connections::Medium; -using ::location::nearby::proto::connections::MOVED_TO_NEW_MEDIUM; -using ::location::nearby::proto::connections::NOT_SENT; -using ::location::nearby::proto::connections::OperationResultCategory; using ::location::nearby::proto::connections::OperationResultCode; -using ::location::nearby::proto::connections::OUTGOING; -using ::location::nearby::proto::connections::P2P_CLUSTER; -using ::location::nearby::proto::connections::P2P_POINT_TO_POINT; -using ::location::nearby::proto::connections::P2P_STAR; -using ::location::nearby::proto::connections::PayloadStatus; -using ::location::nearby::proto::connections::PayloadType; -using ::location::nearby::proto::connections::REJECTED; -using ::location::nearby::proto::connections::RESULT_SUCCESS; -using ::location::nearby::proto::connections::SessionRole; -using ::location::nearby::proto::connections::START_CLIENT_SESSION; -using ::location::nearby::proto::connections::START_STRATEGY_SESSION; -using ::location::nearby::proto::connections::STOP_CLIENT_SESSION; -using ::location::nearby::proto::connections::STOP_STRATEGY_SESSION; -using ::location::nearby::proto::connections::StopAdvertisingReason; -using ::location::nearby::proto::connections::StopDiscoveringReason; -using ::location::nearby::proto::connections::STREAM; -using ::location::nearby::proto::connections::UNFINISHED; -using ::location::nearby::proto::connections::UNFINISHED_ERROR; -using ::location::nearby::proto::connections::UNKNOWN_MEDIUM; -using ::location::nearby::proto::connections::UNKNOWN_PAYLOAD_TYPE; -using ::location::nearby::proto::connections::UNKNOWN_STRATEGY; -using ::location::nearby::proto::connections::UPGRADE_RESULT_SUCCESS; -using ::location::nearby::proto::connections::UPGRADE_SUCCESS; -using ::location::nearby::proto::connections::UPGRADE_UNFINISHED; -using ::location::nearby::proto::connections::UPGRADED; -using ::nearby::analytics::EventLogger; -using SafeDisconnectionResult = ::location::nearby::analytics::proto:: - ConnectionsLog::EstablishedConnection::SafeDisconnectionResult; - -OperationResultCategory ConvertToOperationResultCategory( - OperationResultCode result_code) { - if (result_code == OperationResultCode::DETAIL_SUCCESS) { - return OperationResultCategory::CATEGORY_SUCCESS; - } - // TODO(b/409865630): check later if we need to add back the dct error. - // Section of CATEGORY_DCT_ERROR, from 5000 to 5499 if (result_code - // >= OperationResultCode::DCT_ERROR_BLE_DISABLED) { - // return OperationResultCategory::CATEGORY_DCT_ERROR; - //} - - // Section of CATEGORY_NEARBY_ERROR, starting from 4500 to 4999 - if (result_code >= - OperationResultCode::NEARBY_BLE_ADVERTISEMENT_MAPPING_TO_MAC_ERROR) { - return OperationResultCategory::CATEGORY_NEARBY_ERROR; - } - // Section of CATEGORY_CONNECTIVITY_ERROR, starting from 3500 to 4499 - if (result_code >= - OperationResultCode::CONNECTIVITY_WIFI_AWARE_ATTACH_FAILURE) { - return OperationResultCategory::CATEGORY_CONNECTIVITY_ERROR; - } - // Section of CATEGORY_IO_ERROR, from 3000 to 3499 - if (result_code >= OperationResultCode::IO_FILE_OPENING_ERROR) { - return OperationResultCategory::CATEGORY_IO_ERROR; - } - // Section of CATEGORY_MISCELLANEOUS, from 2500 to 2999 - if (result_code >= - OperationResultCode::MISCELLEANEOUS_BLUETOOTH_MAC_ADDRESS_NULL) { - return OperationResultCategory::CATEGORY_MISCELLANEOUS; - } - // Section of CATEGORY_CLIENT_ERROR, from 2000 to 2499 - if (result_code >= - OperationResultCode:: - CLIENT_WIFI_DIRECT_ALREADY_HOSTING_DIRECT_GROUP_FOR_THIS_CLIENT) { - return OperationResultCategory::CATEGORY_CLIENT_ERROR; - } - // Section of CATEGORY_MEDIUM_UNAVAILABLE, from 1500 to 1999 - if (result_code >= OperationResultCode:: - MEDIUM_UNAVAILABLE_WIFI_AWARE_RESOURCE_NOT_AVAILABLE) { - return OperationResultCategory::CATEGORY_MEDIUM_UNAVAILABLE; - } - // Section of CATEGORY_DEVICE_STATE_ERROR, from 1000 to 1499 - if (result_code >= - OperationResultCode::DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS) { - return OperationResultCategory::CATEGORY_DEVICE_STATE_ERROR; - } - // Section of CATEGORY_CLIENT_CANCELLATION, from 500 to 999 - if (result_code >= - OperationResultCode::CLIENT_CANCELLATION_REMOTE_IN_CANCELED_STATE) { - return OperationResultCategory::CATEGORY_CLIENT_CANCELLATION; - } - // Clarify other non success cases as unknown - return OperationResultCategory::CATEGORY_UNKNOWN; -} -} // namespace - -AnalyticsRecorder::AnalyticsRecorder(EventLogger* event_logger) - : event_logger_(event_logger) { - VLOG(1) << "Start AnalyticsRecorder ctor event_logger_=" << event_logger_; - LogStartSession(); -} - -AnalyticsRecorder::~AnalyticsRecorder() = default; - -bool AnalyticsRecorder::IsSessionLogged() { - MutexLock lock(&mutex_); - return session_was_logged_; -} - -int AnalyticsRecorder::GetLatestUpdateIndexLocked( - const std::vector& list) { - int latest_update_index = 0; - for (const auto& operation_result_with_medium : list) { - if (operation_result_with_medium.update_index() > latest_update_index) { - latest_update_index = operation_result_with_medium.update_index(); - } - } - return latest_update_index; -} - -void AnalyticsRecorder::OnStartAdvertising( - connections::Strategy strategy, const std::vector& mediums, - AdvertisingMetadataParams* advertising_metadata_params) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnStartAdvertising")) { - return; - } - if (!strategy.IsValid()) { - LOG(INFO) << "AnalyticsRecorder OnStartAdvertising with unknown " - "strategy, bail out."; - return; - } - // Initialize/update a StrategySession. - UpdateStrategySessionLocked(strategy, ADVERTISER); - - // Initialize and set a AdvertisingPhase. - started_advertising_phase_time_ = SystemClock::ElapsedRealtime(); - current_advertising_phase_ = - std::make_unique(); - absl::c_copy(mediums, RepeatedFieldBackInserter( - current_advertising_phase_->mutable_medium())); - // Set a AdvertisingMetadata. - AdvertisingMetadataParams default_params = {}; - if (advertising_metadata_params == nullptr) { - advertising_metadata_params = &default_params; - } - if (!advertising_metadata_params->operation_result_with_mediums.empty()) { - absl::c_copy(advertising_metadata_params->operation_result_with_mediums, - RepeatedFieldBackInserter( - current_advertising_phase_->mutable_adv_dis_result())); - } - auto* advertising_metadata = - current_advertising_phase_->mutable_advertising_metadata(); - advertising_metadata->set_supports_extended_ble_advertisements( - advertising_metadata_params->is_extended_advertisement_supported); - advertising_metadata->set_connected_ap_frequency( - advertising_metadata_params->connected_ap_frequency); - advertising_metadata->set_supports_nfc_technology( - advertising_metadata_params->is_nfc_available); -} - -void AnalyticsRecorder::OnStopAdvertising() { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnStopAdvertising")) { - return; - } - RecordAdvertisingPhaseDurationAndReasonLocked(/* on_stop= */ true); -} - -int AnalyticsRecorder::GetNextAdvertisingUpdateIndex() { - MutexLock lock(&mutex_); - - if (current_advertising_phase_ == nullptr) { - return 0; - } - return GetLatestUpdateIndexLocked( - std::vector( - current_advertising_phase_->adv_dis_result().begin(), - current_advertising_phase_->adv_dis_result().end())) + - 1; -} - -void AnalyticsRecorder::OnStartDiscovery( - connections::Strategy strategy, const std::vector& mediums, - DiscoveryMetadataParams* discovery_metadata_params) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnStartDiscovery")) { - return; - } - if (!strategy.IsValid()) { - LOG(INFO) << "AnalyticsRecorder OnStartDiscovery unknown " - "strategy enter, bail out."; - return; - } - - // Initialize/update a StrategySession. - UpdateStrategySessionLocked(strategy, DISCOVERER); - - // Initialize and set a DiscoveryPhase. - started_discovery_phase_time_ = SystemClock::ElapsedRealtime(); - current_discovery_phase_ = std::make_unique(); - absl::c_copy(mediums, RepeatedFieldBackInserter( - current_discovery_phase_->mutable_medium())); - // Set a DiscoveryMetadata. - DiscoveryMetadataParams default_params = {}; - if (discovery_metadata_params == nullptr) { - discovery_metadata_params = &default_params; - } - if (!discovery_metadata_params->operation_result_with_mediums.empty()) { - absl::c_copy(discovery_metadata_params->operation_result_with_mediums, - RepeatedFieldBackInserter( - current_discovery_phase_->mutable_adv_dis_result())); - } - auto* discovery_metadata = - current_discovery_phase_->mutable_discovery_metadata(); - discovery_metadata->set_supports_extended_ble_advertisements( - discovery_metadata_params->is_extended_advertisement_supported); - discovery_metadata->set_connected_ap_frequency( - discovery_metadata_params->connected_ap_frequency); - discovery_metadata->set_supports_nfc_technology( - discovery_metadata_params->is_nfc_available); -} - -void AnalyticsRecorder::OnStopDiscovery() { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnStopDiscovery")) { - return; - } - RecordDiscoveryPhaseDurationAndReasonLocked(/*on_stop=*/true); -} - -int AnalyticsRecorder::GetNextDiscoveryUpdateIndex() { - MutexLock lock(&mutex_); - if (current_discovery_phase_ == nullptr) { - return 0; - } - return GetLatestUpdateIndexLocked( - std::vector( - current_discovery_phase_->adv_dis_result().begin(), - current_discovery_phase_->adv_dis_result().end())) + - 1; -} - -void AnalyticsRecorder::OnStartedIncomingConnectionListening( - connections::Strategy strategy) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnStartedIncomingConnectionListening")) { - return; - } - UpdateStrategySessionLocked(strategy, ADVERTISER); - if (started_advertising_phase_time_ == absl::InfinitePast()) { - started_advertising_phase_time_ = SystemClock::ElapsedRealtime(); - } -} - -void AnalyticsRecorder::OnStoppedIncomingConnectionListening() { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnStoppedIncomingConnectionListening")) { - return; - } - RecordAdvertisingPhaseDurationAndReasonLocked(/* on_stop= */ false); -} - -void AnalyticsRecorder::OnEndpointFound(Medium medium) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnEndpointFound")) { - return; - } - if (current_discovery_phase_ == nullptr) { - LOG(INFO) << "Unable to record discovered endpoint due to null " - "current_discovery_phase_"; - return; - } - ConnectionsLog::DiscoveredEndpoint* discovered_endpoint = - current_discovery_phase_->add_discovered_endpoint(); - discovered_endpoint->set_medium(medium); - discovered_endpoint->set_latency_millis(absl::ToInt64Milliseconds( - SystemClock::ElapsedRealtime() - started_discovery_phase_time_)); -} - -void AnalyticsRecorder::OnRequestConnection( - const connections::Strategy& strategy, const std::string& endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("onRequestConnection")) { - return; - } - - UpdateStrategySessionLocked(strategy, DISCOVERER); - if (started_discovery_phase_time_ == absl::InfinitePast()) { - started_discovery_phase_time_ = SystemClock::ElapsedRealtime(); - } -} - -void AnalyticsRecorder::OnConnectionRequestReceived( - const std::string& remote_endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnConnectionRequestReceived")) { - return; - } - absl::Time current_time = SystemClock::ElapsedRealtime(); - auto connection_request = - std::make_unique(); - connection_request->set_duration_millis(absl::ToUnixMillis(current_time)); - connection_request->set_request_delay_millis(absl::ToInt64Milliseconds( - current_time - started_advertising_phase_time_)); - incoming_connection_requests_.insert( - {remote_endpoint_id, std::move(connection_request)}); -} - -void AnalyticsRecorder::OnConnectionRequestSent( - const std::string& remote_endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnConnectionRequestSent")) { - return; - } - absl::Time current_time = SystemClock::ElapsedRealtime(); - auto connection_request = - std::make_unique(); - connection_request->set_duration_millis(absl::ToUnixMillis(current_time)); - connection_request->set_request_delay_millis( - absl::ToInt64Milliseconds(current_time - started_discovery_phase_time_)); - outgoing_connection_requests_.insert( - {remote_endpoint_id, std::move(connection_request)}); -} - -void AnalyticsRecorder::OnRemoteEndpointAccepted( - const std::string& remote_endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnRemoteEndpointAccepted")) { - return; - } - RemoteEndpointRespondedLocked(remote_endpoint_id, ACCEPTED); -} - -void AnalyticsRecorder::OnLocalEndpointAccepted( - const std::string& remote_endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnLocalEndpointAccepted")) { - return; - } - LocalEndpointRespondedLocked(remote_endpoint_id, ACCEPTED); -} - -void AnalyticsRecorder::OnRemoteEndpointRejected( - const std::string& remote_endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnRemoteEndpointRejected")) { - return; - } - RemoteEndpointRespondedLocked(remote_endpoint_id, REJECTED); -} - -void AnalyticsRecorder::OnLocalEndpointRejected( - const std::string& remote_endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnLocalEndpointRejected")) { - return; - } - LocalEndpointRespondedLocked(remote_endpoint_id, REJECTED); -} - -void AnalyticsRecorder::OnIncomingConnectionAttempt( - ConnectionAttemptType type, Medium medium, ConnectionAttemptResult result, - absl::Duration duration, const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnIncomingConnectionAttempt")) { - return; - } - if (current_strategy_session_ == nullptr) { - LOG(INFO) << "Unable to record incoming connection attempt due to " - "null current_strategy_session_"; - return; - } - - ConnectionAttemptMetadataParams default_params = {}; - if (connection_attempt_metadata_params == nullptr) { - connection_attempt_metadata_params = &default_params; - } - OnIncomingConnectionAttemptLocked(type, medium, result, duration, - connection_token, - connection_attempt_metadata_params); -} - -void AnalyticsRecorder::OnIncomingConnectionAttemptLocked( - location::nearby::proto::connections::ConnectionAttemptType type, - location::nearby::proto::connections::Medium medium, - location::nearby::proto::connections::ConnectionAttemptResult result, - absl::Duration duration, const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) { - auto* connection_attempt = - current_strategy_session_->add_connection_attempt(); - connection_attempt->set_duration_millis(absl::ToInt64Milliseconds(duration)); - connection_attempt->set_type(type); - connection_attempt->set_direction(INCOMING); - connection_attempt->set_medium(medium); - connection_attempt->set_attempt_result(result); - connection_attempt->set_connection_token(connection_token); - - auto* connection_attempt_metadata = - connection_attempt->mutable_connection_attempt_metadata(); - connection_attempt_metadata->set_technology( - connection_attempt_metadata_params->technology); - connection_attempt_metadata->set_band( - connection_attempt_metadata_params->band); - connection_attempt_metadata->set_frequency( - connection_attempt_metadata_params->frequency); - connection_attempt_metadata->set_network_operator( - connection_attempt_metadata_params->network_operator); - connection_attempt_metadata->set_country_code( - connection_attempt_metadata_params->country_code); - connection_attempt_metadata->set_frequency( - connection_attempt_metadata_params->frequency); - connection_attempt_metadata->set_is_tdls_used( - connection_attempt_metadata_params->is_tdls_used); - connection_attempt_metadata->set_wifi_hotspot_status( - connection_attempt_metadata_params->wifi_hotspot_enabled); - connection_attempt_metadata->set_try_counts( - connection_attempt_metadata_params->try_count); - connection_attempt_metadata->set_max_tx_speed( - connection_attempt_metadata_params->max_wifi_tx_speed); - connection_attempt_metadata->set_max_rx_speed( - connection_attempt_metadata_params->max_wifi_rx_speed); - connection_attempt_metadata->set_wifi_channel_width( - connection_attempt_metadata_params->channel_width); - - auto operation_result_proto = - std::make_unique(); - operation_result_proto->set_result_code( - connection_attempt_metadata_params->operation_result_code); - operation_result_proto->set_result_category(ConvertToOperationResultCategory( - connection_attempt_metadata_params->operation_result_code)); - connection_attempt->set_allocated_operation_result( - operation_result_proto.release()); -} - -void AnalyticsRecorder::OnOutgoingConnectionAttempt( - const std::string& remote_endpoint_id, ConnectionAttemptType type, - Medium medium, ConnectionAttemptResult result, absl::Duration duration, - const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnOutgoingConnectionAttempt")) { - return; - } - if (current_strategy_session_ == nullptr) { - LOG(INFO) << "Unable to record outgoing connection attempt due to " - "null current_strategy_session_"; - return; - } - - ConnectionAttemptMetadataParams default_params = {}; - if (connection_attempt_metadata_params == nullptr) { - connection_attempt_metadata_params = &default_params; - } - - // For the case of transfer a big file and the upgrades always failure, then - // there will have repeating upgrade attempt and cause many same attempt value - // be log. So add a method to skip. - if (ConnectionAttemptResultCodeExistedLocked( - medium, OUTGOING, connection_token, type, - connection_attempt_metadata_params->operation_result_code)) { - return; - } - - OnOutgoingConnectionAttemptLocked(remote_endpoint_id, type, medium, result, - duration, connection_token, - connection_attempt_metadata_params); -} - -void AnalyticsRecorder::OnOutgoingConnectionAttemptLocked( - const std::string& remote_endpoint_id, ConnectionAttemptType type, - Medium medium, ConnectionAttemptResult result, absl::Duration duration, - const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) { - auto* connection_attempt = - current_strategy_session_->add_connection_attempt(); - connection_attempt->set_duration_millis(absl::ToInt64Milliseconds(duration)); - connection_attempt->set_type(type); - connection_attempt->set_direction(OUTGOING); - connection_attempt->set_medium(medium); - connection_attempt->set_attempt_result(result); - connection_attempt->set_connection_token(connection_token); - - auto* connection_attempt_metadata = - connection_attempt->mutable_connection_attempt_metadata(); - connection_attempt_metadata->set_technology( - connection_attempt_metadata_params->technology); - connection_attempt_metadata->set_band( - connection_attempt_metadata_params->band); - connection_attempt_metadata->set_frequency( - connection_attempt_metadata_params->frequency); - connection_attempt_metadata->set_network_operator( - connection_attempt_metadata_params->network_operator); - connection_attempt_metadata->set_country_code( - connection_attempt_metadata_params->country_code); - connection_attempt_metadata->set_frequency( - connection_attempt_metadata_params->frequency); - connection_attempt_metadata->set_is_tdls_used( - connection_attempt_metadata_params->is_tdls_used); - connection_attempt_metadata->set_wifi_hotspot_status( - connection_attempt_metadata_params->wifi_hotspot_enabled); - connection_attempt_metadata->set_try_counts( - connection_attempt_metadata_params->try_count); - connection_attempt_metadata->set_max_tx_speed( - connection_attempt_metadata_params->max_wifi_tx_speed); - connection_attempt_metadata->set_max_rx_speed( - connection_attempt_metadata_params->max_wifi_rx_speed); - connection_attempt_metadata->set_wifi_channel_width( - connection_attempt_metadata_params->channel_width); - - auto operation_result_proto = - std::make_unique(); - operation_result_proto->set_result_code( - connection_attempt_metadata_params->operation_result_code); - operation_result_proto->set_result_category(ConvertToOperationResultCategory( - connection_attempt_metadata_params->operation_result_code)); - connection_attempt->set_allocated_operation_result( - operation_result_proto.release()); - - if (type == INITIAL && result != RESULT_SUCCESS) { - auto it = outgoing_connection_requests_.find(remote_endpoint_id); - if (it != outgoing_connection_requests_.end()) { - // An outgoing, initial ConnectionAttempt has a corresponding - // ConnectionRequest that, since the ConnectionAttempt has failed, will - // never be delivered to the advertiser. - auto pair = outgoing_connection_requests_.extract(it); - std::unique_ptr& connection_request = - pair.mapped(); - connection_request->set_local_response(NOT_SENT); - connection_request->set_remote_response(NOT_SENT); - UpdateDiscovererConnectionRequestLocked(connection_request.get()); - } - } -} - -void AnalyticsRecorder::OnConnectionEstablished( - const std::string& endpoint_id, Medium medium, - const std::string& connection_token) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnConnectionEstablished")) { - return; - } - auto it = active_connections_.find(endpoint_id); - if (it != active_connections_.end()) { - const std::unique_ptr& logical_connection = it->second; - logical_connection->PhysicalConnectionEstablished(medium, connection_token); - } else { - active_connections_.insert( - {endpoint_id, - std::make_unique(medium, connection_token)}); - } -} - -void AnalyticsRecorder::OnConnectionClosed(const std::string& endpoint_id, - Medium medium, - DisconnectionReason reason, - SafeDisconnectionResult result) { - MutexLock lock(&mutex_); - LOG(INFO) << __func__ - << ": OnConnectionClosed is called with endpoint_id:" << endpoint_id - << ", medium:" << Medium_Name(medium) - << ", reason:" << DisconnectionReason_Name(reason) - << ", result:" << result; - - if (!CanRecordAnalyticsLocked("OnConnectionClosed")) { - return; - } - - if (current_strategy_session_ == nullptr) { - VLOG(1) << "AnalyticsRecorder CanRecordAnalytics Unexpected call " - << __func__ << " since current_strategy_session_ is required."; - return; - } - - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - return; - } - const std::unique_ptr& logical_connection = it->second; - logical_connection->PhysicalConnectionClosed(medium, reason, result); - if (reason != UPGRADED) { - // Unless this is an upgraded connection, remove this from our active - // connections. Any future communication with an endpoint will need to be - // re-established with a new ConnectionRequest. - auto pair = active_connections_.extract(it); - std::unique_ptr& logical_connection = pair.mapped(); - - absl::c_copy( - logical_connection->GetEstablisedConnections(), - RepeatedFieldBackInserter( - current_strategy_session_->mutable_established_connection())); - } -} - -void AnalyticsRecorder::OnIncomingPayloadStarted( - const std::string& endpoint_id, std::int64_t payload_id, - connections::PayloadType type, std::int64_t total_size_bytes) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnIncomingPayloadStarted")) { - return; - } - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - return; - } - const std::unique_ptr& logical_connection = it->second; - logical_connection->IncomingPayloadStarted( - payload_id, PayloadTypeToProtoPayloadType(type), total_size_bytes); -} - -void AnalyticsRecorder::OnPayloadChunkReceived(const std::string& endpoint_id, - std::int64_t payload_id, - std::int64_t chunk_size_bytes) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnPayloadChunkReceived")) { - return; - } - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - return; - } - const std::unique_ptr& logical_connection = it->second; - logical_connection->ChunkReceived(payload_id, chunk_size_bytes); -} - -void AnalyticsRecorder::OnIncomingPayloadDone( - const std::string& endpoint_id, std::int64_t payload_id, - PayloadStatus status, OperationResultCode operation_result_code) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnIncomingPayloadDone")) { - return; - } - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - return; - } - const std::unique_ptr& logical_connection = it->second; - logical_connection->IncomingPayloadDone(payload_id, status, - operation_result_code); -} - -void AnalyticsRecorder::OnOutgoingPayloadStarted( - const std::vector& endpoint_ids, std::int64_t payload_id, - connections::PayloadType type, std::int64_t total_size_bytes) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnOutgoingPayloadStarted")) { - return; - } - for (const auto& endpoint_id : endpoint_ids) { - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - continue; - } - const std::unique_ptr& logical_connection = it->second; - logical_connection->OutgoingPayloadStarted( - payload_id, PayloadTypeToProtoPayloadType(type), total_size_bytes); - } -} - -void AnalyticsRecorder::OnPayloadChunkSent(const std::string& endpoint_id, - std::int64_t payload_id, - std::int64_t chunk_size_bytes) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnPayloadChunkSent")) { - return; - } - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - return; - } - const std::unique_ptr& logical_connection = it->second; - logical_connection->ChunkSent(payload_id, chunk_size_bytes); -} - -void AnalyticsRecorder::OnOutgoingPayloadDone( - const std::string& endpoint_id, std::int64_t payload_id, - PayloadStatus status, OperationResultCode operation_result_code) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnOutgoingPayloadDone")) { - return; - } - auto it = active_connections_.find(endpoint_id); - if (it == active_connections_.end()) { - return; - } - - const std::unique_ptr& logical_connection = it->second; - logical_connection->OutgoingPayloadDone(payload_id, status, - operation_result_code); -} - -void AnalyticsRecorder::OnBandwidthUpgradeStarted( - const std::string& endpoint_id, Medium from_medium, Medium to_medium, - ConnectionAttemptDirection direction, const std::string& connection_token) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnBandwidthUpgradeStarted")) { - return; - } - auto bandwidth_upgrade_attempt = - std::make_unique(); - bandwidth_upgrade_attempt->set_duration_millis( - absl::ToUnixMillis(SystemClock::ElapsedRealtime())); - bandwidth_upgrade_attempt->set_from_medium(from_medium); - bandwidth_upgrade_attempt->set_to_medium(to_medium); - bandwidth_upgrade_attempt->set_direction(direction); - bandwidth_upgrade_attempt->set_connection_token(connection_token); - bandwidth_upgrade_attempts_.insert( - {endpoint_id, std::move(bandwidth_upgrade_attempt)}); -} - -void AnalyticsRecorder::UpdateBwUpgradeNetworkInfo( - const std::string& endpoint_id, int num_interfaces, - int num_ipv6_only_interfaces) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("UpdateBwUpgradeNetworkInfo")) { - return; - } - auto it = bandwidth_upgrade_attempts_.find(endpoint_id); - if (it == bandwidth_upgrade_attempts_.end()) { - return; - } - ConnectionsLog::BandwidthUpgradeAttempt* bandwidth_upgrade_attempt = - it->second.get(); - bandwidth_upgrade_attempt->set_num_interfaces(num_interfaces); - bandwidth_upgrade_attempt->set_num_ipv6_only_interfaces( - num_ipv6_only_interfaces); -} - -void AnalyticsRecorder::OnBandwidthUpgradeError( - const std::string& endpoint_id, BandwidthUpgradeResult result, - BandwidthUpgradeErrorStage error_stage, - OperationResultCode operation_result_code) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnBandwidthUpgradeError")) { - return; - } - // If the same records existed, drop this one. - if (EraseIfBandwidthUpgradeRecordExistedLocked( - endpoint_id, result, error_stage, operation_result_code)) { - return; - } - FinishUpgradeAttemptLocked(endpoint_id, result, error_stage, - operation_result_code); -} - -void AnalyticsRecorder::OnBandwidthUpgradeSuccess( - const std::string& endpoint_id) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnBandwidthUpgradeSuccess")) { - return; - } - FinishUpgradeAttemptLocked(endpoint_id, UPGRADE_RESULT_SUCCESS, - UPGRADE_SUCCESS, - OperationResultCode::DETAIL_SUCCESS); -} - -void AnalyticsRecorder::OnErrorCode(const ErrorCodeParams& params) { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("OnErrorCode")) { - return; - } - auto error_code = std::make_unique(); - error_code->set_medium(params.medium); - error_code->set_event(params.event); - error_code->set_connection_token(params.connection_token); - error_code->set_description(params.description); - - if (params.is_common_error) { - error_code->set_common_error(params.common_error); - } else { - switch (params.event) { - case location::nearby::errorcode::proto::START_ADVERTISING: - error_code->set_start_advertising_error(params.start_advertising_error); - break; - case location::nearby::errorcode::proto::STOP_ADVERTISING: - error_code->set_stop_advertising_error(params.stop_advertising_error); - break; - case location::nearby::errorcode::proto:: - START_LISTENING_INCOMING_CONNECTION: - error_code->set_start_listening_incoming_connection_error( - params.start_listening_incoming_connection_error); - break; - case location::nearby::errorcode::proto:: - STOP_LISTENING_INCOMING_CONNECTION: - error_code->set_stop_listening_incoming_connection_error( - params.stop_listening_incoming_connection_error); - break; - case location::nearby::errorcode::proto::START_DISCOVERING: - error_code->set_start_discovering_error(params.start_discovering_error); - break; - case location::nearby::errorcode::proto::STOP_DISCOVERING: - error_code->set_stop_discovering_error(params.stop_discovering_error); - break; - case location::nearby::errorcode::proto::CONNECT: - error_code->set_connect_error(params.connect_error); - break; - case location::nearby::errorcode::proto::DISCONNECT: - error_code->set_disconnect_error(params.disconnect_error); - break; - case location::nearby::errorcode::proto::UNKNOWN_EVENT: - default: - error_code->set_common_error(params.common_error); - break; - } - } - - ConnectionsLog connections_log; - connections_log.set_event_type(ERROR_CODE); - connections_log.set_version(kVersion); - connections_log.set_allocated_error_code(error_code.release()); - - VLOG(1) << "AnalyticsRecorder LogErrorCode connections_log=" - << connections_log.DebugString(); // NOLINT - - event_logger_->Log(connections_log); -} - -void AnalyticsRecorder::LogStartSession() { - MutexLock lock(&mutex_); - if (start_client_session_was_logged_) { - LOG(WARNING) << "AnalyticsRecorder CanRecordAnalytics Unexpected call " - << kOnStartClientSession - << " after start client session has already been logged."; - return; - } - - session_was_logged_ = false; - if (CanRecordAnalyticsLocked(kOnStartClientSession)) { - client_session_ = std::make_unique(); - started_client_session_time_ = SystemClock::ElapsedRealtime(); - start_client_session_was_logged_ = true; - LogEvent(START_CLIENT_SESSION); - } -} - -void AnalyticsRecorder::LogSession() { - MutexLock lock(&mutex_); - if (!CanRecordAnalyticsLocked("LogSession")) { - return; - } - FinishStrategySessionLocked(); - client_session_->set_duration_millis(absl::ToInt64Milliseconds( - SystemClock::ElapsedRealtime() - started_client_session_time_)); - LogClientSessionLocked(); - LogEvent(STOP_CLIENT_SESSION); - start_client_session_was_logged_ = false; - session_was_logged_ = true; -} std::unique_ptr AnalyticsRecorder::BuildAdvertisingMetadataParams( bool is_extended_advertisement_supported, int connected_ap_frequency, bool is_nfc_available, - const std::vector& + const std::vector& operation_result_with_mediums) { auto params = std::make_unique(); params->is_extended_advertisement_supported = is_extended_advertisement_supported; params->connected_ap_frequency = connected_ap_frequency; params->is_nfc_available = is_nfc_available; - params->operation_result_with_mediums = - std::move(operation_result_with_mediums); + params->operation_result_with_mediums = operation_result_with_mediums; return params; } @@ -936,15 +50,14 @@ std::unique_ptr AnalyticsRecorder::BuildDiscoveryMetadataParams( bool is_extended_advertisement_supported, int connected_ap_frequency, bool is_nfc_available, - const std::vector& + const std::vector& operation_result_with_mediums) { auto params = std::make_unique(); params->is_extended_advertisement_supported = is_extended_advertisement_supported; params->connected_ap_frequency = connected_ap_frequency; params->is_nfc_available = is_nfc_available; - params->operation_result_with_mediums = - std::move(operation_result_with_mediums); + params->operation_result_with_mediums = operation_result_with_mediums; return params; } @@ -1000,694 +113,4 @@ OperationResultCode AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium( } } -bool AnalyticsRecorder::CanRecordAnalyticsLocked( - absl::string_view method_name) { - VLOG(1) << "AnalyticsRecorder LogEvent " << method_name << " is calling."; - if (event_logger_ == nullptr) { - return false; - } - - if (session_was_logged_) { - VLOG(1) << "AnalyticsRecorder CanRecordAnalytics Unexpected call " - << method_name << " after session has already been logged."; - return false; - } - - return true; -} - -// TODO: b/391339677 - Investigate why we need to reset the resources. And -// verify in b/238375695 to see if we still meet the issue after removing the -// Reset function. -void AnalyticsRecorder::LogClientSessionLocked() { - ConnectionsLog connections_log; - connections_log.set_event_type(CLIENT_SESSION); - connections_log.set_allocated_client_session(client_session_.release()); - connections_log.set_version(kVersion); - - VLOG(1) << "AnalyticsRecorder LogClientSession connections_log=" - << connections_log.DebugString(); // NOLINT - - event_logger_->Log(connections_log); - client_session_ = nullptr; -} - -void AnalyticsRecorder::LogEvent(EventType event_type) { - ConnectionsLog connections_log; - connections_log.set_event_type(event_type); - connections_log.set_version(kVersion); - - VLOG(1) << "AnalyticsRecorder LogEvent connections_log=" - << connections_log.DebugString(); // NOLINT - - event_logger_->Log(connections_log); -} - -void AnalyticsRecorder::UpdateStrategySessionLocked( - connections::Strategy strategy, SessionRole role) { - // If we're not switching strategies, just update the current StrategySession - // with the new role. - if (strategy == current_strategy_ && current_strategy_session_ != nullptr) { - if (absl::c_linear_search(current_strategy_session_->role(), role)) { - // We've already acted as this role before, so make sure we've finished - // recording the previous round. - switch (role) { - case ADVERTISER: - FinishAdvertisingPhaseLocked(); - break; - case DISCOVERER: - FinishDiscoveryPhaseLocked(); - break; - default: - break; - } - } else { - current_strategy_session_->add_role(role); - } - } else { - // Otherwise, we're starting a new Strategy. - current_strategy_ = strategy; - FinishStrategySessionLocked(); - LogEvent(START_STRATEGY_SESSION); - current_strategy_session_ = - std::make_unique(); - started_strategy_session_time_ = SystemClock::ElapsedRealtime(); - current_strategy_session_->set_strategy( - StrategyToConnectionStrategy(strategy)); - current_strategy_session_->add_role(role); - } -} - -void AnalyticsRecorder::RecordAdvertisingPhaseDurationAndReasonLocked( - bool on_stop) const { - if (current_advertising_phase_ == nullptr) { - LOG(INFO) << "Unable to record advertising phase duration due to " - "null current_advertising_phase_"; - return; - } - if (!current_advertising_phase_->has_duration_millis()) { - current_advertising_phase_->set_duration_millis(absl::ToInt64Milliseconds( - SystemClock::ElapsedRealtime() - started_advertising_phase_time_)); - } - if (!current_advertising_phase_->has_stop_reason()) { - current_advertising_phase_->set_stop_reason( - on_stop ? StopAdvertisingReason::CLIENT_STOP_ADVERTISING - : StopAdvertisingReason::FINISH_SESSION_STOP_ADVERTISING); - } -} - -void AnalyticsRecorder::FinishAdvertisingPhaseLocked() { - if (current_advertising_phase_ != nullptr) { - for (const auto& item : incoming_connection_requests_) { - // ConnectionRequests still pending have been ignored by the local or - // remote (or both) endpoints. - const std::unique_ptr& - connection_request = item.second; - MarkConnectionRequestIgnoredLocked(connection_request.get()); - UpdateAdvertiserConnectionRequestLocked(connection_request.get()); - } - RecordAdvertisingPhaseDurationAndReasonLocked(/* on_stop= */ false); - if (current_strategy_session_ != nullptr) { - *current_strategy_session_->add_advertising_phase() = - *std::move(current_advertising_phase_); - } else { - LOG(INFO) << "Unable to record advertising phase due to null " - "current_strategy_session_"; - } - } - incoming_connection_requests_.clear(); -} - -void AnalyticsRecorder::RecordDiscoveryPhaseDurationAndReasonLocked( - bool on_stop) const { - if (current_discovery_phase_ == nullptr) { - LOG(INFO) << "Unable to record discovery phase duration due to " - "null current_discovery_phase_"; - return; - } - if (!current_discovery_phase_->has_duration_millis()) { - current_discovery_phase_->set_duration_millis(absl::ToInt64Milliseconds( - SystemClock::ElapsedRealtime() - started_discovery_phase_time_)); - } - // If the stop reason haven't been set yet, then set it. - if (!current_discovery_phase_->has_stop_reason()) { - current_discovery_phase_->set_stop_reason( - on_stop ? StopDiscoveringReason::CLIENT_STOP_DISCOVERING - : StopDiscoveringReason::FINISH_SESSION_STOP_DISCOVERING); - } -} - -void AnalyticsRecorder::FinishDiscoveryPhaseLocked() { - if (current_discovery_phase_ != nullptr) { - for (const auto& item : outgoing_connection_requests_) { - // ConnectionRequests still pending have been ignored by the local or - // remote (or both) endpoints. - const std::unique_ptr& - connection_request = item.second; - MarkConnectionRequestIgnoredLocked(connection_request.get()); - UpdateDiscovererConnectionRequestLocked(connection_request.get()); - } - RecordDiscoveryPhaseDurationAndReasonLocked(/* on_stop=*/false); - if (current_strategy_session_ != nullptr) { - *current_strategy_session_->add_discovery_phase() = - *std::move(current_discovery_phase_); - } else { - LOG(INFO) << "Unable to record discovery phase due to null " - "current_strategy_session_"; - } - } - outgoing_connection_requests_.clear(); -} - -bool AnalyticsRecorder::UpdateAdvertiserConnectionRequestLocked( - ConnectionsLog::ConnectionRequest* request) { - if (current_advertising_phase_ == nullptr) { - LOG(INFO) << "Unable to record advertiser connection request due to null " - "current_advertising_phase_"; - return false; - } - if (BothEndpointsRespondedLocked(request)) { - request->set_duration_millis( - absl::ToUnixMillis(SystemClock::ElapsedRealtime()) - - request->duration_millis()); - *current_advertising_phase_->add_received_connection_request() = *request; - return true; - } - return false; -} - -bool AnalyticsRecorder::UpdateDiscovererConnectionRequestLocked( - ConnectionsLog::ConnectionRequest* request) { - if (current_discovery_phase_ == nullptr) { - LOG(INFO) << "Unable to record discoverer connection request due " - "to null current_discovery_phase_."; - return false; - } - if (BothEndpointsRespondedLocked(request) || - request->local_response() == NOT_SENT) { - request->set_duration_millis( - absl::ToUnixMillis(SystemClock::ElapsedRealtime()) - - request->duration_millis()); - *current_discovery_phase_->add_sent_connection_request() = *request; - return true; - } - return false; -} - -bool AnalyticsRecorder::BothEndpointsRespondedLocked( - ConnectionsLog::ConnectionRequest* request) { - return request->has_local_response() && request->has_remote_response(); -} - -void AnalyticsRecorder::LocalEndpointRespondedLocked( - const std::string& remote_endpoint_id, ConnectionRequestResponse response) { - auto out = outgoing_connection_requests_.find(remote_endpoint_id); - if (out != outgoing_connection_requests_.end()) { - ConnectionsLog::ConnectionRequest* connection_request = out->second.get(); - connection_request->set_local_response(response); - if (UpdateDiscovererConnectionRequestLocked(connection_request)) { - outgoing_connection_requests_.erase(out); - } - } - auto in = incoming_connection_requests_.find(remote_endpoint_id); - if (in != incoming_connection_requests_.end()) { - ConnectionsLog::ConnectionRequest* connection_request = in->second.get(); - connection_request->set_local_response(response); - if (UpdateAdvertiserConnectionRequestLocked(connection_request)) { - incoming_connection_requests_.erase(in); - } - } -} - -void AnalyticsRecorder::RemoteEndpointRespondedLocked( - const std::string& remote_endpoint_id, ConnectionRequestResponse response) { - auto out = outgoing_connection_requests_.find(remote_endpoint_id); - if (out != outgoing_connection_requests_.end()) { - ConnectionsLog::ConnectionRequest* connection_request = out->second.get(); - connection_request->set_remote_response(response); - if (UpdateDiscovererConnectionRequestLocked(connection_request)) { - outgoing_connection_requests_.erase(out); - } - } - auto in = incoming_connection_requests_.find(remote_endpoint_id); - if (in != incoming_connection_requests_.end()) { - ConnectionsLog::ConnectionRequest* connection_request = in->second.get(); - connection_request->set_remote_response(response); - if (UpdateAdvertiserConnectionRequestLocked(connection_request)) { - incoming_connection_requests_.erase(in); - } - } -} - -void AnalyticsRecorder::MarkConnectionRequestIgnoredLocked( - ConnectionsLog::ConnectionRequest* request) { - if (!request->has_local_response()) { - request->set_local_response(IGNORED); - } - if (!request->has_remote_response()) { - request->set_remote_response(IGNORED); - } -} - -bool AnalyticsRecorder::ConnectionAttemptResultCodeExistedLocked( - Medium medium, ConnectionAttemptDirection direction, - const std::string& connection_token, ConnectionAttemptType type, - OperationResultCode operation_result_code) { - if (current_strategy_session_ == nullptr || - current_strategy_session_->connection_attempt_size() == 0) { - return false; - } - for (auto& connection_attempt : - current_strategy_session_->connection_attempt()) { - if (connection_attempt.medium() == medium && - connection_attempt.direction() == direction && - connection_attempt.connection_token() == connection_token && - connection_attempt.type() == type && - connection_attempt.operation_result().result_code() == - operation_result_code) { - return true; - } - } - - return false; -} - -// If bandwidth upgrade always failed on the same fromMedium, toMedium, result, -// stage and result code, we'll drop the duplicate logs for preventing the waste -// of log storage space -bool AnalyticsRecorder::EraseIfBandwidthUpgradeRecordExistedLocked( - const std::string& endpoint_id, BandwidthUpgradeResult result, - BandwidthUpgradeErrorStage error_stage, - OperationResultCode operation_result_code) { - if (current_strategy_session_ == nullptr) { - return false; - } - auto it = bandwidth_upgrade_attempts_.find(endpoint_id); - if (it != bandwidth_upgrade_attempts_.end()) { - ConnectionsLog::BandwidthUpgradeAttempt* attempt = it->second.get(); - for (auto& existing_attempt : - current_strategy_session_->upgrade_attempt()) { - if (attempt->from_medium() == existing_attempt.from_medium() && - attempt->to_medium() == existing_attempt.to_medium() && - result == existing_attempt.upgrade_result() && - error_stage == existing_attempt.error_stage() && - operation_result_code == - existing_attempt.operation_result().result_code()) { - bandwidth_upgrade_attempts_.erase(it); - return true; - } - } - } - return false; -} - -void AnalyticsRecorder::FinishUpgradeAttemptLocked( - const std::string& endpoint_id, BandwidthUpgradeResult result, - BandwidthUpgradeErrorStage error_stage, - OperationResultCode operation_result_code, bool erase_item) { - if (current_strategy_session_ == nullptr) { - LOG(INFO) << "Unable to record upgrade attempt due to null " - "current_strategy_session_"; - return; - } - // Add the BandwidthUpgradeAttempt in the current StrategySession. - auto it = bandwidth_upgrade_attempts_.find(endpoint_id); - if (it != bandwidth_upgrade_attempts_.end()) { - ConnectionsLog::BandwidthUpgradeAttempt* attempt = it->second.get(); - attempt->set_duration_millis( - absl::ToUnixMillis(SystemClock::ElapsedRealtime()) - - attempt->duration_millis()); - attempt->set_error_stage(error_stage); - attempt->set_upgrade_result(result); - - auto operation_result_proto = - std::make_unique(); - operation_result_proto->set_result_code(operation_result_code); - operation_result_proto->set_result_category( - ConvertToOperationResultCategory(operation_result_code)); - attempt->set_allocated_operation_result(operation_result_proto.release()); - *current_strategy_session_->add_upgrade_attempt() = *attempt; - if (erase_item) { - bandwidth_upgrade_attempts_.erase(it); - } - } -} - -void AnalyticsRecorder::FinishStrategySessionLocked() { - if (current_strategy_session_ != nullptr) { - FinishAdvertisingPhaseLocked(); - FinishDiscoveryPhaseLocked(); - - // Finish any unfinished LogicalConnections. - for (const auto& item : active_connections_) { - const std::unique_ptr& logical_connection = - item.second; - logical_connection->CloseAllPhysicalConnections(); - absl::c_copy( - logical_connection->GetEstablisedConnections(), - RepeatedFieldBackInserter( - current_strategy_session_->mutable_established_connection())); - } - active_connections_.clear(); - - // Finish any pending upgrade attempts. - for (const auto& item : bandwidth_upgrade_attempts_) { - FinishUpgradeAttemptLocked( - item.first, UNFINISHED_ERROR, UPGRADE_UNFINISHED, - OperationResultCode::DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS, - /*erase_item=*/false); - } - bandwidth_upgrade_attempts_.clear(); - - // Add the StrategySession in ClientSession - if (current_strategy_session_ != nullptr) { - current_strategy_session_->set_duration_millis(absl::ToInt64Milliseconds( - SystemClock::ElapsedRealtime() - started_strategy_session_time_)); - *client_session_->add_strategy_session() = - *std::move(current_strategy_session_); - } - - current_strategy_session_ = nullptr; - current_strategy_ = connections::Strategy::kNone; - LogEvent(STOP_STRATEGY_SESSION); - } -} - -ConnectionsStrategy AnalyticsRecorder::StrategyToConnectionStrategy( - connections::Strategy strategy) { - if (strategy == connections::Strategy::kP2pCluster) { - return P2P_CLUSTER; - } - if (strategy == connections::Strategy::kP2pStar) { - return P2P_STAR; - } - if (strategy == connections::Strategy::kP2pPointToPoint) { - return P2P_POINT_TO_POINT; - } - return UNKNOWN_STRATEGY; -} - -PayloadType AnalyticsRecorder::PayloadTypeToProtoPayloadType( - connections::PayloadType type) { - switch (type) { - case connections::PayloadType::kBytes: - return BYTES; - case connections::PayloadType::kFile: - return FILE; - case connections::PayloadType::kStream: - return STREAM; - default: - return UNKNOWN_PAYLOAD_TYPE; - } -} - -void AnalyticsRecorder::PendingPayload::AddChunk( - std::int64_t chunk_size_bytes) { - num_bytes_transferred_ += chunk_size_bytes; - num_chunks_++; -} - -ConnectionsLog::Payload AnalyticsRecorder::PendingPayload::GetProtoPayload( - PayloadStatus status) { - ConnectionsLog::Payload payload; - payload.set_duration_millis( - absl::ToInt64Milliseconds(SystemClock::ElapsedRealtime() - start_time_)); - payload.set_type(type_); - payload.set_total_size_bytes(total_size_bytes_); - payload.set_num_bytes_transferred(num_bytes_transferred_); - payload.set_num_chunks(num_chunks_); - payload.set_status(status); - - auto operation_result_proto = - std::make_unique(); - operation_result_proto->set_result_code(operation_result_code_); - operation_result_proto->set_result_category( - ConvertToOperationResultCategory(operation_result_code_)); - payload.set_allocated_operation_result(operation_result_proto.release()); - - return payload; -} - -void AnalyticsRecorder::LogicalConnection::PhysicalConnectionEstablished( - Medium medium, const std::string& connection_token) { - if (current_medium_ != UNKNOWN_MEDIUM) { - LOG(WARNING) << "Unexpected call to PhysicalConnectionEstablished while " - "AnalyticsRecorder still has an active current medium."; - } - - auto established_connection = - std::make_unique(); - established_connection->set_medium(medium); - established_connection->set_duration_millis( - absl::ToUnixMillis(SystemClock::ElapsedRealtime())); - established_connection->set_connection_token(connection_token); - - auto operation_result_proto = - std::make_unique(); - operation_result_proto->set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result_proto->set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - established_connection->set_allocated_operation_result( - operation_result_proto.release()); - physical_connections_.insert({medium, std::move(established_connection)}); - current_medium_ = medium; -} - -void AnalyticsRecorder::LogicalConnection::PhysicalConnectionClosed( - Medium medium, DisconnectionReason reason, SafeDisconnectionResult result) { - if (current_medium_ == UNKNOWN_MEDIUM) { - LOG(WARNING) << "Unexpected call to PhysicalConnectionClosed() for medium " - << Medium_Name(medium) - << " while AnalyticsRecorder has no active current medium"; - } else if (current_medium_ != medium) { - LOG(WARNING) << "Unexpected call to PhysicalConnectionClosed() for medium " - << Medium_Name(medium) - << "while AnalyticsRecorder has active medium " - << Medium_Name(current_medium_); - } - - auto it = physical_connections_.find(medium); - if (it == physical_connections_.end()) { - LOG(WARNING) - << "Unexpected call to physicalConnectionClosed() for medium " - << Medium_Name(medium) - << " with no corresponding EstablishedConnection that was previously" - " opened."; - return; - } - ConnectionsLog::EstablishedConnection* established_connection = - it->second.get(); - if (established_connection->has_disconnection_reason()) { - LOG(WARNING) << "Unexpected call to physicalConnectionClosed() for medium " - << Medium_Name(medium) - << " which already has disconnection reason " - << DisconnectionReason_Name( - established_connection->disconnection_reason()); - return; - } - FinishPhysicalConnection(established_connection, reason, result); - - if (medium == current_medium_) { - // If the EstablishedConnection we just closed was the one that we have - // marked as current, unset currentMedium. - current_medium_ = UNKNOWN_MEDIUM; - } -} - -void AnalyticsRecorder::LogicalConnection::CloseAllPhysicalConnections() { - for (const auto& physical_connection : physical_connections_) { - ConnectionsLog::EstablishedConnection* established_connection = - physical_connection.second.get(); - if (!established_connection->has_disconnection_reason()) { - FinishPhysicalConnection( - established_connection, UNFINISHED, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); - } - } - current_medium_ = UNKNOWN_MEDIUM; -} - -std::vector -AnalyticsRecorder::LogicalConnection::GetEstablisedConnections() { - std::vector established_connections; - if (current_medium_ != UNKNOWN_MEDIUM) { - LOG(WARNING) - << "AnalyticsRecorder expected no more active physical connections " - "before logging this endpoint connection."; - return established_connections; - } - std::transform(physical_connections_.begin(), physical_connections_.end(), - std::back_inserter(established_connections), - [](auto& kv) { return *kv.second; }); - physical_connections_.clear(); - - for (auto& established_connection : established_connections) { - if (absl::Milliseconds(established_connection.duration_millis()) >= - kConnectionTokenMaxLife) { - LOG(INFO) << "connection token exceed TTL, drop token."; - established_connection.set_connection_token(""); - } - } - - return established_connections; -} - -void AnalyticsRecorder::LogicalConnection::IncomingPayloadStarted( - std::int64_t payload_id, PayloadType type, std::int64_t total_size_bytes) { - incoming_payloads_.insert( - {payload_id, std::make_unique(type, total_size_bytes)}); -} - -void AnalyticsRecorder::LogicalConnection::ChunkReceived( - std::int64_t payload_id, std::int64_t size_bytes) { - auto it = incoming_payloads_.find(payload_id); - if (it == incoming_payloads_.end()) { - return; - } - PendingPayload* pending_payload = it->second.get(); - pending_payload->AddChunk(size_bytes); -} - -void AnalyticsRecorder::LogicalConnection::IncomingPayloadDone( - std::int64_t payload_id, PayloadStatus status, - OperationResultCode operation_result_code) { - if (current_medium_ == UNKNOWN_MEDIUM) { - LOG(WARNING) << "Unexpected call to incomingPayloadDone() while " - "AnalyticsRecorder has no active current medium."; - return; - } - auto it = physical_connections_.find(current_medium_); - if (it != physical_connections_.end()) { - const std::unique_ptr& - established_connection = it->second; - auto it = incoming_payloads_.find(payload_id); - if (it != incoming_payloads_.end()) { - it->second->SetOperationResultCode(operation_result_code); - *established_connection->add_received_payload() = - it->second->GetProtoPayload(status); - incoming_payloads_.erase(it); - } - } -} - -void AnalyticsRecorder::LogicalConnection::OutgoingPayloadStarted( - std::int64_t payload_id, PayloadType type, std::int64_t total_size_bytes) { - outgoing_payloads_.insert( - {payload_id, std::make_unique(type, total_size_bytes)}); -} - -void AnalyticsRecorder::LogicalConnection::ChunkSent(std::int64_t payload_id, - std::int64_t size_bytes) { - auto it = outgoing_payloads_.find(payload_id); - if (it == outgoing_payloads_.end()) { - return; - } - PendingPayload* payload = it->second.get(); - payload->AddChunk(size_bytes); -} - -void AnalyticsRecorder::LogicalConnection::OutgoingPayloadDone( - std::int64_t payload_id, PayloadStatus status, - OperationResultCode operation_result_code) { - if (current_medium_ == UNKNOWN_MEDIUM) { - LOG(WARNING) << "Unexpected call to outgoingPayloadDone() while " - "AnalyticsRecorder has no active current medium."; - return; - } - auto it = physical_connections_.find(current_medium_); - if (it != physical_connections_.end()) { - const std::unique_ptr& - established_connection = it->second; - auto it = outgoing_payloads_.find(payload_id); - if (it != outgoing_payloads_.end()) { - it->second->SetOperationResultCode(operation_result_code); - *established_connection->add_sent_payload() = - it->second->GetProtoPayload(status); - outgoing_payloads_.erase(it); - } - } -} - -void AnalyticsRecorder::LogicalConnection::FinishPhysicalConnection( - ConnectionsLog::EstablishedConnection* established_connection, - DisconnectionReason reason, SafeDisconnectionResult result) { - established_connection->set_disconnection_reason(reason); - established_connection->set_safe_disconnection_result(result); - established_connection->set_duration_millis( - absl::ToUnixMillis(SystemClock::ElapsedRealtime()) - - established_connection->duration_millis()); - - // Add any not-yet-finished payloads to this EstablishedConnection. - std::vector in_payloads = - ResolvePendingPayloads(incoming_payloads_, reason); - absl::c_move(in_payloads, - RepeatedFieldBackInserter( - established_connection->mutable_received_payload())); - std::vector out_payloads = - ResolvePendingPayloads(outgoing_payloads_, reason); - absl::c_move(out_payloads, - RepeatedFieldBackInserter( - established_connection->mutable_sent_payload())); -} - -std::vector -AnalyticsRecorder::LogicalConnection::ResolvePendingPayloads( - absl::btree_map>& - pending_payloads, - DisconnectionReason reason) { - std::vector completed_payloads; - absl::btree_map> - upgraded_payloads; - PayloadStatus status = - reason == UPGRADED ? MOVED_TO_NEW_MEDIUM : CONNECTION_CLOSED; - - OperationResultCode operation_result_code = - GetPendingPayloadResultCodeFromReason(reason); - for (const auto& item : pending_payloads) { - const std::unique_ptr& pending_payload = item.second; - pending_payload->SetOperationResultCode(operation_result_code); - ConnectionsLog::Payload proto_payload = - pending_payload->GetProtoPayload(status); - completed_payloads.push_back(proto_payload); - if (reason == UPGRADED) { - upgraded_payloads.insert( - {item.first, - std::make_unique(pending_payload->type(), - pending_payload->total_size_bytes(), - operation_result_code)}); - } - } - pending_payloads.clear(); - - if (reason == UPGRADED) { - // Re-populate the map with a new PendingPayload for each pending payload, - // since we expect them to be completed on the next EstablishedConnection. - pending_payloads = std::move(upgraded_payloads); - } - // Return the list of completed payloads to be added to the current - // EstablishedConnection. - return completed_payloads; -} - -OperationResultCode -AnalyticsRecorder::LogicalConnection::GetPendingPayloadResultCodeFromReason( - DisconnectionReason reason) { - switch (reason) { - case UPGRADED: - return OperationResultCode::MISCELLEANEOUS_MOVE_TO_NEW_MEDIUM; - case DisconnectionReason::LOCAL_DISCONNECTION: - return OperationResultCode::CLIENT_CANCELLATION_LOCAL_DISCONNECT; - case DisconnectionReason::REMOTE_DISCONNECTION: - return OperationResultCode::CLIENT_CANCELLATION_REMOTE_DISCONNECT; - default: - return OperationResultCode::NEARBY_GENERIC_CONNECTION_CLOSED; - } -} - -OperationResultCategory AnalyticsRecorder::GetOperationResultCategory( - location::nearby::proto::connections::OperationResultCode result_code) { - return ConvertToOperationResultCategory(result_code); -} - -} // namespace analytics -} // namespace nearby +} // namespace nearby::analytics diff --git a/connections/implementation/analytics/analytics_recorder.h b/connections/implementation/analytics/analytics_recorder.h index b24232b3..601d12bc 100644 --- a/connections/implementation/analytics/analytics_recorder.h +++ b/connections/implementation/analytics/analytics_recorder.h @@ -18,118 +18,98 @@ #include #include #include -#include #include -#include "absl/base/thread_annotations.h" -#include "absl/container/btree_map.h" -#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "connections/implementation/analytics/advertising_metadata_params.h" #include "connections/implementation/analytics/connection_attempt_metadata_params.h" #include "connections/implementation/analytics/discovery_metadata_params.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/payload_type.h" #include "connections/strategy.h" -#include "internal/analytics/event_logger.h" #include "internal/platform/error_code_params.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/mutex.h" -#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" -namespace nearby { -namespace analytics { +namespace nearby::analytics { + +enum class SafeDisconnectionResult { + kUnknown = 0, + kSafeDisconnection = 1, + kUnsafeDisconnection = 2, +}; class AnalyticsRecorder { public: - explicit AnalyticsRecorder(::nearby::analytics::EventLogger* event_logger); - virtual ~AnalyticsRecorder(); + AnalyticsRecorder() = default; + virtual ~AnalyticsRecorder() = default; // Advertising phase - void OnStartAdvertising( + virtual void OnStartAdvertising( connections::Strategy strategy, const std::vector& mediums, - AdvertisingMetadataParams* advertising_metadata_params) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnStopAdvertising() ABSL_LOCKS_EXCLUDED(mutex_); + AdvertisingMetadataParams* advertising_metadata_params) = 0; + virtual void OnStopAdvertising() = 0; - // In case the client calls the {@link BasePcp#updateAdvertisingOptions()} - // multiple times, adds one index value to group the mediums results within - // the same UpdateAdvertisingOptions call, this API is to return the largest - // index value in current_advertising_phase. - int GetNextAdvertisingUpdateIndex() ABSL_LOCKS_EXCLUDED(mutex_); + virtual int GetNextAdvertisingUpdateIndex() = 0; // Connection listening - void OnStartedIncomingConnectionListening(connections::Strategy strategy) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnStoppedIncomingConnectionListening() ABSL_LOCKS_EXCLUDED(mutex_); + virtual void OnStartedIncomingConnectionListening( + connections::Strategy strategy) = 0; + virtual void OnStoppedIncomingConnectionListening() = 0; // Discovery phase - void OnStartDiscovery( + virtual void OnStartDiscovery( connections::Strategy strategy, const std::vector& mediums, - DiscoveryMetadataParams* discovery_metadata_params) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnStopDiscovery() ABSL_LOCKS_EXCLUDED(mutex_); + DiscoveryMetadataParams* discovery_metadata_params) = 0; + virtual void OnStopDiscovery() = 0; - // In case the client calls the {@link BasePcp#updateDiscoveryOptions()} - // multiple times, adds one index value to group the medium results within the - // same UpdateDiscoveryOptions call, this - // API is to return the latest index value in current_discovery_phase. - int GetNextDiscoveryUpdateIndex() ABSL_LOCKS_EXCLUDED(mutex_); - void OnEndpointFound(location::nearby::proto::connections::Medium medium) - ABSL_LOCKS_EXCLUDED(mutex_); + virtual int GetNextDiscoveryUpdateIndex() = 0; + virtual void OnEndpointFound( + location::nearby::proto::connections::Medium medium) = 0; // Connection request - void OnRequestConnection(const connections::Strategy& strategy, - const std::string& endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); + virtual void OnRequestConnection(const connections::Strategy& strategy, + const std::string& endpoint_id) = 0; - void OnConnectionRequestReceived(const std::string& remote_endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnConnectionRequestSent(const std::string& remote_endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnRemoteEndpointAccepted(const std::string& remote_endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnLocalEndpointAccepted(const std::string& remote_endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnRemoteEndpointRejected(const std::string& remote_endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnLocalEndpointRejected(const std::string& remote_endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); + virtual void OnConnectionRequestReceived( + const std::string& remote_endpoint_id) = 0; + virtual void OnConnectionRequestSent( + const std::string& remote_endpoint_id) = 0; + virtual void OnRemoteEndpointAccepted( + const std::string& remote_endpoint_id) = 0; + virtual void OnLocalEndpointAccepted( + const std::string& remote_endpoint_id) = 0; + virtual void OnRemoteEndpointRejected( + const std::string& remote_endpoint_id) = 0; + virtual void OnLocalEndpointRejected( + const std::string& remote_endpoint_id) = 0; // Connection attempt - // Records an attempt with meta data at establishing an incoming physical - // connection. - void OnIncomingConnectionAttempt( + virtual void OnIncomingConnectionAttempt( location::nearby::proto::connections::ConnectionAttemptType type, location::nearby::proto::connections::Medium medium, location::nearby::proto::connections::ConnectionAttemptResult result, absl::Duration duration, const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) - ABSL_LOCKS_EXCLUDED(mutex_); - // Records an attempt with meta data at establishing an outgoing physical - // connection. - void OnOutgoingConnectionAttempt( + ConnectionAttemptMetadataParams* connection_attempt_metadata_params) = 0; + virtual void OnOutgoingConnectionAttempt( const std::string& remote_endpoint_id, location::nearby::proto::connections::ConnectionAttemptType type, location::nearby::proto::connections::Medium medium, location::nearby::proto::connections::ConnectionAttemptResult result, absl::Duration duration, const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) - ABSL_LOCKS_EXCLUDED(mutex_); + ConnectionAttemptMetadataParams* connection_attempt_metadata_params) = 0; + static std::unique_ptr BuildAdvertisingMetadataParams( bool is_extended_advertisement_supported = false, int connected_ap_frequency = 0, bool is_nfc_available = false, - const std::vector& + const std::vector& operation_result_with_mediums = {}); static std::unique_ptr BuildDiscoveryMetadataParams( bool is_extended_advertisement_supported = false, int connected_ap_frequency = 0, bool is_nfc_available = false, - const std::vector& + const std::vector& operation_result_with_mediums = {}); static std::unique_ptr @@ -147,363 +127,78 @@ class AnalyticsRecorder { GetChannelIoErrorResultCodeFromMedium( location::nearby::proto::connections::Medium medium); - // Connection establishedSafeDisconnectionResult - void OnConnectionEstablished( + // Connection established + virtual void OnConnectionEstablished( const std::string& endpoint_id, location::nearby::proto::connections::Medium medium, - const std::string& connection_token) ABSL_LOCKS_EXCLUDED(mutex_); - void OnConnectionClosed( + const std::string& connection_token) = 0; + virtual void OnConnectionClosed( const std::string& endpoint_id, location::nearby::proto::connections::Medium medium, location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result) - ABSL_LOCKS_EXCLUDED(mutex_); + SafeDisconnectionResult result) = 0; // Payload - void OnIncomingPayloadStarted(const std::string& endpoint_id, - std::int64_t payload_id, - connections::PayloadType type, - std::int64_t total_size_bytes) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnPayloadChunkReceived(const std::string& endpoint_id, - std::int64_t payload_id, - std::int64_t chunk_size_bytes) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnIncomingPayloadDone( + virtual void OnIncomingPayloadStarted(const std::string& endpoint_id, + std::int64_t payload_id, + connections::PayloadType type, + std::int64_t total_size_bytes) = 0; + virtual void OnPayloadChunkReceived(const std::string& endpoint_id, + std::int64_t payload_id, + std::int64_t chunk_size_bytes) = 0; + virtual void OnIncomingPayloadDone( const std::string& endpoint_id, std::int64_t payload_id, location::nearby::proto::connections::PayloadStatus status, location::nearby::proto::connections::OperationResultCode - operation_result_code) ABSL_LOCKS_EXCLUDED(mutex_); - void OnOutgoingPayloadStarted(const std::vector& endpoint_ids, - std::int64_t payload_id, - connections::PayloadType type, - std::int64_t total_size_bytes) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnPayloadChunkSent(const std::string& endpoint_id, - std::int64_t payload_id, - std::int64_t chunk_size_bytes) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnOutgoingPayloadDone( + operation_result_code) = 0; + virtual void OnOutgoingPayloadStarted( + const std::vector& endpoint_ids, std::int64_t payload_id, + connections::PayloadType type, std::int64_t total_size_bytes) = 0; + virtual void OnPayloadChunkSent(const std::string& endpoint_id, + std::int64_t payload_id, + std::int64_t chunk_size_bytes) = 0; + virtual void OnOutgoingPayloadDone( const std::string& endpoint_id, std::int64_t payload_id, location::nearby::proto::connections::PayloadStatus status, location::nearby::proto::connections::OperationResultCode - operation_result_code) ABSL_LOCKS_EXCLUDED(mutex_); + operation_result_code) = 0; // BandwidthUpgrade - void OnBandwidthUpgradeStarted( + virtual void OnBandwidthUpgradeStarted( const std::string& endpoint_id, location::nearby::proto::connections::Medium from_medium, location::nearby::proto::connections::Medium to_medium, location::nearby::proto::connections::ConnectionAttemptDirection direction, - const std::string& connection_token) ABSL_LOCKS_EXCLUDED(mutex_); - void UpdateBwUpgradeNetworkInfo(const std::string& endpoint_id, - int num_interfaces, - int num_ipv6_only_interfaces) - ABSL_LOCKS_EXCLUDED(mutex_); - void OnBandwidthUpgradeError( + const std::string& connection_token) = 0; + virtual void UpdateBwUpgradeNetworkInfo(const std::string& endpoint_id, + int num_interfaces, + int num_ipv6_only_interfaces) = 0; + virtual void OnBandwidthUpgradeError( const std::string& endpoint_id, location::nearby::proto::connections::BandwidthUpgradeResult result, location::nearby::proto::connections::BandwidthUpgradeErrorStage error_stage, location::nearby::proto::connections::OperationResultCode - operation_result_code) ABSL_LOCKS_EXCLUDED(mutex_); - void OnBandwidthUpgradeSuccess(const std::string& endpoint_id) - ABSL_LOCKS_EXCLUDED(mutex_); + operation_result_code) = 0; + virtual void OnBandwidthUpgradeSuccess(const std::string& endpoint_id) = 0; // Error Code - void OnErrorCode(const ErrorCodeParams& params); + virtual void OnErrorCode(const ErrorCodeParams& params) = 0; - // Log the start client session event with start client session logging - // resources setup (e.g. client_session_, started_client_session_time_) - void LogStartSession() ABSL_LOCKS_EXCLUDED(mutex_); + virtual void LogStartSession() = 0; + virtual void LogSession() = 0; - // Invokes event_logger_.Log() at the end of life of client. Log action is - // called in a separate thread to allow synchronous potentially lengthy - // execution. - void LogSession() ABSL_LOCKS_EXCLUDED(mutex_); + virtual bool IsSessionLogged() = 0; - bool IsSessionLogged(); - - location::nearby::proto::connections::OperationResultCategory + virtual location::nearby::proto::connections::OperationResultCategory GetOperationResultCategory( - location::nearby::proto::connections::OperationResultCode result_code); - - // Waits until all logs are sent to the backend. - // For testing only. - void Sync(); - - private: - // Tracks the chunks and duration of a Payload on a particular medium. - class PendingPayload { - public: - PendingPayload(location::nearby::proto::connections::PayloadType type, - std::int64_t total_size_bytes) - : PendingPayload(type, total_size_bytes, - location::nearby::proto::connections:: - OperationResultCode::DETAIL_UNKNOWN) {} - PendingPayload(location::nearby::proto::connections::PayloadType type, - std::int64_t total_size_bytes, - location::nearby::proto::connections::OperationResultCode - operation_result_code) - : start_time_(SystemClock::ElapsedRealtime()), - type_(type), - total_size_bytes_(total_size_bytes), - num_bytes_transferred_(0), - num_chunks_(0), - operation_result_code_(operation_result_code) {} - ~PendingPayload() = default; - - void AddChunk(std::int64_t chunk_size_bytes); - - location::nearby::analytics::proto::ConnectionsLog::Payload GetProtoPayload( - location::nearby::proto::connections::PayloadStatus status); - - location::nearby::proto::connections::PayloadType type() const { - return type_; - } - - std::int64_t total_size_bytes() const { return total_size_bytes_; } - - void SetOperationResultCode( - location::nearby::proto::connections::OperationResultCode - operation_result_code) { - operation_result_code_ = operation_result_code; - } - - private: - absl::Time start_time_; - location::nearby::proto::connections::PayloadType type_; - std::int64_t total_size_bytes_; - std::int64_t num_bytes_transferred_; - int num_chunks_; - location::nearby::proto::connections::OperationResultCode - operation_result_code_ = location::nearby::proto::connections:: - OperationResultCode::DETAIL_UNKNOWN; - }; - - class LogicalConnection { - public: - LogicalConnection( - location::nearby::proto::connections::Medium initial_medium, - const std::string& connection_token) { - PhysicalConnectionEstablished(initial_medium, connection_token); - } - LogicalConnection(const LogicalConnection&) = delete; - LogicalConnection(LogicalConnection&& other) - : current_medium_(std::move(other.current_medium_)), - physical_connections_(std::move(other.physical_connections_)), - incoming_payloads_(std::move(other.incoming_payloads_)), - outgoing_payloads_(std::move(other.outgoing_payloads_)) {} - LogicalConnection& operator=(const LogicalConnection&) = delete; - LogicalConnection&& operator=(LogicalConnection&&) = delete; - ~LogicalConnection() = default; - - void PhysicalConnectionEstablished( - location::nearby::proto::connections::Medium medium, - const std::string& connection_token); - void PhysicalConnectionClosed( - location::nearby::proto::connections::Medium medium, - location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result); - void CloseAllPhysicalConnections(); - - void IncomingPayloadStarted( - std::int64_t payload_id, - location::nearby::proto::connections::PayloadType type, - std::int64_t total_size_bytes); - void ChunkReceived(std::int64_t payload_id, std::int64_t size_bytes); - void IncomingPayloadDone( - std::int64_t payload_id, - location::nearby::proto::connections::PayloadStatus status, - location::nearby::proto::connections::OperationResultCode - operation_result_code); - void OutgoingPayloadStarted( - std::int64_t payload_id, - location::nearby::proto::connections::PayloadType type, - std::int64_t total_size_bytes); - void ChunkSent(std::int64_t payload_id, std::int64_t size_bytes); - void OutgoingPayloadDone( - std::int64_t payload_id, - location::nearby::proto::connections::PayloadStatus status, - location::nearby::proto::connections::OperationResultCode - operation_result_code); - - std::vector - GetEstablisedConnections(); - - private: - void FinishPhysicalConnection( - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection* established_connection, - location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result); - std::vector - ResolvePendingPayloads( - absl::btree_map>& - pending_payloads, - location::nearby::proto::connections::DisconnectionReason reason); - location::nearby::proto::connections::OperationResultCode - GetPendingPayloadResultCodeFromReason( - location::nearby::proto::connections::DisconnectionReason reason); - - location::nearby::proto::connections::Medium current_medium_ = - location::nearby::proto::connections::UNKNOWN_MEDIUM; - absl::btree_map> - physical_connections_; - absl::btree_map> - incoming_payloads_; - absl::btree_map> - outgoing_payloads_; - }; - - bool CanRecordAnalyticsLocked(absl::string_view method_name) - ABSL_SHARED_LOCKS_REQUIRED(mutex_); - - // Callbacks the ConnectionsLog proto byte array data to the EventLogger with - // ClientSession sub-proto. - void LogClientSessionLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - // Callbacks the ConnectionsLog proto byte array data to the EventLogger. - void LogEvent(location::nearby::proto::connections::EventType event_type); - - void UpdateStrategySessionLocked( - connections::Strategy strategy, - location::nearby::proto::connections::SessionRole role) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void RecordAdvertisingPhaseDurationAndReasonLocked(bool on_stop) const - ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void FinishAdvertisingPhaseLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void RecordDiscoveryPhaseDurationAndReasonLocked(bool on_stop) const - ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void FinishDiscoveryPhaseLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - bool UpdateAdvertiserConnectionRequestLocked( - location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest* - request) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - bool UpdateDiscovererConnectionRequestLocked( - location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest* - request) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - bool BothEndpointsRespondedLocked( - location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest* - request) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void LocalEndpointRespondedLocked( - const std::string& remote_endpoint_id, - location::nearby::proto::connections::ConnectionRequestResponse response) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void RemoteEndpointRespondedLocked( - const std::string& remote_endpoint_id, - location::nearby::proto::connections::ConnectionRequestResponse response) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - void MarkConnectionRequestIgnoredLocked( - location::nearby::analytics::proto::ConnectionsLog::ConnectionRequest* - request) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void OnIncomingConnectionAttemptLocked( - location::nearby::proto::connections::ConnectionAttemptType type, - location::nearby::proto::connections::Medium medium, - location::nearby::proto::connections::ConnectionAttemptResult result, - absl::Duration duration, const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) - ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void OnOutgoingConnectionAttemptLocked( - const std::string& remote_endpoint_id, - location::nearby::proto::connections::ConnectionAttemptType type, - location::nearby::proto::connections::Medium medium, - location::nearby::proto::connections::ConnectionAttemptResult result, - absl::Duration duration, const std::string& connection_token, - ConnectionAttemptMetadataParams* connection_attempt_metadata_params) - ABSL_SHARED_LOCKS_REQUIRED(mutex_); - bool ConnectionAttemptResultCodeExistedLocked( - location::nearby::proto::connections::Medium medium, - location::nearby::proto::connections::ConnectionAttemptDirection - direction, - const std::string& connection_token, - location::nearby::proto::connections::ConnectionAttemptType type, location::nearby::proto::connections::OperationResultCode - operation_result_code) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - bool EraseIfBandwidthUpgradeRecordExistedLocked( - const std::string& endpoint_id, - location::nearby::proto::connections::BandwidthUpgradeResult result, - location::nearby::proto::connections::BandwidthUpgradeErrorStage - error_stage, - location::nearby::proto::connections::OperationResultCode - operation_result_code) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void FinishUpgradeAttemptLocked( - const std::string& endpoint_id, - location::nearby::proto::connections::BandwidthUpgradeResult result, - location::nearby::proto::connections::BandwidthUpgradeErrorStage - error_stage, - location::nearby::proto::connections::OperationResultCode - operation_result_code, - bool erase_item = true) ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void FinishStrategySessionLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + result_code) = 0; - int GetLatestUpdateIndexLocked( - const std::vector& list) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - location::nearby::proto::connections::ConnectionsStrategy - StrategyToConnectionStrategy(connections::Strategy strategy); - location::nearby::proto::connections::PayloadType - PayloadTypeToProtoPayloadType(connections::PayloadType type); - - // Not owned by AnalyticsRecorder. Pointer must refer to a valid object - // that outlives the one constructed. - ::nearby::analytics::EventLogger* event_logger_; - - // Protects all sub-protos reading and writing in ConnectionLog. - Mutex mutex_; - - // ClientSession - std::unique_ptr< - location::nearby::analytics::proto::ConnectionsLog::ClientSession> - client_session_; - absl::Time started_client_session_time_; - bool session_was_logged_ ABSL_GUARDED_BY(mutex_) = false; - bool start_client_session_was_logged_ ABSL_GUARDED_BY(mutex_) = false; - - // Current StrategySession - connections::Strategy current_strategy_ ABSL_GUARDED_BY(mutex_) = - connections::Strategy::kNone; - std::unique_ptr< - location::nearby::analytics::proto::ConnectionsLog::StrategySession> - current_strategy_session_ ABSL_GUARDED_BY(mutex_); - absl::Time started_strategy_session_time_ ABSL_GUARDED_BY(mutex_); - - // Current AdvertisingPhase - std::unique_ptr< - location::nearby::analytics::proto::ConnectionsLog::AdvertisingPhase> - current_advertising_phase_; - absl::Time started_advertising_phase_time_ = absl::InfinitePast(); - - // Current DiscoveryPhase - std::unique_ptr< - location::nearby::analytics::proto::ConnectionsLog::DiscoveryPhase> - current_discovery_phase_; - absl::Time started_discovery_phase_time_ = absl::InfinitePast(); - - absl::btree_map> - incoming_connection_requests_ ABSL_GUARDED_BY(mutex_); - absl::btree_map> - outgoing_connection_requests_ ABSL_GUARDED_BY(mutex_); - absl::btree_map> - active_connections_ ABSL_GUARDED_BY(mutex_); - absl::btree_map> - bandwidth_upgrade_attempts_ ABSL_GUARDED_BY(mutex_); + virtual void Sync() = 0; }; -} // namespace analytics -} // namespace nearby +} // namespace nearby::analytics #endif // ANALYTICS_ANALYTICS_RECORDER_H_ diff --git a/connections/implementation/analytics/analytics_recorder_test.cc b/connections/implementation/analytics/analytics_recorder_test.cc deleted file mode 100644 index c431e862..00000000 --- a/connections/implementation/analytics/analytics_recorder_test.cc +++ /dev/null @@ -1,2593 +0,0 @@ -// Copyright 2022-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. -// 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 "connections/implementation/analytics/analytics_recorder.h" - -#include - -#include -#include -#include -#include - -#include "net/proto2/contrib/parse_proto/parse_text_proto.h" -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/time/time.h" -#include "connections/implementation/analytics/connection_attempt_metadata_params.h" -#include "connections/payload_type.h" -#include "connections/strategy.h" -#include "internal/analytics/mock_event_logger.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/error_code_params.h" -#include "internal/platform/error_code_recorder.h" -#include "internal/platform/exception.h" -#include "internal/platform/medium_environment.h" -#include "internal/proto/analytics/connections_log.proto.h" -#include "internal/test/fake_clock.h" -#include "proto/connections_enums.proto.h" - -namespace nearby { -namespace analytics { -namespace { - -using ::location::nearby::analytics::proto::ConnectionsLog; -using ::location::nearby::errorcode::proto::DISCONNECT; -using ::location::nearby::errorcode::proto::DISCONNECT_NETWORK_FAILED; -using ::location::nearby::errorcode::proto::INVALID_PARAMETER; -using ::location::nearby::errorcode::proto::NULL_BLUETOOTH_DEVICE_NAME; -using ::location::nearby::errorcode::proto::START_DISCOVERING; -using ::location::nearby::errorcode::proto::START_EXTENDED_DISCOVERING_FAILED; -using ::location::nearby::errorcode::proto:: - TACHYON_SEND_MESSAGE_STATUS_EXCEPTION; -using ::location::nearby::proto::connections::BLE; -using ::location::nearby::proto::connections::BLUETOOTH; -using ::location::nearby::proto::connections::CLIENT_SESSION; -using ::location::nearby::proto::connections::ERROR_CODE; -using ::location::nearby::proto::connections::EventType; -using ::location::nearby::proto::connections::INCOMING; -using ::location::nearby::proto::connections::INITIAL; -using ::location::nearby::proto::connections::LOCAL_DISCONNECTION; -using ::location::nearby::proto::connections::Medium; -using ::location::nearby::proto::connections::OperationResultCategory; -using ::location::nearby::proto::connections::OperationResultCode; -using ::location::nearby::proto::connections::RESULT_ERROR; -using ::location::nearby::proto::connections::RESULT_SUCCESS; -using ::location::nearby::proto::connections::START_CLIENT_SESSION; -using ::location::nearby::proto::connections::START_STRATEGY_SESSION; -using ::location::nearby::proto::connections::STOP_CLIENT_SESSION; -using ::location::nearby::proto::connections::STOP_STRATEGY_SESSION; -using ::location::nearby::proto::connections::SUCCESS; -using ::location::nearby::proto::connections::UPGRADED; -using ::location::nearby::proto::connections::WEB_RTC; -using ::location::nearby::proto::connections::WIFI_LAN; -using ::location::nearby::proto::connections::WIFI_LAN_MEDIUM_ERROR; -using ::location::nearby::proto::connections::WIFI_LAN_SOCKET_CREATION; -using ::nearby::analytics::MockEventLogger; -using ::proto2::contrib::parse_proto::ParseTextProtoOrDie; -using ::testing::Contains; -using ::protobuf_matchers::EqualsProto; -using ::testing::Not; - -constexpr absl::Duration kDefaultTimeout = absl::Milliseconds(1000); - -class FakeEventLogger : public MockEventLogger { - public: - explicit FakeEventLogger(CountDownLatch& client_session_done_latch) - : client_session_done_latch_(client_session_done_latch) {} - - FakeEventLogger(CountDownLatch& client_session_done_latch, - CountDownLatch* start_client_session_done_latch_ptr) - : client_session_done_latch_(client_session_done_latch), - start_client_session_done_latch_ptr_( - start_client_session_done_latch_ptr) {} - - void Log(const ConnectionsLog& message) override { - EventType event_type = message.event_type(); - logged_event_types_.push_back(event_type); - if (event_type == CLIENT_SESSION) { - logged_client_session_count_++; - logged_client_session_ = message.client_session(); - } - if (event_type == ERROR_CODE) { - error_code_ = message.error_code(); - } - if (event_type == STOP_CLIENT_SESSION) { - client_session_done_latch_.CountDown(); - } - if (start_client_session_done_latch_ptr_ != nullptr && - event_type == START_CLIENT_SESSION) { - start_client_session_done_latch_ptr_->CountDown(); - } - } - - int GetLoggedClientSessionCount() const { - return logged_client_session_count_; - } - - const ConnectionsLog::ClientSession& GetLoggedClientSession() { - return logged_client_session_; - } - - const ConnectionsLog::ErrorCode& GetErrorCode() { return error_code_; } - - std::vector GetLoggedEventTypes() { return logged_event_types_; } - - void SetClientSessionDoneLatch( - const CountDownLatch& client_session_done_latch) { - client_session_done_latch_ = client_session_done_latch; - } - - void SetStartClientSessionDoneLatchPtr( - CountDownLatch* start_client_session_done_latch_ptr) { - start_client_session_done_latch_ptr_ = start_client_session_done_latch_ptr; - } - - private: - int logged_client_session_count_ = 0; - CountDownLatch& client_session_done_latch_; - CountDownLatch* start_client_session_done_latch_ptr_ = nullptr; - ConnectionsLog::ClientSession logged_client_session_; - ConnectionsLog::ErrorCode error_code_; - std::vector logged_event_types_; -}; - -class AnalyticsRecorderTest : public ::testing::Test { - protected: - void SetUp() override { - MediumEnvironment::Instance().Start({.use_simulated_clock = true}); - } - - void TearDown() override { MediumEnvironment::Instance().Stop(); } - - FakeClock& GetFakeClock() const { - return *MediumEnvironment::Instance().GetSimulatedClock().value(); - } -}; - -// Test if session_was_logged_ is reset by checking if LogSession can take -// effect again or not. -TEST_F(AnalyticsRecorderTest, SessionOnlyLoggedOnceWorks) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - analytics_recorder.LogSession(); - analytics_recorder.LogSession(); - analytics_recorder.LogSession(); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - // Only called once. - EXPECT_EQ(event_logger.GetLoggedClientSessionCount(), 1); -} - -TEST_F(AnalyticsRecorderTest, SetFieldsCorrectlyForNestedAdvertisingCalls) { - connections::Strategy strategy = connections::Strategy::kP2pStar; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLUETOOTH); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - advertising_metadata_params->operation_result_with_mediums = { - operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(50)); - analytics_recorder.OnStartAdvertising(strategy, /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStopAdvertising(); - operation_result.set_medium(BLE); - advertising_metadata_params->operation_result_with_mediums = { - operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStartAdvertising(strategy, /*mediums=*/{BLUETOOTH}, - advertising_metadata_params.get()); - - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 650 - strategy_session { - duration_millis: 600 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 100 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: CLIENT_STOP_ADVERTISING - } - advertising_phase { - duration_millis: 300 - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLE - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - (EqualsProto(strategy_session_proto))); -} - -TEST_F(AnalyticsRecorderTest, SetFieldsCorrectlyForNestedDiscoveryCalls) { - connections::Strategy strategy = connections::Strategy::kP2pStar; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLUETOOTH); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - ConnectionsLog::OperationResultWithMedium operation_result2; - operation_result2.set_medium(BLE); - operation_result2.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result2.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams( - /*is_extended_advertisement_supported*/ true, - /*connected_ap_frequency*/ 1, /*is_nfc_available=*/false, - {operation_result, operation_result2}); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(strategy, /*mediums=*/{BLE, BLUETOOTH}, - discovery_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStopDiscovery(); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnEndpointFound(BLUETOOTH); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnEndpointFound(BLE); - GetFakeClock().FastForward(absl::Milliseconds(500)); - - auto discovery_metadata_params2 = - analytics_recorder.BuildDiscoveryMetadataParams( - /*is_extended_advertisement_supported*/ true, - /*connected_ap_frequency*/ 1, /*is_nfc_available=*/false, - {operation_result}); - analytics_recorder.OnStartDiscovery(strategy, /*mediums=*/{BLUETOOTH}, - discovery_metadata_params2.get()); - GetFakeClock().FastForward(absl::Milliseconds(600)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 2100 - strategy_session { - duration_millis: 2000 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 200 - medium: BLE - medium: BLUETOOTH - discovered_endpoint { - medium: BLUETOOTH - latency_millis: 500 - } - discovered_endpoint { - medium: BLE - latency_millis: 900 - } - discovery_metadata { - supports_extended_ble_advertisements: true - connected_ap_frequency: 1 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - adv_dis_result { - medium: BLE - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: CLIENT_STOP_DISCOVERING - } - discovery_phase { - duration_millis: 600 - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: true - connected_ap_frequency: 1 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: FINISH_SESSION_STOP_DISCOVERING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, - OneStrategySessionForMultipleRoundsOfDiscoveryAdvertising) { - connections::Strategy strategy = connections::Strategy::kP2pStar; - std::vector mediums = {BLE, BLUETOOTH}; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(strategy, mediums, - advertising_metadata_params.get()); - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStartDiscovery(strategy, mediums, - discovery_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnStopDiscovery(); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnStartAdvertising(strategy, mediums, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(700)); - analytics_recorder.OnStartDiscovery(strategy, mediums, - discovery_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.OnStopDiscovery(); - GetFakeClock().FastForward(absl::Milliseconds(900)); - analytics_recorder.OnStartDiscovery(strategy, mediums, {}); - GetFakeClock().FastForward(absl::Milliseconds(1000)); - analytics_recorder.OnStartAdvertising(strategy, mediums, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(1100)); - analytics_recorder.OnStopDiscovery(); - GetFakeClock().FastForward(absl::Milliseconds(1200)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(1300)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - std::vector event_types = event_logger.GetLoggedEventTypes(); - EXPECT_THAT(event_types, Contains(START_STRATEGY_SESSION).Times(1)); - EXPECT_THAT(event_types, Contains(STOP_STRATEGY_SESSION).Times(1)); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 9100 - strategy_session { - duration_millis: 9000 - strategy: P2P_STAR - role: ADVERTISER - role: DISCOVERER - discovery_phase { - duration_millis: 700 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_DISCOVERING - } - discovery_phase { - duration_millis: 800 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_DISCOVERING - } - discovery_phase { - duration_millis: 2100 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_DISCOVERING - } - advertising_phase { - duration_millis: 500 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - } - advertising_phase { - duration_millis: 600 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - } - advertising_phase { - duration_millis: 2300 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, AdvertiserConnectionRequestsWorks) { - std::string endpoint_id_0 = "endpoint_id_0"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - std::string endpoint_id_3 = "endpoint_id_3"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLE); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - advertising_metadata_params->operation_result_with_mediums = { - operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(700)); - analytics_recorder.OnRemoteEndpointRejected(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(900)); - analytics_recorder.OnLocalEndpointRejected(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(1000)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(1100)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_3); - GetFakeClock().FastForward(absl::Milliseconds(1200)); - analytics_recorder.OnLocalEndpointRejected(endpoint_id_3); - GetFakeClock().FastForward(absl::Milliseconds(1300)); - analytics_recorder.OnRemoteEndpointRejected(endpoint_id_3); - GetFakeClock().FastForward(absl::Milliseconds(1400)); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 10500 - strategy_session { - duration_millis: 10400 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 10400 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLE - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - received_connection_request { - duration_millis: 700 - request_delay_millis: 200 - local_response: ACCEPTED - remote_response: ACCEPTED - } - received_connection_request { - duration_millis: 1300 - request_delay_millis: 1400 - local_response: ACCEPTED - remote_response: REJECTED - } - received_connection_request { - duration_millis: 1900 - request_delay_millis: 3500 - local_response: REJECTED - remote_response: ACCEPTED - } - received_connection_request { - duration_millis: 2500 - request_delay_millis: 6500 - local_response: REJECTED - remote_response: REJECTED - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, DiscoveryConnectionRequestsWorks) { - std::string endpoint_id_0 = "endpoint_id_0"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - std::string endpoint_id_3 = "endpoint_id_3"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLUETOOTH); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - discovery_metadata_params->operation_result_with_mediums = {operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - discovery_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionRequestSent(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnConnectionRequestSent(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(700)); - analytics_recorder.OnRemoteEndpointRejected(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.OnConnectionRequestSent(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(900)); - analytics_recorder.OnLocalEndpointRejected(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(1000)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(1100)); - - analytics_recorder.OnConnectionRequestSent(endpoint_id_3); - GetFakeClock().FastForward(absl::Milliseconds(1200)); - analytics_recorder.OnLocalEndpointRejected(endpoint_id_3); - GetFakeClock().FastForward(absl::Milliseconds(1300)); - analytics_recorder.OnRemoteEndpointRejected(endpoint_id_3); - GetFakeClock().FastForward(absl::Milliseconds(1400)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 10500 - strategy_session { - duration_millis: 10400 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 10400 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: FINISH_SESSION_STOP_DISCOVERING - sent_connection_request { - duration_millis: 700 - request_delay_millis: 200 - local_response: ACCEPTED - remote_response: ACCEPTED - } - sent_connection_request { - duration_millis: 1300 - request_delay_millis: 1400 - local_response: ACCEPTED - remote_response: REJECTED - } - sent_connection_request { - duration_millis: 1900 - request_delay_millis: 3500 - local_response: REJECTED - remote_response: ACCEPTED - } - sent_connection_request { - duration_millis: 2500 - request_delay_millis: 6500 - local_response: REJECTED - remote_response: REJECTED - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, - AdvertiserUnfinishedConnectionRequestsIncludedAsIgnored) { - std::string endpoint_id_0 = "endpoint_id_0"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLUETOOTH); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - advertising_metadata_params->operation_result_with_mediums = { - operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - // Ignored by local. - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(400)); - - // Ignored by remote. - analytics_recorder.OnConnectionRequestReceived(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(600)); - - // Ignored by both. - analytics_recorder.OnConnectionRequestReceived(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(700)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 2800 - strategy_session { - duration_millis: 2700 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 2700 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - received_connection_request { - duration_millis: 2500 - request_delay_millis: 200 - local_response: IGNORED - remote_response: ACCEPTED - } - received_connection_request { - duration_millis: 1800 - request_delay_millis: 900 - local_response: ACCEPTED - remote_response: IGNORED - } - received_connection_request { - duration_millis: 700 - request_delay_millis: 2000 - local_response: IGNORED - remote_response: IGNORED - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, - DiscovererUnfinishedConnectionRequestsIncludedAsIgnored) { - std::string endpoint_id_0 = "endpoint_id_0"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLUETOOTH); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - discovery_metadata_params->operation_result_with_mediums = {operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - discovery_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - - // Ignored by local. - analytics_recorder.OnConnectionRequestSent(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(400)); - - // Ignored by remote. - analytics_recorder.OnConnectionRequestSent(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(600)); - - // Ignored by both. - analytics_recorder.OnConnectionRequestSent(endpoint_id_2); - GetFakeClock().FastForward(absl::Milliseconds(700)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 2800 - strategy_session { - duration_millis: 2700 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 2700 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - stop_reason: FINISH_SESSION_STOP_DISCOVERING - sent_connection_request { - duration_millis: 2500 - request_delay_millis: 200 - local_response: IGNORED - remote_response: ACCEPTED - } - sent_connection_request { - duration_millis: 1800 - request_delay_millis: 900 - local_response: ACCEPTED - remote_response: IGNORED - } - sent_connection_request { - duration_millis: 700 - request_delay_millis: 2000 - local_response: IGNORED - remote_response: IGNORED - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, SuccessfulIncomingConnectionAttempt) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - ConnectionsLog::OperationResultWithMedium operation_result; - operation_result.set_medium(BLUETOOTH); - operation_result.set_result_code(OperationResultCode::DETAIL_SUCCESS); - operation_result.set_result_category( - OperationResultCategory::CATEGORY_SUCCESS); - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - advertising_metadata_params->operation_result_with_mediums = { - operation_result}; - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - - auto connections_attempt_metadata_params = - std::make_unique(); - connections_attempt_metadata_params->operation_result_code = - OperationResultCode::DETAIL_SUCCESS; - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnIncomingConnectionAttempt( - INITIAL, BLUETOOTH, RESULT_SUCCESS, absl::Duration{}, - /*connection_token=*/"", connections_attempt_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(400)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 1000 - strategy_session { - duration_millis: 900 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 500 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - adv_dis_result { - medium: BLUETOOTH - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - connection_attempt { - duration_millis: 0 - type: INITIAL - direction: INCOMING - medium: BLUETOOTH - attempt_result: RESULT_SUCCESS - connection_token: "" - connection_attempt_metadata { - technology: CONNECTION_TECHNOLOGY_UNKNOWN_TECHNOLOGY - band: CONNECTION_BAND_UNKNOWN_BAND - frequency: -1 - network_operator: "" - country_code: "" - is_tdls_used: false - try_counts: 0 - wifi_hotspot_status: false - max_tx_speed: 0 - max_rx_speed: 0 - wifi_channel_width: -1 - } - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, - FailedConnectionAttemptUpdatesConnectionRequestNotSent) { - std::string endpoint_id = "endpoint_id"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto connections_attempt_metadata_params = - analytics_recorder.BuildConnectionAttemptMetadataParams( - ::location::nearby::proto::connections:: - CONNECTION_TECHNOLOGY_HOTSPOT_LOCALONLY, - ::location::nearby::proto::connections:: - CONNECTION_BAND_WIFI_BAND_6GHZ, - /*frequency*/ 2400, /*try_count*/ 0, /*network_operator*/ {}, - /*country_code*/ {}, /*is_tdls_used*/ false, - /*wifi_hotspot_enabled*/ false, /*max_wifi_tx_speed*/ 0, - /*max_wifi_rx_speed*/ 0, /*channel_width*/ 0, - OperationResultCode::CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE); - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - discovery_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionRequestSent(endpoint_id); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnOutgoingConnectionAttempt( - endpoint_id, INITIAL, BLUETOOTH, RESULT_ERROR, absl::Duration{}, - /*connection_token=*/"", connections_attempt_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(400)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 1000 - strategy_session { - duration_millis: 900 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 900 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_DISCOVERING - sent_connection_request { - duration_millis: 300 - request_delay_millis: 200 - local_response: NOT_SENT - remote_response: NOT_SENT - } - } - connection_attempt { - duration_millis: 0 - type: INITIAL - direction: OUTGOING - medium: BLUETOOTH - attempt_result: RESULT_ERROR - connection_token: "" - connection_attempt_metadata { - technology: CONNECTION_TECHNOLOGY_HOTSPOT_LOCALONLY - band: CONNECTION_BAND_WIFI_BAND_6GHZ - frequency: 2400 - network_operator: "" - country_code: "" - is_tdls_used: false - try_counts: 0 - wifi_hotspot_status: false - max_tx_speed: 0 - max_rx_speed: 0 - wifi_channel_width: 0 - } - operation_result { - result_category: CATEGORY_CONNECTIVITY_ERROR - result_code: CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, - UnfinishedEstablishedConnectionsAddedAsUnfinished) { - std::string endpoint_id = "endpoint_id"; - std::string connection_token = "connection_token"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionEstablished(endpoint_id, BLUETOOTH, - connection_token); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnConnectionClosed( - endpoint_id, BLUETOOTH, UPGRADED, - ConnectionsLog::EstablishedConnection::UNKNOWN_SAFE_DISCONNECTION_RESULT); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnConnectionEstablished(endpoint_id, WIFI_LAN, - connection_token); - GetFakeClock().FastForward(absl::Milliseconds(500)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 1500 - strategy_session { - duration_millis: 1400 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 1400 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - established_connection { - duration_millis: 300 - medium: BLUETOOTH - disconnection_reason: UPGRADED - connection_token: "connection_token" - safe_disconnection_result: UNKNOWN_SAFE_DISCONNECTION_RESULT - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - established_connection { - duration_millis: 500 - medium: WIFI_LAN - disconnection_reason: UNFINISHED - connection_token: "connection_token" - safe_disconnection_result: SAFE_DISCONNECTION - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, OutgoingPayloadUpgraded) { - std::string endpoint_id = "endpoint_id"; - std::int64_t payload_id = 123456789; - std::string connection_token = "connection_token"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionEstablished(endpoint_id, BLUETOOTH, - connection_token); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnOutgoingPayloadStarted( - {endpoint_id}, payload_id, connections::PayloadType::kFile, 50); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnPayloadChunkSent(endpoint_id, payload_id, 10); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnPayloadChunkSent(endpoint_id, payload_id, 10); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnConnectionClosed( - endpoint_id, BLUETOOTH, UPGRADED, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); - GetFakeClock().FastForward(absl::Milliseconds(700)); - analytics_recorder.OnConnectionEstablished(endpoint_id, WIFI_LAN, - connection_token); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.OnPayloadChunkSent(endpoint_id, payload_id, 10); - GetFakeClock().FastForward(absl::Milliseconds(900)); - analytics_recorder.OnPayloadChunkSent(endpoint_id, payload_id, 10); - GetFakeClock().FastForward(absl::Milliseconds(1000)); - analytics_recorder.OnPayloadChunkSent(endpoint_id, payload_id, 10); - GetFakeClock().FastForward(absl::Milliseconds(1100)); - analytics_recorder.OnOutgoingPayloadDone(endpoint_id, payload_id, SUCCESS, - OperationResultCode::DETAIL_SUCCESS); - GetFakeClock().FastForward(absl::Milliseconds(1200)); - analytics_recorder.OnConnectionClosed( - endpoint_id, WIFI_LAN, LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); - GetFakeClock().FastForward(absl::Milliseconds(1300)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 9100 - strategy_session { - duration_millis: 9000 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 9000 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - established_connection { - duration_millis: 1800 - medium: BLUETOOTH - sent_payload { - duration_millis: 1500 - type: FILE - total_size_bytes: 50 - num_bytes_transferred: 20 - num_chunks: 2 - status: MOVED_TO_NEW_MEDIUM - operation_result { - result_category: CATEGORY_MISCELLANEOUS - result_code: MISCELLEANEOUS_MOVE_TO_NEW_MEDIUM - } - } - disconnection_reason: UPGRADED - connection_token: "connection_token" - safe_disconnection_result: SAFE_DISCONNECTION - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - established_connection { - duration_millis: 5000 - medium: WIFI_LAN - sent_payload { - duration_millis: 4500 - type: FILE - total_size_bytes: 50 - num_bytes_transferred: 30 - num_chunks: 3 - status: SUCCESS - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - disconnection_reason: LOCAL_DISCONNECTION - connection_token: "connection_token" - safe_disconnection_result: SAFE_DISCONNECTION - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, UpgradeAttemptWorks) { - std::string endpoint_id = "endpoint_id"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - std::string connection_token = "connection_token"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - - analytics_recorder.OnBandwidthUpgradeStarted(endpoint_id, BLE, WIFI_LAN, - INCOMING, connection_token); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - analytics_recorder.OnBandwidthUpgradeStarted( - endpoint_id_1, BLUETOOTH, WIFI_LAN, INCOMING, connection_token); - // Error to upgrade. - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnBandwidthUpgradeError( - endpoint_id, WIFI_LAN_MEDIUM_ERROR, WIFI_LAN_SOCKET_CREATION, - OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL); - // Success to upgrade. - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnBandwidthUpgradeSuccess(endpoint_id_1); - // Upgrade is unfinished. - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnBandwidthUpgradeStarted( - endpoint_id_2, BLUETOOTH, WIFI_LAN, INCOMING, connection_token); - GetFakeClock().FastForward(absl::Milliseconds(700)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 2800 - strategy_session { - duration_millis: 2700 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 2700 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - upgrade_attempt { - duration_millis: 700 - direction: INCOMING - from_medium: BLE - to_medium: WIFI_LAN - upgrade_result: WIFI_LAN_MEDIUM_ERROR - error_stage: WIFI_LAN_SOCKET_CREATION - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_CONNECTIVITY_ERROR - result_code: CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL - } - } - upgrade_attempt { - duration_millis: 900 - direction: INCOMING - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UPGRADE_RESULT_SUCCESS - error_stage: UPGRADE_SUCCESS - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - upgrade_attempt { - duration_millis: 700 - direction: INCOMING - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UNFINISHED_ERROR - error_stage: UPGRADE_UNFINISHED - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_DEVICE_STATE_ERROR - result_code: DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, StartListeningForIncomingConnectionsWorks) { - std::string endpoint_id = "endpoint_id"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - std::string connection_token = "connection_token"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartedIncomingConnectionListening( - connections::Strategy::kP2pStar); - GetFakeClock().FastForward(absl::Milliseconds(200)); - - analytics_recorder.OnBandwidthUpgradeStarted(endpoint_id, BLE, WIFI_LAN, - INCOMING, connection_token); - - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnBandwidthUpgradeStarted( - endpoint_id_1, BLUETOOTH, WIFI_LAN, INCOMING, connection_token); - GetFakeClock().FastForward(absl::Milliseconds(400)); - // Error to upgrade. - analytics_recorder.OnBandwidthUpgradeError( - endpoint_id, WIFI_LAN_MEDIUM_ERROR, WIFI_LAN_SOCKET_CREATION, - OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL); - GetFakeClock().FastForward(absl::Milliseconds(500)); - // Success to upgrade. - analytics_recorder.OnBandwidthUpgradeSuccess(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(600)); - - analytics_recorder.LogSession(); - // ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 2100 - strategy_session { - duration_millis: 2000 - strategy: P2P_STAR - role: ADVERTISER - upgrade_attempt { - direction: INCOMING - duration_millis: 700 - from_medium: BLE - to_medium: WIFI_LAN - upgrade_result: WIFI_LAN_MEDIUM_ERROR - error_stage: WIFI_LAN_SOCKET_CREATION - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_CONNECTIVITY_ERROR - result_code: CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL - } - } - upgrade_attempt { - direction: INCOMING - duration_millis: 900 - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UPGRADE_RESULT_SUCCESS - error_stage: UPGRADE_SUCCESS - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -TEST_F(AnalyticsRecorderTest, SetErrorCodeFieldsCorrectly) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{WEB_RTC}, - discovery_metadata_params.get()); - - ErrorCodeParams error_code_params = ErrorCodeRecorder::BuildErrorCodeParams( - WEB_RTC, DISCONNECT, DISCONNECT_NETWORK_FAILED, - TACHYON_SEND_MESSAGE_STATUS_EXCEPTION, "", "connection_token"); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnErrorCode(error_code_params); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ErrorCode error_code_proto = ParseTextProtoOrDie(R"pb( - medium: WEB_RTC - event: DISCONNECT - description: TACHYON_SEND_MESSAGE_STATUS_EXCEPTION - disconnect_error: DISCONNECT_NETWORK_FAILED - connection_token: "connection_token" - )pb"); - - EXPECT_THAT(event_logger.GetErrorCode(), EqualsProto(error_code_proto)); -} - -TEST_F(AnalyticsRecorderTest, - SetErrorCodeFieldsCorrectlyForUnknownDescription) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{BLUETOOTH}, - discovery_metadata_params.get()); - - ErrorCodeParams error_code_params; - // Skip setting error_code_params.description - error_code_params.medium = BLUETOOTH; - error_code_params.event = START_DISCOVERING; - error_code_params.start_discovering_error = START_EXTENDED_DISCOVERING_FAILED; - error_code_params.connection_token = "connection_token"; - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnErrorCode(error_code_params); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ErrorCode error_code_proto = ParseTextProtoOrDie(R"pb( - medium: BLUETOOTH - event: START_DISCOVERING - description: UNKNOWN - start_discovering_error: START_EXTENDED_DISCOVERING_FAILED - connection_token: "connection_token" - )pb"); - - EXPECT_THAT(event_logger.GetErrorCode(), EqualsProto(error_code_proto)); -} - -TEST_F(AnalyticsRecorderTest, SetErrorCodeFieldsCorrectlyForCommonError) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{BLUETOOTH}, - discovery_metadata_params.get()); - - ErrorCodeParams error_code_params = ErrorCodeRecorder::BuildErrorCodeParams( - BLUETOOTH, START_DISCOVERING, INVALID_PARAMETER, - NULL_BLUETOOTH_DEVICE_NAME, "", "connection_token"); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnErrorCode(error_code_params); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ErrorCode error_code_proto = ParseTextProtoOrDie(R"pb( - medium: BLUETOOTH - event: START_DISCOVERING - description: NULL_BLUETOOTH_DEVICE_NAME - common_error: INVALID_PARAMETER - connection_token: "connection_token" - )pb"); - - EXPECT_THAT(event_logger.GetErrorCode(), EqualsProto(error_code_proto)); -} - -TEST_F(AnalyticsRecorderTest, CheckIfSessionWasLogged) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - GetFakeClock().FastForward(absl::Milliseconds(100)); - // LogSession to count down client_session_done_latch. - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - EXPECT_TRUE(analytics_recorder.IsSessionLogged()); -} - -TEST_F(AnalyticsRecorderTest, ConstructAnalyticsRecorder) { - CountDownLatch client_session_done_latch(0); - CountDownLatch start_client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch, - &start_client_session_done_latch); - - // Call the constructor to count down the session_done_latch. - AnalyticsRecorder analytics_recorder(&event_logger); - ASSERT_TRUE(start_client_session_done_latch.Await(kDefaultTimeout).result()); - - std::vector event_types = event_logger.GetLoggedEventTypes(); - EXPECT_EQ(event_types.size(), 1); - EXPECT_THAT(event_types, Contains(START_CLIENT_SESSION).Times(1)); -} - -TEST_F( - AnalyticsRecorderTest, - StartClientSessionOnlyLoggedOnceWorksAfterAnalyticsRecorderIsConstructed) { - CountDownLatch client_session_done_latch(0); - CountDownLatch start_client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch, - &start_client_session_done_latch); - - // Call the constructor to count down the start_client_session_done_latch. - AnalyticsRecorder analytics_recorder(&event_logger); - ASSERT_TRUE(start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // Log start client session once. - EXPECT_THAT(event_logger.GetLoggedEventTypes(), - Contains(START_CLIENT_SESSION).Times(1)); - - // Reset the start_client_session_done_latch. However, LogStartSession cannot - // count down the start_client_session_done_latch. - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - analytics_recorder.LogStartSession(); - ASSERT_FALSE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // No more start client session was logged. - EXPECT_THAT(event_logger.GetLoggedEventTypes(), - Contains(START_CLIENT_SESSION).Times(1)); -} - -TEST_F(AnalyticsRecorderTest, - CanLogStartClientSessionOnceAgainAfterSessionWasLogged) { - CountDownLatch client_session_done_latch(0); - CountDownLatch start_client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch, - &start_client_session_done_latch); - - // Call the constructor to count down the start_client_session_done_latch. - AnalyticsRecorder analytics_recorder(&event_logger); - ASSERT_TRUE(start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // Log start client session once. - EXPECT_THAT(event_logger.GetLoggedEventTypes(), - Contains(START_CLIENT_SESSION).Times(1)); - - // Reset the client_session_done_latch. Call LogSession to count down the - // client_session_done_latch. - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - // Reset the start_client_session_done_latch. Call LogStartSession to count - // down the start_client_session_done_latch. - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - analytics_recorder.LogStartSession(); - analytics_recorder.LogStartSession(); - analytics_recorder.LogStartSession(); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // Can log start client session once again. - EXPECT_THAT(event_logger.GetLoggedEventTypes(), - Contains(START_CLIENT_SESSION).Times(2)); -} - -TEST_F(AnalyticsRecorderTest, - ClearcIncomingConnectionRequestsAfterSessionWasLogged) { - std::string endpoint_id_0 = "endpoint_id_0"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(500)); - - // LogSession - analytics_recorder.LogSession(); // call ResetClientSessionLoggingResouces - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto1 = - ParseTextProtoOrDie(R"pb( - duration_millis: 1500 - strategy_session { - duration_millis: 1400 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 1400 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - received_connection_request { - duration_millis: 700 - request_delay_millis: 200 - local_response: ACCEPTED - remote_response: ACCEPTED - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - std::string endpoint_id_1 = "endpoint_id_1"; - GetFakeClock().FastForward(absl::Milliseconds(700)); - analytics_recorder.OnConnectionRequestReceived(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(900)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(1000)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(new_client_session_done_latch.Await(kDefaultTimeout).result()); - - // - if the current_strategy_session_ and current_advertising_phase_ are not - // reset, the duplicate advertising_phase (with the additional - // received_connection_request) will append to the strategy_session) - ConnectionsLog::ClientSession strategy_session_proto2 = ParseTextProtoOrDie( - R"pb( - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - received_connection_request { - duration_millis: 0 - request_delay_millis: 0 - local_response: ACCEPTED - remote_response: ACCEPTED - } - } - advertising_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - received_connection_request { - duration_millis: 0 - request_delay_millis: 0 - local_response: ACCEPTED - remote_response: ACCEPTED - } - received_connection_request { - duration_millis: 0 - request_delay_millis: 0 - local_response: ACCEPTED - remote_response: ACCEPTED - } - } - })pb"); - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto2))); -} - -TEST_F(AnalyticsRecorderTest, - ClearcOutgoingConnectionRequestsAfterSessionWasLogged) { - std::string endpoint_id_0 = "endpoint_id_0"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - discovery_metadata_params.get()); - - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionRequestSent(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_0); - GetFakeClock().FastForward(absl::Milliseconds(500)); - - // LogSession - analytics_recorder.LogSession(); // call ResetClientSessionLoggingResouces - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto1 = - ParseTextProtoOrDie(R"pb( - duration_millis: 1500 - strategy_session { - duration_millis: 1400 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 1400 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_DISCOVERING - sent_connection_request { - duration_millis: 700 - request_delay_millis: 200 - local_response: ACCEPTED - remote_response: ACCEPTED - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - std::string endpoint_id_1 = "endpoint_id_1"; - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnConnectionRequestSent(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(700)); - analytics_recorder.OnLocalEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.OnRemoteEndpointAccepted(endpoint_id_1); - GetFakeClock().FastForward(absl::Milliseconds(900)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - // - if the current_strategy_session_ and current_discovery_phase_ are - // not reset, the duplicate discovery_phase (with the additional - // sent_connection_request) will append to the strategy_session) - ConnectionsLog::ClientSession strategy_session_proto2 = - ParseTextProtoOrDie(R"pb( - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - sent_connection_request { - duration_millis: 0 - request_delay_millis: 0 - local_response: ACCEPTED - remote_response: ACCEPTED - } - } - discovery_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - sent_connection_request { - duration_millis: 0 - request_delay_millis: 0 - local_response: ACCEPTED - remote_response: ACCEPTED - } - sent_connection_request { - duration_millis: 0 - request_delay_millis: 0 - local_response: ACCEPTED - remote_response: ACCEPTED - } - } - })pb"); - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto2))); -} - -TEST_F(AnalyticsRecorderTest, ClearcActiveConnectionsAfterSessionWasLogged) { - connections::Strategy strategy = connections::Strategy::kP2pStar; - std::vector mediums = {BLE, BLUETOOTH}; - std::string endpoint_id = "endpoint_id"; - std::string connection_token = "connection_token"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(strategy, mediums, - advertising_metadata_params.get()); - - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnConnectionEstablished(endpoint_id, BLUETOOTH, - connection_token); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - // LogSession - analytics_recorder.LogSession(); // call ResetClientSessionLoggingResouces - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - ConnectionsLog::ClientSession strategy_session_proto1 = - ParseTextProtoOrDie(R"pb( - duration_millis: 600 - strategy_session { - duration_millis: 500 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 500 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - established_connection { - duration_millis: 300 - medium: BLUETOOTH - disconnection_reason: UNFINISHED - connection_token: "connection_token" - safe_disconnection_result: SAFE_DISCONNECTION - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - // - if the current_strategy_session_ and advertising_phase_ are not - // reset, the duplicate advertising_phase_ (with the additional - // will append to the strategy_session), and the active connection (i.e. - // established_connection) will stay there. - ConnectionsLog::ClientSession strategy_session_proto2 = - ParseTextProtoOrDie(R"pb( - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - } - advertising_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - } - established_connection { - duration_millis: 0 - medium: BLUETOOTH - disconnection_reason: UNFINISHED - connection_token: "connection_token" - safe_disconnection_result: SAFE_DISCONNECTION - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto2))); -} - -TEST_F(AnalyticsRecorderTest, - ClearBandwidthUpgradeAttemptsAfterSessionWasLogged) { - std::string endpoint_id = "endpoint_id"; - std::string endpoint_id_1 = "endpoint_id_1"; - std::string endpoint_id_2 = "endpoint_id_2"; - std::string connection_token = "connection_token"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnBandwidthUpgradeStarted(endpoint_id, BLE, WIFI_LAN, - INCOMING, connection_token); - - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnBandwidthUpgradeStarted( - endpoint_id_1, BLUETOOTH, WIFI_LAN, INCOMING, connection_token); - // - Error to upgrade. - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnBandwidthUpgradeError( - endpoint_id, WIFI_LAN_MEDIUM_ERROR, WIFI_LAN_SOCKET_CREATION, - OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL); - // - Success to upgrade. - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnBandwidthUpgradeSuccess(endpoint_id_1); - - // - Upgrade is unfinished. - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnBandwidthUpgradeStarted( - endpoint_id_2, BLUETOOTH, WIFI_LAN, INCOMING, connection_token); - - GetFakeClock().FastForward(absl::Milliseconds(700)); - // LogSession - analytics_recorder.LogSession(); // call ResetClientSessionLoggingResouces - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - // - if the current_strategy_session_ and advertising_phase_ are not - // reset, the duplicate advertising_phase_, and the upgrade_attempts (i.e. - // bandwidth_upgrade_attempts_) will stay there. - ConnectionsLog::ClientSession strategy_session_proto1 = - ParseTextProtoOrDie(R"pb( - duration_millis: 2800 - strategy_session { - duration_millis: 2700 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 2700 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - upgrade_attempt { - direction: INCOMING - duration_millis: 700 - from_medium: BLE - to_medium: WIFI_LAN - upgrade_result: WIFI_LAN_MEDIUM_ERROR - error_stage: WIFI_LAN_SOCKET_CREATION - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_CONNECTIVITY_ERROR - result_code: CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL - } - } - upgrade_attempt { - direction: INCOMING - duration_millis: 900 - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UPGRADE_RESULT_SUCCESS - error_stage: UPGRADE_SUCCESS - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - upgrade_attempt { - direction: INCOMING - duration_millis: 700 - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UNFINISHED_ERROR - error_stage: UPGRADE_UNFINISHED - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_DEVICE_STATE_ERROR - result_code: DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS - } - } - })pb"); - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(800)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(900)); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto2 = - ParseTextProtoOrDie(R"pb( - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - } - advertising_phase { - duration_millis: 0 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - } - upgrade_attempt { - direction: INCOMING - from_medium: BLE - to_medium: WIFI_LAN - upgrade_result: WIFI_LAN_MEDIUM_ERROR - error_stage: WIFI_LAN_SOCKET_CREATION - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_CONNECTIVITY_ERROR - result_code: CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL - } - } - upgrade_attempt { - direction: INCOMING - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UPGRADE_RESULT_SUCCESS - error_stage: UPGRADE_SUCCESS - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_SUCCESS - result_code: DETAIL_SUCCESS - } - } - upgrade_attempt { - direction: INCOMING - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UNFINISHED_ERROR - error_stage: UPGRADE_UNFINISHED - connection_token: "connection_token" - operation_result { - result_category: CATEGORY_DEVICE_STATE_ERROR - result_code: DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS - } - } - })pb"); - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto2))); -} - -// Test if current_strategy_ is reset by checking if the same strategy would -// be logged for different client sessions or not. If yes, it should be logged. -// Otherwise, not. -TEST_F(AnalyticsRecorderTest, - CanLogSeparateStartStrategySessionForSameStrategyAfterSessionWasLogged) { - connections::Strategy strategy = connections::Strategy::kP2pStar; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStopAdvertising(); - - GetFakeClock().FastForward(absl::Milliseconds(300)); - // LogSession - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - // The same strategy session shouldn't be logged again with the same client - // session. - EXPECT_THAT(event_logger.GetLoggedEventTypes(), - Contains(START_STRATEGY_SESSION).Times(1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnStartAdvertising(strategy, /*mediums=*/{BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(700)); - - analytics_recorder.LogSession(); - ASSERT_TRUE(new_client_session_done_latch.Await(kDefaultTimeout).result()); - - EXPECT_THAT(event_logger.GetLoggedEventTypes(), - Contains(START_STRATEGY_SESSION).Times(2)); -} - -// Test if current_strategy_session_ is reset. If not, the same strategy session -// proto will be logged. -TEST_F(AnalyticsRecorderTest, - NotLogSameStrategySessionProtoAfterSessionWasLogged) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - // Via OnStartAdvertising, current_strategy_session_is set in - // UpdateStrategySessionLocked. - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(300)); - // LogSession - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 600 - strategy_session { - duration_millis: 500 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 200 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - // - if current_strategy_session_ is reset, the same - // strategy_session_proto will be logged. - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.LogSession(); - ASSERT_TRUE(new_client_session_done_latch.Await(kDefaultTimeout).result()); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto))); -} - -// Test if current_advertising_phase_ is reset. -TEST_F(AnalyticsRecorderTest, - NotLogDuplicateAdvertisingPhaseAfterSessionWasLogged) { - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising( - connections::Strategy::kP2pStar, - /*mediums=*/{BLUETOOTH}, - advertising_metadata_params.get()); // set current_advertising_phase_ - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - // LogSession - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto1 = - ParseTextProtoOrDie(R"pb( - duration_millis: 600 - strategy_session { - duration_millis: 500 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 200 - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - // - if the current_strategy_session_ and current_advertising_phase_ are - // not reset, the same strategy_session with two same advertising_phase will - // be logged. - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto2 = - ParseTextProtoOrDie(R"pb( - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 0 - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - } - advertising_phase { - duration_millis: 0 - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - } - })pb"); - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto2))); -} - -// Test if current_discovery_phase_ is reset. -TEST_F(AnalyticsRecorderTest, - NotLogDuplicateDiscoveryPhaseAfterSessionWasLogged) { - connections::Strategy strategy = connections::Strategy::kP2pStar; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - auto discovery_metadata_params = - analytics_recorder.BuildDiscoveryMetadataParams( - /*is_extended_advertisement_supported*/ true, - /*connected_ap_frequency*/ 1, /*is_nfc_available=*/false); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartDiscovery( - strategy, {BLUETOOTH}, - discovery_metadata_params.get()); // set current_discovery_phase_ - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStopDiscovery(); - GetFakeClock().FastForward(absl::Milliseconds(300)); - analytics_recorder.OnEndpointFound(BLUETOOTH); - GetFakeClock().FastForward(absl::Milliseconds(400)); - // LogSession - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto1 = - ParseTextProtoOrDie(R"pb( - duration_millis: 1000 - strategy_session { - duration_millis: 900 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 200 - medium: BLUETOOTH - discovered_endpoint { - medium: BLUETOOTH - latency_millis: 500 - } - discovery_metadata { - supports_extended_ble_advertisements: true - connected_ap_frequency: 1 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_DISCOVERING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto1)); - - // LogStartSession - CountDownLatch new_start_client_session_done_latch(1); - event_logger.SetStartClientSessionDoneLatchPtr( - &new_start_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.LogStartSession(); - ASSERT_TRUE( - new_start_client_session_done_latch.Await(kDefaultTimeout).result()); - - // LogSession again - // - if the current_strategy_session_ and current_discovery_phase_ are not - // reset, the same strategy_session with two same discovery_phase will be - // logged. - CountDownLatch new_client_session_done_latch(1); - event_logger.SetClientSessionDoneLatch(new_client_session_done_latch); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto2 = - ParseTextProtoOrDie(R"pb( - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_STAR - role: DISCOVERER - discovery_phase { - duration_millis: 0 - medium: BLUETOOTH - discovered_endpoint { medium: BLUETOOTH } - discovery_metadata { - supports_extended_ble_advertisements: true - connected_ap_frequency: 1 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_DISCOVERING - } - discovery_phase { - duration_millis: 0 - medium: BLUETOOTH - discovery_metadata { - supports_extended_ble_advertisements: true - connected_ap_frequency: 1 - supports_nfc_technology: false - } - } - })pb"); - EXPECT_THAT(event_logger.GetLoggedClientSession(), - Not(EqualsProto(strategy_session_proto2))); -} - -TEST_F(AnalyticsRecorderTest, - NotAddNewConnectionWithoutCallingOnStartAdvertising) { - std::string endpoint_id = "endpoint_id"; - - CountDownLatch client_session_done_latch(1); - FakeEventLogger event_logger(client_session_done_latch); - AnalyticsRecorder analytics_recorder(&event_logger); - - // via OnStartAdvertising, current_strategy_session_ is set in - // UpdateStrategySessionLocked. - auto advertising_metadata_params = - analytics_recorder.BuildAdvertisingMetadataParams(); - GetFakeClock().FastForward(absl::Milliseconds(100)); - analytics_recorder.OnStartAdvertising(connections::Strategy::kP2pStar, - /*mediums=*/{BLE, BLUETOOTH}, - advertising_metadata_params.get()); - GetFakeClock().FastForward(absl::Milliseconds(200)); - analytics_recorder.OnStopAdvertising(); - GetFakeClock().FastForward(absl::Milliseconds(300)); - - // LogSession - analytics_recorder.LogSession(); - ASSERT_TRUE(client_session_done_latch.Await(kDefaultTimeout).result()); - - ConnectionsLog::ClientSession strategy_session_proto = - ParseTextProtoOrDie(R"pb( - duration_millis: 600 - strategy_session { - duration_millis: 500 - strategy: P2P_STAR - role: ADVERTISER - advertising_phase { - duration_millis: 200 - medium: BLE - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: CLIENT_STOP_ADVERTISING - } - })pb"); - - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); - - // Without calling OnStartAdvertising won't create new - // current_strategy_session_. - GetFakeClock().FastForward(absl::Milliseconds(400)); - analytics_recorder.OnConnectionEstablished(endpoint_id, BLUETOOTH, - /*connection_token=*/""); - GetFakeClock().FastForward(absl::Milliseconds(500)); - analytics_recorder.OnConnectionClosed( - endpoint_id, BLUETOOTH, UPGRADED, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); - GetFakeClock().FastForward(absl::Milliseconds(600)); - analytics_recorder.LogSession(); - - // The proto won't change. - EXPECT_THAT(event_logger.GetLoggedClientSession(), - EqualsProto(strategy_session_proto)); -} - -} // namespace -} // namespace analytics -} // namespace nearby diff --git a/connections/implementation/analytics/discovery_metadata_params.h b/connections/implementation/analytics/discovery_metadata_params.h index 6442b03c..b90b2703 100644 --- a/connections/implementation/analytics/discovery_metadata_params.h +++ b/connections/implementation/analytics/discovery_metadata_params.h @@ -17,7 +17,7 @@ #include -#include "internal/proto/analytics/connections_log.pb.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" namespace nearby { @@ -26,8 +26,7 @@ struct DiscoveryMetadataParams { bool is_extended_advertisement_supported = false; int connected_ap_frequency = 0; bool is_nfc_available = false; - std::vector + std::vector operation_result_with_mediums = {}; }; diff --git a/connections/implementation/analytics/mock_analytics_recorder.h b/connections/implementation/analytics/mock_analytics_recorder.h new file mode 100644 index 00000000..d407d98b --- /dev/null +++ b/connections/implementation/analytics/mock_analytics_recorder.h @@ -0,0 +1,196 @@ +// Copyright 2026 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 ANALYTICS_MOCK_ANALYTICS_RECORDER_H_ +#define ANALYTICS_MOCK_ANALYTICS_RECORDER_H_ + +#include +#include +#include + +#include "gmock/gmock.h" +#include "absl/time/time.h" +#include "connections/implementation/analytics/advertising_metadata_params.h" +#include "connections/implementation/analytics/analytics_recorder.h" +#include "connections/implementation/analytics/connection_attempt_metadata_params.h" +#include "connections/implementation/analytics/discovery_metadata_params.h" +#include "connections/payload_type.h" +#include "connections/strategy.h" +#include "internal/platform/error_code_params.h" +#include "proto/connections_enums.pb.h" + +namespace nearby::analytics { + +class MockAnalyticsRecorder : public AnalyticsRecorder { + public: + MockAnalyticsRecorder() = default; + ~MockAnalyticsRecorder() override = default; + + // Advertising phase + MOCK_METHOD(void, OnStartAdvertising, + (connections::Strategy strategy, + const std::vector& + mediums, + AdvertisingMetadataParams* advertising_metadata_params), + (override)); + MOCK_METHOD(void, OnStopAdvertising, (), (override)); + + MOCK_METHOD(int, GetNextAdvertisingUpdateIndex, (), (override)); + + // Connection listening + MOCK_METHOD(void, OnStartedIncomingConnectionListening, + (connections::Strategy strategy), (override)); + MOCK_METHOD(void, OnStoppedIncomingConnectionListening, (), (override)); + + // Discovery phase + MOCK_METHOD(void, OnStartDiscovery, + (connections::Strategy strategy, + const std::vector& + mediums, + DiscoveryMetadataParams* discovery_metadata_params), + (override)); + MOCK_METHOD(void, OnStopDiscovery, (), (override)); + + MOCK_METHOD(int, GetNextDiscoveryUpdateIndex, (), (override)); + MOCK_METHOD(void, OnEndpointFound, + (location::nearby::proto::connections::Medium medium), + (override)); + + // Connection request + MOCK_METHOD(void, OnRequestConnection, + (const connections::Strategy& strategy, + const std::string& endpoint_id), + (override)); + + MOCK_METHOD(void, OnConnectionRequestReceived, + (const std::string& remote_endpoint_id), (override)); + MOCK_METHOD(void, OnConnectionRequestSent, + (const std::string& remote_endpoint_id), (override)); + MOCK_METHOD(void, OnRemoteEndpointAccepted, + (const std::string& remote_endpoint_id), (override)); + MOCK_METHOD(void, OnLocalEndpointAccepted, + (const std::string& remote_endpoint_id), (override)); + MOCK_METHOD(void, OnRemoteEndpointRejected, + (const std::string& remote_endpoint_id), (override)); + MOCK_METHOD(void, OnLocalEndpointRejected, + (const std::string& remote_endpoint_id), (override)); + + // Connection attempt + MOCK_METHOD( + void, OnIncomingConnectionAttempt, + (location::nearby::proto::connections::ConnectionAttemptType type, + location::nearby::proto::connections::Medium medium, + location::nearby::proto::connections::ConnectionAttemptResult result, + absl::Duration duration, const std::string& connection_token, + ConnectionAttemptMetadataParams* connection_attempt_metadata_params), + (override)); + MOCK_METHOD( + void, OnOutgoingConnectionAttempt, + (const std::string& remote_endpoint_id, + location::nearby::proto::connections::ConnectionAttemptType type, + location::nearby::proto::connections::Medium medium, + location::nearby::proto::connections::ConnectionAttemptResult result, + absl::Duration duration, const std::string& connection_token, + ConnectionAttemptMetadataParams* connection_attempt_metadata_params), + (override)); + + // Connection established + MOCK_METHOD(void, OnConnectionEstablished, + (const std::string& endpoint_id, + location::nearby::proto::connections::Medium medium, + const std::string& connection_token), + (override)); + MOCK_METHOD(void, OnConnectionClosed, + (const std::string& endpoint_id, + location::nearby::proto::connections::Medium medium, + location::nearby::proto::connections::DisconnectionReason reason, + SafeDisconnectionResult result), + (override)); + + // Payload + MOCK_METHOD(void, OnIncomingPayloadStarted, + (const std::string& endpoint_id, std::int64_t payload_id, + connections::PayloadType type, std::int64_t total_size_bytes), + (override)); + MOCK_METHOD(void, OnPayloadChunkReceived, + (const std::string& endpoint_id, std::int64_t payload_id, + std::int64_t chunk_size_bytes), + (override)); + MOCK_METHOD(void, OnIncomingPayloadDone, + (const std::string& endpoint_id, std::int64_t payload_id, + location::nearby::proto::connections::PayloadStatus status, + location::nearby::proto::connections::OperationResultCode + operation_result_code), + (override)); + MOCK_METHOD(void, OnOutgoingPayloadStarted, + (const std::vector& endpoint_ids, + std::int64_t payload_id, connections::PayloadType type, + std::int64_t total_size_bytes), + (override)); + MOCK_METHOD(void, OnPayloadChunkSent, + (const std::string& endpoint_id, std::int64_t payload_id, + std::int64_t chunk_size_bytes), + (override)); + MOCK_METHOD(void, OnOutgoingPayloadDone, + (const std::string& endpoint_id, std::int64_t payload_id, + location::nearby::proto::connections::PayloadStatus status, + location::nearby::proto::connections::OperationResultCode + operation_result_code), + (override)); + + // BandwidthUpgrade + MOCK_METHOD(void, OnBandwidthUpgradeStarted, + (const std::string& endpoint_id, + location::nearby::proto::connections::Medium from_medium, + location::nearby::proto::connections::Medium to_medium, + location::nearby::proto::connections::ConnectionAttemptDirection + direction, + const std::string& connection_token), + (override)); + MOCK_METHOD(void, UpdateBwUpgradeNetworkInfo, + (const std::string& endpoint_id, int num_interfaces, + int num_ipv6_only_interfaces), + (override)); + MOCK_METHOD(void, OnBandwidthUpgradeError, + (const std::string& endpoint_id, + location::nearby::proto::connections::BandwidthUpgradeResult + result, + location::nearby::proto::connections::BandwidthUpgradeErrorStage + error_stage, + location::nearby::proto::connections::OperationResultCode + operation_result_code), + (override)); + MOCK_METHOD(void, OnBandwidthUpgradeSuccess, (const std::string& endpoint_id), + (override)); + + // Error Code + MOCK_METHOD(void, OnErrorCode, (const ErrorCodeParams& params), (override)); + + MOCK_METHOD(void, LogStartSession, (), (override)); + MOCK_METHOD(void, LogSession, (), (override)); + + MOCK_METHOD(bool, IsSessionLogged, (), (override)); + + MOCK_METHOD( + location::nearby::proto::connections::OperationResultCategory, + GetOperationResultCategory, + (location::nearby::proto::connections::OperationResultCode result_code), + (override)); + + MOCK_METHOD(void, Sync, (), (override)); +}; + +} // namespace nearby::analytics + +#endif // ANALYTICS_MOCK_ANALYTICS_RECORDER_H_ diff --git a/connections/implementation/analytics/operation_result_with_medium.h b/connections/implementation/analytics/operation_result_with_medium.h new file mode 100644 index 00000000..483acc14 --- /dev/null +++ b/connections/implementation/analytics/operation_result_with_medium.h @@ -0,0 +1,55 @@ +// Copyright 2026 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 ANALYTICS_OPERATION_RESULT_WITH_MEDIUM_H_ +#define ANALYTICS_OPERATION_RESULT_WITH_MEDIUM_H_ + +#include + +#include "proto/connections_enums.pb.h" + +namespace nearby::analytics { + +struct OperationResultWithMedium { + location::nearby::proto::connections::Medium medium = + location::nearby::proto::connections::UNKNOWN_MEDIUM; + std::optional update_index; + location::nearby::proto::connections::OperationResultCategory + result_category = location::nearby::proto::connections::CATEGORY_UNKNOWN; + location::nearby::proto::connections::OperationResultCode result_code = + location::nearby::proto::connections::DETAIL_UNKNOWN; + std::optional + connection_mode; + + void set_medium(location::nearby::proto::connections::Medium m) { + medium = m; + } + void set_update_index(int i) { update_index = i; } + void set_result_category( + location::nearby::proto::connections::OperationResultCategory c) { + result_category = c; + } + void set_result_code( + location::nearby::proto::connections::OperationResultCode c) { + result_code = c; + } + void set_connection_mode( + location::nearby::proto::connections::ConnectionMode m) { + connection_mode = m; + } +}; + +} // namespace nearby::analytics + +#endif // ANALYTICS_OPERATION_RESULT_WITH_MEDIUM_H_ diff --git a/connections/implementation/analytics/packet_meta_data.h b/connections/implementation/analytics/packet_meta_data.h deleted file mode 100644 index 09d2a85a..00000000 --- a/connections/implementation/analytics/packet_meta_data.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2022-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. -// 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 NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_PACKET_META_DATA_H_ -#define NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_PACKET_META_DATA_H_ - -#include - -#include "absl/time/time.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/system_clock.h" - -namespace nearby { -namespace analytics { - -struct PacketMetaData { - int packet_size; - absl::Time file_io_start_time; - absl::Time file_io_end_time; - absl::Time encryption_start_time; - absl::Time encryption_end_time; - absl::Time socket_io_start_time; - absl::Time socket_io_end_time; - - void Reset() { - file_io_start_time = SystemClock::ElapsedRealtime(); - socket_io_start_time = SystemClock::ElapsedRealtime(); - socket_io_start_time = SystemClock::ElapsedRealtime(); - packet_size = 0; - } - - void SetPacketSize(int packet_size) { - this->packet_size = packet_size; - } - - int GetPacketSize() { - return packet_size; - } - - void StartFileIo() { - file_io_start_time = SystemClock::ElapsedRealtime(); - } - - void StopFileIo() { - file_io_end_time = SystemClock::ElapsedRealtime(); - } - - void StartEncryption() { - encryption_start_time = SystemClock::ElapsedRealtime(); - } - - void StopEncryption() { - encryption_end_time = SystemClock::ElapsedRealtime(); - } - - void StartSocketIo() { - socket_io_start_time = SystemClock::ElapsedRealtime(); - } - - void StopSocketIo() { - socket_io_end_time = SystemClock::ElapsedRealtime(); - } - - int64_t GetEncryptionTimeInMillis() { - if (encryption_end_time > encryption_start_time) { - return absl::ToInt64Milliseconds(encryption_end_time - - encryption_start_time); - } - return 0L; - } - - int64_t GetFileIoTimeInMillis() { - if (file_io_end_time > file_io_start_time) { - return absl::ToInt64Milliseconds(file_io_end_time - file_io_start_time); - } - return 0L; - } - - int64_t GetSocketIoTimeInMillis() { - if (socket_io_end_time > socket_io_start_time) { - return absl::ToInt64Milliseconds(socket_io_end_time - - socket_io_start_time); - } - return 0L; - } -}; - -} // namespace analytics -} // namespace nearby - -#endif // NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_PACKET_META_DATA_H_ diff --git a/connections/implementation/analytics/throughput_recorder.cc b/connections/implementation/analytics/throughput_recorder.cc deleted file mode 100644 index 7833d4ad..00000000 --- a/connections/implementation/analytics/throughput_recorder.cc +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2022-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. -// 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 "connections/implementation/analytics/throughput_recorder.h" - -#include - -#include -#include -#include -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/str_format.h" -#include "absl/time/time.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" - -namespace nearby { -namespace analytics { - -namespace { -constexpr int kDefaultThroughoutKbps = 0; -constexpr int kKbInBytes = 1024; -constexpr int kSecInMs = 1000; -} // namespace - -ThroughputRecorder::ThroughputRecorder(int64_t payload_id) - : payload_id_(payload_id) {} - -ThroughputRecorderContainer& ThroughputRecorderContainer::GetInstance() { - alignas(ThroughputRecorderContainer) static char - storage[sizeof(ThroughputRecorderContainer)]; - static ThroughputRecorderContainer* env = - new (&storage) ThroughputRecorderContainer(); - return *env; -} - -void ThroughputRecorder::Start(PayloadType payload_type, - PayloadDirection payload_direction) { - std::string direction = - (payload_direction == PayloadDirection::INCOMING_PAYLOAD) ? "; Receive" - : "; Send"; - - VLOG(1) << "Start TP profiling for payload_id:" << payload_id_ << direction; - - if (payload_type == PayloadType::kUnknown) { - VLOG(1) << "Ignore ThroughputRecorder::start for Unknown Payload type"; - return; - } - - MutexLock lock(&mutex_); - start_timestamp_ = SystemClock::ElapsedRealtime(); - payload_type_ = payload_type; - payload_direction_ = payload_direction; - // Add packetLostAlarm later -} - -bool ThroughputRecorder::Stop() { - MutexLock lock(&mutex_); - VLOG(1) << "Stop TP profiling for payload_id:" << payload_id_; - if (payload_type_ == PayloadType::kUnknown) { - VLOG(1) << "Ignore ThroughputRecorder::stop as it never start"; - return false; - } - { - // Add packetLostAlarm stop process later - absl::Time stop_timestamp = SystemClock::ElapsedRealtime(); - int64_t total_byte_size = 0; - int medium_size = throughputs_.size(); - - // The worse case is the socket/connect blocking the write request, never - // got return when writing a frame out, it would get a very good data rate - // for this case. e.g. use 60 seconds to send a file and failed, the counter - // only get the duration as 30 seconds because the last write request - // blocked. - if (!success_) { - if (!throughputs_.empty()) { - for (auto& tp : throughputs_) { - tp.second.SetLastTimestamp(stop_timestamp); - } - } - } - - // calculate throughput by medium - for (auto& tp : throughputs_) { - tp.second.dump(); - total_byte_size += tp.second.GetTotalByteSize(); - } - - throughputs_.clear(); - - int64_t total_millis = - absl::ToInt64Milliseconds(stop_timestamp - start_timestamp_); - throughput_kbps_ = CalculateThroughputKBps(total_byte_size, total_millis); - int throughput_mbps = CalculateThroughputMBps(throughput_kbps_); - - // calculate overall throughput if there are multiple mediums - if (medium_size > 1) { - if (throughput_kbps_ != kDefaultThroughoutKbps) { - std::string dump_content = absl::StrFormat( - "%s %s data(%d bytes) %s, overall used %d milliseconds, " - "throughput " - "is %d MB/s (%d KB/s), File IO takes %d ms, %s takes %d " - "ms, " - "Socket IO takes %d ms", - (payload_direction_ == PayloadDirection::INCOMING_PAYLOAD) - ? "Received" - : "Sent", - ToString(payload_type_), total_byte_size, - success_ ? "SUCCEEDED" : "FAILED", total_millis, throughput_mbps, - throughput_kbps_, file_io_time_, - (payload_direction_ == PayloadDirection::INCOMING_PAYLOAD) - ? "Decryption" - : "Encryption", - encryption_time_, socket_io_time_); - LOG(INFO) << dump_content; - } - } - } - return true; -} - -void ThroughputRecorder::MarkAsSuccess() { - MutexLock lock(&mutex_); - success_ = true; -} - -int ThroughputRecorder::CalculateThroughputKBps(int64_t total_byte_size, - int64_t total_millis) { - if (total_millis > 0) { - return (int)(total_byte_size * kSecInMs / kKbInBytes / total_millis); - } - return kDefaultThroughoutKbps; -} - -int ThroughputRecorder::CalculateThroughputMBps(int throughputKBps) { - return throughputKBps / kKbInBytes; -} - -void ThroughputRecorder::Throughput::Add(int frame_size, int64_t file_io_time, - int64_t encryption_time, - int64_t socket_io_time) { - total_byte_size_ += frame_size; - // reset the last timestamp - last_timestamp_ = SystemClock::ElapsedRealtime(); - file_io_time_ += file_io_time; - encryption_time_ += encryption_time; - socket_io_time_ += socket_io_time; -} - -bool ThroughputRecorder::Throughput::dump() { - int64_t total_millis = - absl::ToInt64Milliseconds(last_timestamp_ - start_timestamp_); - int throughput_kbps = CalculateThroughputKBps(total_byte_size_, total_millis); - if (throughput_kbps == kDefaultThroughoutKbps) { - return false; - } - int throughpu_mbps = CalculateThroughputMBps(throughput_kbps); - int64_t other = - total_millis - file_io_time_ - encryption_time_ - socket_io_time_; - std::string dump_content = absl::StrFormat( - "%s %s data(%ld bytes) via %s used %ld milliseconds, throughput is %d " - "MB/s (%d KB/s), File IO takes %ld ms, %s takes %ld ms, " - "Socket IO takes %ld ms, " - "Other takes %ld ms", - (payload_direction_ == PayloadDirection::INCOMING_PAYLOAD) ? "Received" - : "Sent", - ToString(payload_type_), total_byte_size_, - location::nearby::proto::connections::Medium_Name(medium_), total_millis, - throughpu_mbps, throughput_kbps, file_io_time_, - (payload_direction_ == PayloadDirection::INCOMING_PAYLOAD) ? "Decryption" - : "Encryption", - encryption_time_, socket_io_time_, other); - LOG(INFO) << dump_content; - return true; -} - -ThroughputRecorder::Throughput& ThroughputRecorder::GetThroughput( - Medium medium, int64_t duration_millis) { - auto it = throughputs_.find(medium); - if (it == throughputs_.end()) { - auto throughput = new Throughput( - medium, - SystemClock::ElapsedRealtime() - absl::Milliseconds(duration_millis), - payload_type_, payload_direction_); - throughputs_.emplace(medium, std::move(*throughput)); - delete throughput; - return throughputs_.find(medium)->second; - } - return it->second; -} - -int ThroughputRecorder::GetThroughputsSize() { - MutexLock lock(&mutex_); - return throughputs_.size(); -} - -int ThroughputRecorder::GetThroughputKbps() { return throughput_kbps_; } - -int64_t ThroughputRecorder::GetDurationMillis() { return duration_millis_; } - -void ThroughputRecorder::OnFrameSent(Medium medium, - PacketMetaData& packetMetaData) { - MutexLock lock(&mutex_); - if (payload_type_ == PayloadType::kUnknown) { - VLOG(1) << "PayloadType is invalid, return"; - return; - } - - duration_millis_ = packetMetaData.GetEncryptionTimeInMillis() + - packetMetaData.GetFileIoTimeInMillis() + - packetMetaData.GetSocketIoTimeInMillis(); - GetThroughput(medium, duration_millis_) - .Add(packetMetaData.packet_size, packetMetaData.GetFileIoTimeInMillis(), - packetMetaData.GetEncryptionTimeInMillis(), - packetMetaData.GetSocketIoTimeInMillis()); - CalculateDurationTimes(packetMetaData); -} - -void ThroughputRecorder::OnFrameReceived(Medium medium, - PacketMetaData& packetMetaData) { - MutexLock lock(&mutex_); - if (payload_type_ == PayloadType::kUnknown) { - VLOG(1) << "PayloadType is invalid, return"; - return; - } - - // Add packetLostAlarm process later - duration_millis_ = packetMetaData.GetEncryptionTimeInMillis() + - packetMetaData.GetFileIoTimeInMillis() + - packetMetaData.GetSocketIoTimeInMillis(); - GetThroughput(medium, duration_millis_) - .Add(packetMetaData.packet_size, packetMetaData.GetFileIoTimeInMillis(), - packetMetaData.GetEncryptionTimeInMillis(), - packetMetaData.GetSocketIoTimeInMillis()); - CalculateDurationTimes(packetMetaData); -} - -void ThroughputRecorder::CalculateDurationTimes(PacketMetaData packetMetaData) { - encryption_time_ += packetMetaData.GetEncryptionTimeInMillis(); - socket_io_time_ += packetMetaData.GetSocketIoTimeInMillis(); - file_io_time_ += packetMetaData.GetFileIoTimeInMillis(); -} - -std::string ThroughputRecorder::ToString(PayloadType type) { - switch (type) { - case PayloadType::kBytes: - return std::string("Bytes"); - case PayloadType::kStream: - return std::string("Stream"); - case PayloadType::kFile: - return std::string("File"); - case PayloadType::kUnknown: - return std::string("Unknown"); - } -} - -// Inplementation for ThroughputRecorderContainer - -void ThroughputRecorderContainer::Shutdown() { - MutexLock lock(&mutex_); - VLOG(1) << __func__ << ". Num of Instance:" << throughput_recorders_.size(); - for (auto& throughput_recorder : throughput_recorders_) { - VLOG(1) << "Stop instance: " << throughput_recorder.second; - throughput_recorder.second->Stop(); - delete throughput_recorder.second; - } - throughput_recorders_.clear(); -} - -ThroughputRecorder* ThroughputRecorderContainer::GetTPRecorder( - const int64_t payload_id, PayloadDirection payload_direction) { - MutexLock lock(&mutex_); - auto it = throughput_recorders_.find( - std::pair(payload_id, payload_direction)); - if (it == throughput_recorders_.end()) { - auto instance = new ThroughputRecorder(payload_id); - std::string direction = - (payload_direction == PayloadDirection::INCOMING_PAYLOAD) ? "; Receive" - : "; Send"; - VLOG(1) << "Add ThroughputRecorder instance : " << instance - << " for payload_id:" << payload_id << direction; - throughput_recorders_.emplace( - std::pair(payload_id, payload_direction), - instance); - return instance; - } - - return it->second; -} - -void ThroughputRecorderContainer::StopTPRecorder( - const int64_t payload_id, PayloadDirection payload_direction) { - MutexLock lock(&mutex_); - std::string direction = - (payload_direction == PayloadDirection::INCOMING_PAYLOAD) ? "; Receive" - : "; Send"; - auto it = throughput_recorders_.find( - std::pair(payload_id, payload_direction)); - if (it != throughput_recorders_.end()) { - VLOG(1) << "Found and stop/delete ThroughputRecorder instance : " - << &(it->second) << " for payload_id:" << payload_id << direction; - it->second->Stop(); - delete it->second; - throughput_recorders_.erase( - std::pair(payload_id, payload_direction)); - return; - } - VLOG(1) << "No ThroughputRecorder found for :" << payload_id; -} - -int ThroughputRecorderContainer::GetSize() { - MutexLock lock(&mutex_); - return throughput_recorders_.size(); -} - -} // namespace analytics -} // namespace nearby diff --git a/connections/implementation/analytics/throughput_recorder.h b/connections/implementation/analytics/throughput_recorder.h deleted file mode 100644 index e6dcdc05..00000000 --- a/connections/implementation/analytics/throughput_recorder.h +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2022-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. -// 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 NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_THROUGHPUT_RECORDER_H_ -#define NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_THROUGHPUT_RECORDER_H_ - -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/time/time.h" -#include "connections/implementation/analytics/packet_meta_data.h" -#include "connections/payload_type.h" -#include "internal/platform/mutex.h" -#include "proto/connections_enums.pb.h" - -namespace nearby { -namespace analytics { - -// The following aliases are only for users' convenience. -using ::location::nearby::proto::connections::Medium; -using ::nearby::connections::PayloadType; -// Enum to represent if a payload is incoming or outgoing. -using ::nearby::connections::PayloadDirection; - -class ThroughputRecorder { - public: - explicit ThroughputRecorder(int64_t payload_id); - ~ThroughputRecorder() = default; - - void Start(PayloadType payload_type, PayloadDirection payload_direction); - bool Stop() ABSL_LOCKS_EXCLUDED(mutex_); - static int CalculateThroughputKBps(int64_t total_byte_size, - int64_t total_millis); - static int CalculateThroughputMBps(int throughputKBps); - - class Throughput { - public: - Throughput() = default; - ~Throughput() = default; - Throughput(Medium medium, absl::Time start_timestamp, - PayloadType payload_type, PayloadDirection payload_direction) - : medium_(medium), - start_timestamp_(start_timestamp), - payload_type_(payload_type), - payload_direction_(payload_direction) {} - - void Add(int frame_size, int64_t file_io_time, int64_t encryption_time, - int64_t socket_io_time); - - void SetLastTimestamp(absl::Time time_stamp) { - last_timestamp_ = time_stamp; - } - - int64_t GetTotalByteSize() { return total_byte_size_; } - - bool dump(); - - private: - Medium medium_; - absl::Time start_timestamp_; - PayloadType payload_type_; - int64_t total_byte_size_ = 0; - absl::Time last_timestamp_; - PayloadDirection payload_direction_ = PayloadDirection::INCOMING_PAYLOAD; - int64_t file_io_time_ = 0; - int64_t encryption_time_ = 0; - int64_t socket_io_time_ = 0; - }; - - Throughput& GetThroughput(Medium medium, int64_t duration_millis); - int GetThroughputsSize(); - int GetThroughputKbps(); - int64_t GetDurationMillis(); - void OnFrameSent(Medium medium, PacketMetaData& packetMetaData); - void OnFrameReceived(Medium medium, PacketMetaData& packetMetaData); - void MarkAsSuccess(); - - private: - void CalculateDurationTimes(PacketMetaData packetMetaData); - static std::string ToString(PayloadType type); - - Mutex mutex_; - int64_t payload_id_ = 0; - absl::Time start_timestamp_; - PayloadType payload_type_ = PayloadType::kUnknown; - PayloadDirection payload_direction_ = PayloadDirection::INCOMING_PAYLOAD; - absl::flat_hash_map throughputs_; - bool success_ = false; - - int64_t file_io_time_ = 0; - int64_t encryption_time_ = 0; - int64_t socket_io_time_ = 0; - int64_t duration_millis_ = 0; - int throughput_kbps_ = 0; -}; - -class ThroughputRecorderContainer { - public: - ThroughputRecorderContainer(const ThroughputRecorderContainer&) = delete; - ThroughputRecorderContainer& operator=(const ThroughputRecorderContainer&) = - delete; - - static ThroughputRecorderContainer& GetInstance(); - void Shutdown() ABSL_LOCKS_EXCLUDED(mutex_); - - ThroughputRecorder* GetTPRecorder(int64_t payload_id, - PayloadDirection payload_direction) - ABSL_LOCKS_EXCLUDED(mutex_); - void StopTPRecorder(int64_t payload_id, PayloadDirection payload_direction) - ABSL_LOCKS_EXCLUDED(mutex_); - int GetSize() ABSL_LOCKS_EXCLUDED(mutex_); - - private: - // This is a singleton object, for which destructor will never be called. - // Constructor will be invoked once from Instance() static method. - // Object is create in-place (with a placement new) to guarantee that - // destructor is not scheduled for execution at exit. - ThroughputRecorderContainer() = default; - ~ThroughputRecorderContainer() = default; - - Mutex mutex_; - // std::pair for - absl::flat_hash_map, ThroughputRecorder*> - throughput_recorders_ ABSL_GUARDED_BY(mutex_); -}; - -} // namespace analytics -} // namespace nearby - -#endif // NEARBY_CONNECTIONS_IMPLEMENTATION_ANALYTICS_THROUGHPUT_RECORDER_H_ diff --git a/connections/implementation/analytics/throughput_recorder_test.cc b/connections/implementation/analytics/throughput_recorder_test.cc deleted file mode 100644 index 8b31add3..00000000 --- a/connections/implementation/analytics/throughput_recorder_test.cc +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2022-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. -// 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 "connections/implementation/analytics/throughput_recorder.h" - -#include - -#include -#include - -#include "gtest/gtest.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "internal/platform/logging.h" -#include "proto/connections_enums.pb.h" - -namespace nearby { -namespace analytics { -namespace { -// TODO(b/246693797): Add unit tests coverage for throughput recorder code - -constexpr int64_t kPayloadIdA = 123456789; -constexpr int64_t kPayloadIdB = 987654321; -constexpr int kFrameSize = 10 * 64 * 1024; -constexpr int64_t kTotalByteSize1GB = 1024 * 1024 * 1024; -constexpr int64_t kTotalMillis10Sec = 10 * 1000; -constexpr int kTPResultKBPerSec = 1024 * 1024 / 10; -constexpr int kTPKBPerSec = 100 * 1024; -constexpr int kTPResultMBPerSec = 100; - -// class ThroughputRecorderTest : public testing::Test { -class ThroughputRecorderTest : public testing::TestWithParam { - protected: - ThroughputRecorderTest() = default; - ~ThroughputRecorderTest() override { - ThroughputRecorderContainer::GetInstance().Shutdown(); - } - - ThroughputRecorderContainer& tp_recorder_container_ = - ThroughputRecorderContainer::GetInstance(); -}; - -INSTANTIATE_TEST_SUITE_P(ParametrisedTestThroughputRecorderTest, - ThroughputRecorderTest, testing::Values(true, false)); - -TEST(ThroughputRecorder, CalculateThroughputKBps) { - EXPECT_EQ(ThroughputRecorder::CalculateThroughputKBps(kTotalByteSize1GB, - kTotalMillis10Sec), - kTPResultKBPerSec); - EXPECT_EQ(ThroughputRecorder::CalculateThroughputKBps(kTotalByteSize1GB, 0), - 0); -} - -TEST(ThroughputRecorder, CalculateThroughputMBps) { - EXPECT_EQ(ThroughputRecorder::CalculateThroughputMBps(kTPKBPerSec), - kTPResultMBPerSec); -} - -TEST(ThroughputRecorderContainer, InstanceCreate_ContainerSize) { - ThroughputRecorderContainer& TPRecorderContainer = - ThroughputRecorderContainer::GetInstance(); - TPRecorderContainer.GetTPRecorder(kPayloadIdA, - PayloadDirection::OUTGOING_PAYLOAD); - TPRecorderContainer.GetTPRecorder(kPayloadIdB, - PayloadDirection::INCOMING_PAYLOAD); - EXPECT_EQ(ThroughputRecorderContainer::GetInstance().GetSize(), 2); - ThroughputRecorderContainer::GetInstance().Shutdown(); - EXPECT_EQ(ThroughputRecorderContainer::GetInstance().GetSize(), 0); -} - -TEST_F(ThroughputRecorderTest, OnFrameSentSaveTransferredSize) { - auto TPRecorder = tp_recorder_container_.GetTPRecorder( - kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD); - TPRecorder->Start(PayloadType::kFile, PayloadDirection::OUTGOING_PAYLOAD); - - PacketMetaData packet_meta_data; - packet_meta_data.SetPacketSize(kFrameSize); - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data); - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data); - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data); - - auto throughput = - TPRecorder->GetThroughput(location::nearby::proto::connections::BLE, 0); - EXPECT_EQ(throughput.GetTotalByteSize(), kFrameSize * 3); -} - -TEST_F(ThroughputRecorderTest, OnIgnoreUnkownPaylaodType) { - auto TPRecorder = tp_recorder_container_.GetTPRecorder( - kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD); - TPRecorder->Start(PayloadType::kUnknown, PayloadDirection::OUTGOING_PAYLOAD); - - PacketMetaData packet_meta_data; - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data); - EXPECT_EQ(TPRecorder->GetThroughputsSize(), 0); - - TPRecorder->Start(PayloadType::kUnknown, PayloadDirection::INCOMING_PAYLOAD); - TPRecorder->OnFrameReceived(location::nearby::proto::connections::BLE, - packet_meta_data); - EXPECT_EQ(TPRecorder->GetThroughputsSize(), 0); -} - -TEST_P(ThroughputRecorderTest, OnFrameSentStopAndDump) { - auto TPRecorder = tp_recorder_container_.GetTPRecorder( - kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD); - TPRecorder->Start(PayloadType::kFile, PayloadDirection::OUTGOING_PAYLOAD); - - PacketMetaData packet_meta_data; - packet_meta_data.SetPacketSize(kFrameSize); - packet_meta_data.StartFileIo(); - absl::SleepFor(absl::Milliseconds(5)); - packet_meta_data.StopFileIo(); - packet_meta_data.StartEncryption(); - absl::SleepFor(absl::Milliseconds(6)); - packet_meta_data.StopEncryption(); - packet_meta_data.StartSocketIo(); - absl::SleepFor(absl::Milliseconds(7)); - packet_meta_data.StopSocketIo(); - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data); - EXPECT_EQ(TPRecorder->GetDurationMillis(), - packet_meta_data.GetEncryptionTimeInMillis() + - packet_meta_data.GetFileIoTimeInMillis() + - packet_meta_data.GetSocketIoTimeInMillis()); - - packet_meta_data.SetPacketSize(kFrameSize); - packet_meta_data.StartFileIo(); - absl::SleepFor(absl::Milliseconds(15)); - packet_meta_data.StopFileIo(); - packet_meta_data.StartEncryption(); - absl::SleepFor(absl::Milliseconds(16)); - packet_meta_data.StopEncryption(); - packet_meta_data.StartSocketIo(); - absl::SleepFor(absl::Milliseconds(17)); - packet_meta_data.StopSocketIo(); - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data); - - if (GetParam() == true) { - LOG(INFO) << "MarkAsSuccess"; - TPRecorder->MarkAsSuccess(); - } - EXPECT_TRUE(TPRecorder->Stop()); - EXPECT_NE(TPRecorder->GetThroughputKbps(), 0); -} - -TEST_F(ThroughputRecorderTest, OnFrameSentStopAndDumpForMultiMeadium) { - auto TPRecorder = tp_recorder_container_.GetTPRecorder( - kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD); - TPRecorder->Start(PayloadType::kFile, PayloadDirection::OUTGOING_PAYLOAD); - - PacketMetaData packet_meta_data1; - packet_meta_data1.SetPacketSize(kFrameSize); - packet_meta_data1.StartFileIo(); - absl::SleepFor(absl::Milliseconds(5)); - packet_meta_data1.StopFileIo(); - packet_meta_data1.StartEncryption(); - absl::SleepFor(absl::Milliseconds(6)); - packet_meta_data1.StopEncryption(); - packet_meta_data1.StartSocketIo(); - absl::SleepFor(absl::Milliseconds(7)); - packet_meta_data1.StopSocketIo(); - TPRecorder->OnFrameSent(location::nearby::proto::connections::BLE, - packet_meta_data1); - - PacketMetaData packet_meta_data2; - packet_meta_data2.SetPacketSize(kFrameSize); - packet_meta_data2.StartFileIo(); - absl::SleepFor(absl::Milliseconds(15)); - packet_meta_data2.StopFileIo(); - packet_meta_data2.StartEncryption(); - absl::SleepFor(absl::Milliseconds(16)); - packet_meta_data2.StopEncryption(); - packet_meta_data2.StartSocketIo(); - absl::SleepFor(absl::Milliseconds(17)); - packet_meta_data2.StopSocketIo(); - TPRecorder->OnFrameSent(location::nearby::proto::connections::WIFI_LAN, - packet_meta_data2); - - TPRecorder->MarkAsSuccess(); - EXPECT_TRUE(TPRecorder->Stop()); - EXPECT_NE(TPRecorder->GetThroughputKbps(), 0); -} - -TEST_F(ThroughputRecorderTest, OnFrameReceivedCheckDurationMillis) { - auto TPRecorder = tp_recorder_container_.GetTPRecorder( - kPayloadIdA, PayloadDirection::INCOMING_PAYLOAD); - TPRecorder->Start(PayloadType::kFile, PayloadDirection::INCOMING_PAYLOAD); - - PacketMetaData packet_meta_data; - packet_meta_data.SetPacketSize(kFrameSize); - packet_meta_data.StartFileIo(); - absl::SleepFor(absl::Milliseconds(5)); - packet_meta_data.StopFileIo(); - packet_meta_data.StartEncryption(); - absl::SleepFor(absl::Milliseconds(6)); - packet_meta_data.StopEncryption(); - packet_meta_data.StartSocketIo(); - absl::SleepFor(absl::Milliseconds(7)); - packet_meta_data.StopSocketIo(); - TPRecorder->OnFrameReceived(location::nearby::proto::connections::BLE, - packet_meta_data); - EXPECT_EQ(TPRecorder->GetDurationMillis(), - packet_meta_data.GetEncryptionTimeInMillis() + - packet_meta_data.GetFileIoTimeInMillis() + - packet_meta_data.GetSocketIoTimeInMillis()); -} - -TEST_F(ThroughputRecorderTest, OnTPRecorderNotStarted) { - auto TPRecorder = tp_recorder_container_.GetTPRecorder( - kPayloadIdA, PayloadDirection::OUTGOING_PAYLOAD); - auto throughput = - TPRecorder->GetThroughput(location::nearby::proto::connections::BLE, 0); - EXPECT_FALSE(throughput.dump()); -} - -} // namespace -} // namespace analytics -} // namespace nearby diff --git a/connections/implementation/base_bwu_handler.cc b/connections/implementation/base_bwu_handler.cc index 15f14aa2..29dbb8f0 100644 --- a/connections/implementation/base_bwu_handler.cc +++ b/connections/implementation/base_bwu_handler.cc @@ -20,7 +20,6 @@ #include "connections/implementation/client_proxy.h" #include "connections/implementation/service_id_constants.h" -#include "internal/platform/byte_array.h" #include "internal/platform/logging.h" namespace nearby { @@ -30,16 +29,16 @@ BaseBwuHandler::BaseBwuHandler( IncomingConnectionCallback incoming_connection_callback) : incoming_connection_callback_(std::move(incoming_connection_callback)) {} -ByteArray BaseBwuHandler::InitializeUpgradedMediumForEndpoint( +std::string BaseBwuHandler::InitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& service_id, const std::string& endpoint_id) { std::string upgrade_service_id = WrapInitiatorUpgradeServiceId(service_id); // Perform any medium-specific handling in the child class. - ByteArray upgrade_path_available_frame = + std::string upgrade_path_available_frame = HandleInitializeUpgradedMediumForEndpoint(client, upgrade_service_id, endpoint_id); - if (!upgrade_path_available_frame.Empty()) { + if (!upgrade_path_available_frame.empty()) { upgrade_service_id_to_active_endpoint_ids_[upgrade_service_id].insert( endpoint_id); } diff --git a/connections/implementation/base_bwu_handler.h b/connections/implementation/base_bwu_handler.h index 3f8e40ad..d95aacd8 100644 --- a/connections/implementation/base_bwu_handler.h +++ b/connections/implementation/base_bwu_handler.h @@ -22,7 +22,6 @@ #include "absl/container/flat_hash_set.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" -#include "internal/platform/byte_array.h" namespace nearby { namespace connections { @@ -35,7 +34,7 @@ class BaseBwuHandler : public BwuHandler { IncomingConnectionCallback incoming_connection_callback); // BwuHandler implementation: - ByteArray InitializeUpgradedMediumForEndpoint( + std::string InitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& service_id, const std::string& endpoint_id) final; void RevertInitiatorState() final; @@ -51,7 +50,7 @@ class BaseBwuHandler : public BwuHandler { // respectively, to handle medium-specific logic. // HandleRevertInitiatorStateForService is only invoked after the last // endpoint for the service is reverted. - virtual ByteArray HandleInitializeUpgradedMediumForEndpoint( + virtual std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) = 0; virtual void HandleRevertInitiatorStateForService( diff --git a/connections/implementation/base_bwu_handler_test.cc b/connections/implementation/base_bwu_handler_test.cc index da3f87ab..a8c8c0be 100644 --- a/connections/implementation/base_bwu_handler_test.cc +++ b/connections/implementation/base_bwu_handler_test.cc @@ -24,7 +24,6 @@ #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/service_id_constants.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" namespace nearby { @@ -55,8 +54,8 @@ class BwuHandlerImpl : public BaseBwuHandler { const std::vector& handle_revert_calls() const { return handle_revert_calls_; } - void set_handle_initialize_output(ByteArray bytes) { - handle_initialize_output_ = bytes; + void set_handle_initialize_output(absl::string_view bytes) { + handle_initialize_output_ = std::string(bytes); } private: @@ -73,7 +72,7 @@ class BwuHandlerImpl : public BaseBwuHandler { const std::string& endpoint_id) final {} // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final { handle_initialize_calls_.push_back({.client = client, @@ -86,7 +85,7 @@ class BwuHandlerImpl : public BaseBwuHandler { handle_revert_calls_.push_back({.service_id = upgrade_service_id}); } - ByteArray handle_initialize_output_; + std::string handle_initialize_output_; std::vector handle_initialize_calls_; std::vector handle_revert_calls_; }; @@ -95,7 +94,7 @@ TEST(BaseBwuHandlerTest, InitializeAndRevert) { ClientProxy client; BwuHandlerImpl handler; - ByteArray expected_output{"not empty"}; + absl::string_view expected_output{"not empty"}; handler.set_handle_initialize_output(expected_output); // Initialize two upgrade endpoints for service A and one for service B. @@ -150,7 +149,7 @@ TEST(BaseBwuHandlerTest, InitializeAndRevertAll) { ClientProxy client; BwuHandlerImpl handler; - ByteArray expected_output{"not empty"}; + absl::string_view expected_output{"not empty"}; handler.set_handle_initialize_output(expected_output); handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A", @@ -169,7 +168,7 @@ TEST(BaseBwuHandlerTest, Initialize_Failure_EmptyUpgradePathAvailableFrame) { ClientProxy client; BwuHandlerImpl handler; - ByteArray expected_output{}; + absl::string_view expected_output{}; handler.set_handle_initialize_output(expected_output); handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A", @@ -191,7 +190,7 @@ TEST(BaseBwuHandlerTest, Initialize_StillWorkWithUpgradeServiceIdSuffix) { ClientProxy client; BwuHandlerImpl handler; - ByteArray expected_output{"not empty"}; + absl::string_view expected_output{"not empty"}; handler.set_handle_initialize_output(expected_output); // The method should be robust and not add _another_ upgrade suffix @@ -208,7 +207,7 @@ TEST(BaseBwuHandlerTest, Revert_Failure_CantFindService) { ClientProxy client; BwuHandlerImpl handler; - ByteArray expected_output{"not empty"}; + absl::string_view expected_output{"not empty"}; handler.set_handle_initialize_output(expected_output); handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A", /*endpoint_id=*/"1"); @@ -222,7 +221,7 @@ TEST(BaseBwuHandlerTest, Revert_Failure_CantFindEndpoint) { ClientProxy client; BwuHandlerImpl handler; - ByteArray expected_output{"not empty"}; + absl::string_view expected_output{"not empty"}; handler.set_handle_initialize_output(expected_output); handler.InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"A", /*endpoint_id=*/"1"); diff --git a/connections/implementation/base_endpoint_channel.cc b/connections/implementation/base_endpoint_channel.cc index 0687d7be..79ba0de0 100644 --- a/connections/implementation/base_endpoint_channel.cc +++ b/connections/implementation/base_endpoint_channel.cc @@ -40,15 +40,13 @@ #include "internal/platform/mutex_lock.h" #include "internal/platform/output_stream.h" -namespace nearby { -namespace connections { +namespace nearby::connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::proto::connections::Medium::BLE; using ::location::nearby::proto::connections::Medium::BLE_L2CAP; -using DisconnectionReason = - ::location::nearby::proto::connections::DisconnectionReason; +using ::nearby::analytics::SafeDisconnectionResult; +using ::location::nearby::proto::connections::DisconnectionReason; Exception WriteInt(OutputStream* writer, std::int32_t value) { return Base64Utils::WriteInt(writer, value); @@ -92,17 +90,10 @@ BaseEndpointChannel::BaseEndpointChannel( try_count_(try_count) {} ExceptionOr BaseEndpointChannel::Read() { - PacketMetaData packet_meta_data; - return Read(packet_meta_data); -} - -ExceptionOr BaseEndpointChannel::Read( - PacketMetaData& packet_meta_data) { ByteArray result; { MutexLock lock(&reader_mutex_); - packet_meta_data.StartSocketIo(); ExceptionOr read_int; if (NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature:: @@ -133,8 +124,6 @@ ExceptionOr BaseEndpointChannel::Read( if (!read_bytes.ok()) { return read_bytes; } - packet_meta_data.StopSocketIo(); - packet_meta_data.SetPacketSize(read_int.result() + sizeof(std::int32_t)); result = std::move(read_bytes.result()); } @@ -144,7 +133,6 @@ ExceptionOr BaseEndpointChannel::Read( if (IsEncryptionEnabledLocked()) { // If encryption is enabled, decode the message. std::string input(std::move(result)); - packet_meta_data.StartEncryption(); std::unique_ptr decrypted_data = crypto_context_->DecodeMessageFromPeer(input); if (decrypted_data) { @@ -157,7 +145,7 @@ ExceptionOr BaseEndpointChannel::Read( // and let it through if it is, otherwise message is erased. // TODO(apolyudov): verify this happens at most once per session. result = {}; - auto parsed = parser::FromBytes(ByteArray(input)); + auto parsed = parser::FromBytes(input); if (parsed.ok()) { if (parser::GetFrameType(parsed.result()) == location::nearby::connections::V1Frame::KEEP_ALIVE) { @@ -175,7 +163,6 @@ ExceptionOr BaseEndpointChannel::Read( << ": Unable to parse data as unencrypted message."; } } - packet_meta_data.StopEncryption(); if (result.Empty()) { LOG(WARNING) << __func__ << ": Unable to parse read result."; return ExceptionOr(message_exception); @@ -190,13 +177,7 @@ ExceptionOr BaseEndpointChannel::Read( return ExceptionOr(result); } -Exception BaseEndpointChannel::Write(const ByteArray& data) { - PacketMetaData packet_meta_data; - return Write(data.AsStringView(), packet_meta_data); -} - -Exception BaseEndpointChannel::Write(absl::string_view data, - PacketMetaData& packet_meta_data) { +Exception BaseEndpointChannel::Write(absl::string_view data) { { MutexLock pause_lock(&is_paused_mutex_); if (is_paused_) { @@ -217,9 +198,7 @@ Exception BaseEndpointChannel::Write(absl::string_view data, MutexLock crypto_lock(&crypto_mutex_); if (IsEncryptionEnabledLocked()) { // If encryption is enabled, encode the message. - packet_meta_data.StartEncryption(); encrypted = crypto_context_->EncodeMessageToPeer(data); - packet_meta_data.StopEncryption(); if (!encrypted) { LOG(WARNING) << __func__ << ": Failed to encrypt data."; return {Exception::kIo}; @@ -235,7 +214,6 @@ Exception BaseEndpointChannel::Write(absl::string_view data, return {Exception::kIo}; } - packet_meta_data.StartSocketIo(); Exception write_exception; if (NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature:: @@ -262,8 +240,6 @@ Exception BaseEndpointChannel::Write(absl::string_view data, << ": Failed to flush writer: " << flush_exception.value; return flush_exception; } - packet_meta_data.StopSocketIo(); - packet_meta_data.SetPacketSize(data_size + sizeof(std::uint32_t)); } { @@ -326,7 +302,7 @@ void BaseEndpointChannel::SetAnalyticsRecorder( void BaseEndpointChannel::Close( location::nearby::proto::connections::DisconnectionReason reason) { - Close(reason, ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + Close(reason, SafeDisconnectionResult::kSafeDisconnection); } void BaseEndpointChannel::Close( @@ -490,5 +466,4 @@ std::unique_ptr BaseEndpointChannel::EncodeMessageForTests( return crypto_context_->EncodeMessageToPeer(data); } -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/base_endpoint_channel.h b/connections/implementation/base_endpoint_channel.h index 9946b9fa..421a8a9f 100644 --- a/connections/implementation/base_endpoint_channel.h +++ b/connections/implementation/base_endpoint_channel.h @@ -23,7 +23,6 @@ #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "connections/implementation/analytics/analytics_recorder.h" -#include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/endpoint_channel.h" #include "internal/platform/byte_array.h" #include "internal/platform/condition_variable.h" @@ -32,10 +31,7 @@ #include "internal/platform/mutex.h" #include "internal/platform/output_stream.h" -namespace nearby { -namespace connections { - -using analytics::PacketMetaData; +namespace nearby::connections { class BaseEndpointChannel : public EndpointChannel { public: @@ -51,20 +47,16 @@ class BaseEndpointChannel : public EndpointChannel { ~BaseEndpointChannel() override = default; // EndpointChannel: - ExceptionOr Read() override; - ExceptionOr Read(PacketMetaData& packet_meta_data) + ExceptionOr Read() ABSL_LOCKS_EXCLUDED(reader_mutex_, crypto_mutex_, last_read_mutex_) override; - Exception Write(const ByteArray& data) override; - Exception Write(absl::string_view data, PacketMetaData& packet_meta_data) + Exception Write(absl::string_view data) ABSL_LOCKS_EXCLUDED(writer_mutex_, crypto_mutex_) override; void Close() ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; void Close(location::nearby::proto::connections::DisconnectionReason reason) override; - void Close( - location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result) override; + void Close(location::nearby::proto::connections::DisconnectionReason reason, + nearby::analytics::SafeDisconnectionResult result) override; bool IsClosed() const ABSL_LOCKS_EXCLUDED(is_paused_mutex_) override; std::string GetType() const override; std::string GetServiceId() const override; @@ -176,7 +168,6 @@ class BaseEndpointChannel : public EndpointChannel { std::string endpoint_id_ = ""; }; -} // namespace connections -} // namespace nearby +} // namespace nearby::connections #endif // CORE_INTERNAL_BASE_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/base_endpoint_channel_test.cc b/connections/implementation/base_endpoint_channel_test.cc index a1bad6e0..1e3cbbde 100644 --- a/connections/implementation/base_endpoint_channel_test.cc +++ b/connections/implementation/base_endpoint_channel_test.cc @@ -108,20 +108,26 @@ std::function MakeDataMonitor(const std::string& label, std::pair, std::shared_ptr> -DoDhKeyExchange(BaseEndpointChannel* channel_a, - BaseEndpointChannel* channel_b) { +DoDhKeyExchange(std::shared_ptr channel_a, + std::shared_ptr channel_b) { std::shared_ptr context_a; std::shared_ptr context_b; EncryptionRunner crypto_a; EncryptionRunner crypto_b; ClientProxy proxy_a; ClientProxy proxy_b; - CountDownLatch latch(2); + std::shared_ptr shared_channel_a = channel_a; + std::shared_ptr shared_channel_b = channel_b; + + // Create a shared_ptr for the latch to prevent Use-After-Free if the + // negotiation times out and this function returns early. + auto latch = std::make_shared(2); + crypto_a.StartClient( - &proxy_a, "endpoint_id", channel_a, + &proxy_a, "endpoint_id", shared_channel_a, { .on_success_cb = - [&latch, &context_a]( + [latch, &context_a]( const std::string& endpoint_id, std::unique_ptr ukey2, const std::string& auth_token, @@ -131,20 +137,19 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a, auto context = ukey2->ToConnectionContext(); EXPECT_NE(context, nullptr); context_a = std::move(context); - latch.CountDown(); + latch->CountDown(); }, .on_failure_cb = - [&latch](const std::string& endpoint_id, - EndpointChannel* channel) { + [latch](const std::string& endpoint_id) { LOG(INFO) << "client-A side key negotiation failed"; - latch.CountDown(); + latch->CountDown(); }, }); crypto_b.StartServer( - &proxy_b, "endpoint_id", channel_b, + &proxy_b, "endpoint_id", shared_channel_b, { .on_success_cb = - [&latch, &context_b]( + [latch, &context_b]( const std::string& endpoint_id, std::unique_ptr ukey2, const std::string& auth_token, @@ -154,16 +159,15 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a, auto context = ukey2->ToConnectionContext(); EXPECT_NE(context, nullptr); context_b = std::move(context); - latch.CountDown(); + latch->CountDown(); }, .on_failure_cb = - [&latch](const std::string& endpoint_id, - EndpointChannel* channel) { + [latch](const std::string& endpoint_id) { LOG(INFO) << "client-B side key negotiation failed"; - latch.CountDown(); + latch->CountDown(); }, }); - EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result()); + EXPECT_TRUE(latch->Await(absl::Milliseconds(5000)).result()); return std::make_pair(std::move(context_a), std::move(context_b)); } @@ -174,7 +178,7 @@ class BaseEndpointChannelTest : public ::testing::Test { NearbyFlags::GetInstance().ResetOverridedValues(); } - const ByteArray kTestData{"test_data"}; + const absl::string_view kTestData = "test_data"; }; TEST_F(BaseEndpointChannelTest, ReadSucceedsWhenFlagDisabled) { @@ -189,7 +193,7 @@ TEST_F(BaseEndpointChannelTest, ReadSucceedsWhenFlagDisabled) { channel_a.Write(kTestData); ByteArray rx_message = std::move(channel_b.Read().result()); - EXPECT_EQ(rx_message, kTestData); + EXPECT_EQ(rx_message.AsStringView(), kTestData); } TEST_F(BaseEndpointChannelTest, ReadCallsDispatchPacketWhenFlagEnabled) { @@ -203,13 +207,14 @@ TEST_F(BaseEndpointChannelTest, ReadCallsDispatchPacketWhenFlagEnabled) { TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); EXPECT_CALL(channel_b, DispatchPacket) - .WillOnce(::testing::Return(ExceptionOr(kTestData))); + .WillOnce(::testing::Return( + ExceptionOr(ByteArray(std::string(kTestData))))); channel_a.Write(kTestData); auto read_byte = channel_b.Read(); EXPECT_TRUE(read_byte.ok()); - EXPECT_EQ(read_byte.result(), kTestData); + EXPECT_EQ(read_byte.result().AsStringView(), kTestData); } TEST_F(BaseEndpointChannelTest, @@ -243,10 +248,10 @@ TEST_F(BaseEndpointChannelTest, ReadWrite) { auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); - ByteArray tx_message{"data message"}; + absl::string_view tx_message = "data message"; channel_a.Write(tx_message); ByteArray rx_message = std::move(channel_b.Read().result()); - EXPECT_EQ(rx_message, tx_message); + EXPECT_EQ(rx_message.AsStringView(), tx_message); } TEST_F(BaseEndpointChannelTest, ChannelUnencryptedByDefault) { @@ -264,20 +269,22 @@ TEST_F(BaseEndpointChannelTest, TryDecrypt) { absl::string_view kMessage = "message"; auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); - TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); - auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); + auto channel_a = std::make_shared(pipe_b.first.get(), + pipe_a.second.get()); + auto channel_b = std::make_shared(pipe_a.first.get(), + pipe_b.second.get()); + auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b); ASSERT_NE(context_a, nullptr); ASSERT_NE(context_b, nullptr); - channel_a.EnableEncryption(context_a); - channel_b.EnableEncryption(context_b); + channel_a->EnableEncryption(context_a); + channel_b->EnableEncryption(context_b); std::unique_ptr encrypted_message = - channel_a.EncodeMessageForTests(kMessage); + channel_a->EncodeMessageForTests(kMessage); ExceptionOr decrypted_message = - channel_b.TryDecrypt(ByteArray(*encrypted_message)); + channel_b->TryDecrypt(ByteArray(*encrypted_message)); - EXPECT_TRUE(channel_b.IsEncrypted()); + EXPECT_TRUE(channel_b->IsEncrypted()); EXPECT_TRUE(decrypted_message.ok()); EXPECT_EQ(decrypted_message.result().AsStringView(), kMessage); } @@ -285,16 +292,18 @@ TEST_F(BaseEndpointChannelTest, TryDecrypt) { TEST_F(BaseEndpointChannelTest, TryDecryptFailsWhenDecryptionFails) { auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); - TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); - auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); + auto channel_a = std::make_shared(pipe_b.first.get(), + pipe_a.second.get()); + auto channel_b = std::make_shared(pipe_a.first.get(), + pipe_b.second.get()); + auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b); ASSERT_NE(context_a, nullptr); - channel_a.EnableEncryption(context_a); + channel_a->EnableEncryption(context_a); ExceptionOr result = - channel_a.TryDecrypt(ByteArray("invalid message")); + channel_a->TryDecrypt(ByteArray("invalid message")); - EXPECT_TRUE(channel_a.IsEncrypted()); + EXPECT_TRUE(channel_a->IsEncrypted()); EXPECT_FALSE(result.ok()); EXPECT_EQ(result.exception(), Exception::kExecution); } @@ -332,12 +341,12 @@ TEST_F(BaseEndpointChannelTest, NotEncryptedReadWriteCanBeIntercepted) { EXPECT_EQ(channel_b.GetType(), "BLE"); // Start data transfer - ByteArray tx_message{"data message"}; + absl::string_view tx_message = "data message"; channel_a.Write(tx_message); ByteArray rx_message = std::move(channel_b.Read().result()); // Verify expectations. - EXPECT_EQ(rx_message, tx_message); + EXPECT_EQ(rx_message.AsStringView(), tx_message); { absl::MutexLock lock(mutex); std::string message{tx_message}; @@ -365,13 +374,15 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { // to server "b". auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes // to server "a". - TestEndpointChannel channel_a(server_a.first.get(), client_a.second.get()); - TestEndpointChannel channel_b(server_b.first.get(), client_b.second.get()); + auto channel_a = std::make_shared(server_a.first.get(), + client_a.second.get()); + auto channel_b = std::make_shared(server_b.first.get(), + client_b.second.get()); - ON_CALL(channel_a, GetMedium).WillByDefault([]() { + ON_CALL(*channel_a, GetMedium).WillByDefault([]() { return Medium::BLUETOOTH; }); - ON_CALL(channel_b, GetMedium).WillByDefault([]() { + ON_CALL(*channel_b, GetMedium).WillByDefault([]() { return Medium::BLUETOOTH; }); @@ -384,24 +395,24 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { MakeDataMonitor("monitor_b", &capture_b, &mutex))); // Run DH key exchange; setup encryption contexts for channels. - auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); + auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b); ASSERT_NE(context_a, nullptr); ASSERT_NE(context_b, nullptr); - channel_a.EnableEncryption(context_a); - channel_b.EnableEncryption(context_b); + channel_a->EnableEncryption(context_a); + channel_b->EnableEncryption(context_b); - EXPECT_EQ(channel_a.GetType(), "ENCRYPTED_BLUETOOTH"); - EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH"); - EXPECT_TRUE(channel_a.IsEncrypted()); - EXPECT_TRUE(channel_b.IsEncrypted()); + EXPECT_EQ(channel_a->GetType(), "ENCRYPTED_BLUETOOTH"); + EXPECT_EQ(channel_b->GetType(), "ENCRYPTED_BLUETOOTH"); + EXPECT_TRUE(channel_a->IsEncrypted()); + EXPECT_TRUE(channel_b->IsEncrypted()); // Start data transfer - ByteArray tx_message{"data message"}; - channel_a.Write(tx_message); - ByteArray rx_message = std::move(channel_b.Read().result()); + absl::string_view tx_message = "data message"; + channel_a->Write(tx_message); + ByteArray rx_message = std::move(channel_b->Read().result()); // Verify expectations. - EXPECT_EQ(rx_message, tx_message); + EXPECT_EQ(rx_message.AsStringView(), tx_message); { absl::MutexLock lock(mutex); std::string message{tx_message}; @@ -410,8 +421,8 @@ TEST_F(BaseEndpointChannelTest, EncryptedReadWriteCanNotBeIntercepted) { } // Shutdown test environment. - channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); - channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); + channel_a->Close(DisconnectionReason::LOCAL_DISCONNECTION); + channel_b->Close(DisconnectionReason::REMOTE_DISCONNECTION); } TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) { @@ -432,8 +443,8 @@ TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) { EXPECT_EQ(channel_b.GetType(), "WIFI_LAN"); // Start data transfer - ByteArray tx_message{"data message"}; - ByteArray more_message{"more data"}; + absl::string_view tx_message = "data message"; + absl::string_view more_message = "more data"; channel_a.Write(tx_message); ByteArray rx_message = std::move(channel_b.Read().result()); @@ -459,7 +470,7 @@ TEST_F(BaseEndpointChannelTest, CanBesuspendedAndResumed) { // Resume; verify that data transfer comepleted. channel_a.Resume(); EXPECT_TRUE(latch.Await(absl::Milliseconds(1000)).result()); - EXPECT_EQ(read_more, more_message); + EXPECT_EQ(read_more.AsStringView(), more_message); // Shutdown test environment. channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); @@ -485,43 +496,45 @@ TEST_F(BaseEndpointChannelTest, ReadUnencryptedFrameOnEncryptedChannel) { // Setup test communication environment. auto pipe_a = CreatePipe(); // channel_a writes to pipe_a, reads from pipe_b. auto pipe_b = CreatePipe(); // channel_b writes to pipe_b, reads from pipe_a. - TestEndpointChannel channel_a(pipe_b.first.get(), pipe_a.second.get()); - TestEndpointChannel channel_b(pipe_a.first.get(), pipe_b.second.get()); + auto channel_a = std::make_shared(pipe_b.first.get(), + pipe_a.second.get()); + auto channel_b = std::make_shared(pipe_a.first.get(), + pipe_b.second.get()); - ON_CALL(channel_a, GetMedium).WillByDefault([]() { + ON_CALL(*channel_a, GetMedium).WillByDefault([]() { return Medium::BLUETOOTH; }); - ON_CALL(channel_b, GetMedium).WillByDefault([]() { + ON_CALL(*channel_b, GetMedium).WillByDefault([]() { return Medium::BLUETOOTH; }); // Run DH key exchange; setup encryption contexts for channels. But only // encrypt |channel_b|. - auto [context_a, context_b] = DoDhKeyExchange(&channel_a, &channel_b); + auto [context_a, context_b] = DoDhKeyExchange(channel_a, channel_b); ASSERT_NE(context_a, nullptr); ASSERT_NE(context_b, nullptr); - channel_b.EnableEncryption(context_b); + channel_b->EnableEncryption(context_b); - EXPECT_EQ(channel_a.GetType(), "BLUETOOTH"); - EXPECT_EQ(channel_b.GetType(), "ENCRYPTED_BLUETOOTH"); + EXPECT_EQ(channel_a->GetType(), "BLUETOOTH"); + EXPECT_EQ(channel_b->GetType(), "ENCRYPTED_BLUETOOTH"); // An unencrypted KeepAlive should succeed. - ByteArray keep_alive_message = parser::ForKeepAlive(); - channel_a.Write(keep_alive_message); - ExceptionOr result = channel_b.Read(); + std::string keep_alive_message = parser::ForKeepAlive(); + channel_a->Write(keep_alive_message); + ExceptionOr result = channel_b->Read(); EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), keep_alive_message); + EXPECT_EQ(result.result().AsStringView(), keep_alive_message); // An unencrypted data frame should fail. - ByteArray tx_message{"data message"}; - channel_a.Write(tx_message); - result = channel_b.Read(); + absl::string_view tx_message = "data message"; + channel_a->Write(tx_message); + result = channel_b->Read(); EXPECT_FALSE(result.ok()); EXPECT_EQ(result.exception(), Exception::kInvalidProtocolBuffer); // Shutdown test environment. - channel_a.Close(DisconnectionReason::LOCAL_DISCONNECTION); - channel_b.Close(DisconnectionReason::REMOTE_DISCONNECTION); + channel_a->Close(DisconnectionReason::LOCAL_DISCONNECTION); + channel_b->Close(DisconnectionReason::REMOTE_DISCONNECTION); } } // namespace diff --git a/connections/implementation/base_pcp_handler.cc b/connections/implementation/base_pcp_handler.cc index 406d35f2..81bb0181 100644 --- a/connections/implementation/base_pcp_handler.cc +++ b/connections/implementation/base_pcp_handler.cc @@ -36,7 +36,9 @@ #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/analytics/connection_attempt_metadata_params.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/connections_authentication_transport.h" @@ -51,7 +53,6 @@ #include "connections/implementation/mediums/webrtc_peer_id.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/pcp.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/implementation/webrtc_state.h" #include "connections/listeners.h" #include "connections/medium_selector.h" @@ -84,11 +85,24 @@ #include "internal/platform/runnable.h" #include "internal/platform/wifi.h" #include "internal/platform/wifi_lan_connection_info.h" -#include "proto/connections_enums.pb.h" namespace nearby::connections { namespace { +using ::location::nearby::connections::ConnectionRequestFrame; +using ::location::nearby::connections::ConnectionResponseFrame; +using ::location::nearby::connections::ConnectionsDevice; +using ::location::nearby::connections::MediumMetadata; +using ::location::nearby::connections::OfflineFrame; +using ::location::nearby::connections::OsInfo; +using ::location::nearby::connections::PresenceDevice; +using ::location::nearby::connections::V1Frame; +using ::location::nearby::proto::connections::OperationResultCode; +using ::location::nearby::proto::connections::WifiDirectAuthType; +using ::nearby::analytics::AnalyticsRecorder; +using ::nearby::analytics::OperationResultWithMedium; +using ::securegcm::UKey2Handshake; + constexpr int kEndpointCancelAlarmTimeout = 10; std::string AuthenticationStatusToString(nearby::AuthenticationStatus status) { @@ -101,20 +115,8 @@ std::string AuthenticationStatusToString(nearby::AuthenticationStatus status) { return "failure"; } } -} // namespace -using ::location::nearby::analytics::proto::ConnectionsLog; -using ::location::nearby::connections::ConnectionRequestFrame; -using ::location::nearby::connections::ConnectionResponseFrame; -using ::location::nearby::connections::ConnectionsDevice; -using ::location::nearby::connections::MediumMetadata; -using ::location::nearby::connections::OfflineFrame; -using ::location::nearby::connections::OsInfo; -using ::location::nearby::connections::PresenceDevice; -using ::location::nearby::connections::V1Frame; -using ::location::nearby::proto::connections::OperationResultCode; -using ::location::nearby::proto::connections::WifiDirectAuthType; -using ::securegcm::UKey2Handshake; +} // namespace BasePcpHandler::BasePcpHandler(Mediums* mediums, EndpointManager* endpoint_manager, @@ -212,8 +214,7 @@ std::vector BasePcpHandler::GetConnectionInfoFromResult( } WifiLanConnectionInfo info( std::string(ip_address.begin(), ip_address.end()), - absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "", - {}); + absl::StrCat(absl::Hex(port, absl::kZeroPad16)), "", {}); connection_infos.push_back(info); } } @@ -279,11 +280,10 @@ Status BasePcpHandler::StartAdvertising( // Save the advertising options for local reference in later process // like upgrading bandwidth. advertising_listener_ = info.listener; - client->StartedAdvertising( - service_id, GetStrategy(), info.listener, - absl::MakeSpan(result.mediums), - std::move(result.operation_result_with_mediums), - compatible_advertising_options); + client->StartedAdvertising(service_id, GetStrategy(), info.listener, + absl::MakeSpan(result.mediums), + result.operation_result_with_mediums, + compatible_advertising_options); client->UpdateLocalEndpointInfo(info.endpoint_info.string_data()); response.Set({Status::kSuccess}); }); @@ -424,25 +424,25 @@ BooleanMediumSelector BasePcpHandler::ComputeIntersectionOfSupportedMediums( pending_connection_info.connection_options.connection_info .supported_wifi_direct_auth_types; LOG(INFO) << "Remote supported WifiDirect auth types: " - << absl::StrJoin( - remote_supported_wifi_direct_auth_types, ", ", - [](std::string* out, int auth_type) { - absl::StrAppend( - out, - WifiDirectAuthType_Name( - static_cast(auth_type))); - }); + << absl::StrJoin( + remote_supported_wifi_direct_auth_types, ", ", + [](std::string* out, int auth_type) { + absl::StrAppend( + out, + WifiDirectAuthType_Name( + static_cast(auth_type))); + }); auto local_supported_wifi_direct_auth_types = mediums_->GetWifiDirect().GetSupportedWifiDirectAuthTypes(); LOG(INFO) << "Local supported WifiDirect auth types: " - << absl::StrJoin( - local_supported_wifi_direct_auth_types, ", ", - [](std::string* out, int auth_type) { - absl::StrAppend( - out, - WifiDirectAuthType_Name( - static_cast(auth_type))); - }); + << absl::StrJoin( + local_supported_wifi_direct_auth_types, ", ", + [](std::string* out, int auth_type) { + absl::StrAppend( + out, + WifiDirectAuthType_Name( + static_cast(auth_type))); + }); bool found_common_auth_type = false; for (const auto& auth_type : local_supported_wifi_direct_auth_types) { if (auth_type == WifiDirectAuthType::WIFI_DIRECT_TYPE_UNKNOWN) { @@ -510,11 +510,11 @@ Status BasePcpHandler::StartDiscovery(ClientProxy* client, MutexLock lock(&discovered_endpoint_mutex_); discovered_endpoints_.clear(); } - client->StartedDiscovery( - service_id, GetStrategy(), std::move(listener), - absl::MakeSpan(result.mediums), - std::move(result.operation_result_with_mediums), - stripped_discovery_options); + client->StartedDiscovery(service_id, GetStrategy(), + std::move(listener), + absl::MakeSpan(result.mediums), + result.operation_result_with_mediums, + stripped_discovery_options); response.Set({Status::kSuccess}); }); return WaitForResult(absl::StrCat("StartDiscovery(", service_id, ")"), @@ -587,34 +587,50 @@ void BasePcpHandler::RunOnPcpHandlerThread(const std::string& name, serial_executor_.Execute(name, std::move(runnable)); } -EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() { +EncryptionRunner::ResultListener BasePcpHandler::GetResultListener( + std::shared_ptr endpoint_channel) { + std::weak_ptr weak_channel = endpoint_channel; + return { .on_success_cb = - [this](const std::string& endpoint_id, - std::unique_ptr ukey2, - const std::string& auth_token, - const ByteArray& raw_auth_token) { + [this, weak_channel](const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token) { + auto channel = weak_channel.lock(); + if (!channel) return; + RunOnPcpHandlerThread( "encryption-success", - [this, endpoint_id, raw_ukey2 = ukey2.release(), auth_token, - raw_auth_token]() RUN_ON_PCP_HANDLER_THREAD() mutable { - OnEncryptionSuccessRunnable( - endpoint_id, std::unique_ptr(raw_ukey2), - auth_token, raw_auth_token); - }); + [this, endpoint_id, weak_channel, raw_ukey2 = ukey2.release(), + auth_token, raw_auth_token]() + RUN_ON_PCP_HANDLER_THREAD() mutable { + std::unique_ptr ukey2(raw_ukey2); + auto channel = weak_channel.lock(); + if (!channel) return; + OnEncryptionSuccessRunnable(endpoint_id, std::move(ukey2), + auth_token, raw_auth_token, + channel); + }); }, .on_failure_cb = - [this](const std::string& endpoint_id, EndpointChannel* channel) { + [this, weak_channel](const std::string& endpoint_id) { + auto channel = weak_channel.lock(); + if (!channel) return; + RunOnPcpHandlerThread( "encryption-failure", - [this, endpoint_id, channel]() RUN_ON_PCP_HANDLER_THREAD() { - LOG(ERROR) - << "Encryption failed for endpoint_id=" << endpoint_id - << " on medium=" - << location::nearby::proto::connections::Medium_Name( - channel->GetMedium()); - OnEncryptionFailureRunnable(endpoint_id, channel); - }); + [this, endpoint_id, weak_channel]() + RUN_ON_PCP_HANDLER_THREAD() { + auto channel = weak_channel.lock(); + if (!channel) return; + LOG(ERROR) + << "Encryption failed for endpoint_id=" << endpoint_id + << " on medium=" + << location::nearby::proto::connections::Medium_Name( + channel->GetMedium()); + OnEncryptionFailureRunnable(endpoint_id, channel); + }); }, }; } @@ -622,36 +638,49 @@ EncryptionRunner::ResultListener BasePcpHandler::GetResultListener() { EncryptionRunner::ResultListener BasePcpHandler::GetResultListenerV3( const NearbyDeviceProvider& device_provider, const NearbyDevice& remote_device, - const EndpointChannel& endpoint_channel) { + std::shared_ptr endpoint_channel) { + std::weak_ptr weak_channel = endpoint_channel; + return { .on_success_cb = - [this, &device_provider, &remote_device, &endpoint_channel]( + [this, &device_provider, &remote_device, weak_channel]( const std::string& endpoint_id, std::unique_ptr ukey2, const std::string& auth_token, const ByteArray& raw_auth_token) { + auto channel = weak_channel.lock(); + if (!channel) return; + RunOnPcpHandlerThread( "encryption-success", - [this, &device_provider, &remote_device, &endpoint_channel, - raw_ukey2 = ukey2.release(), auth_token, - raw_auth_token]() RUN_ON_PCP_HANDLER_THREAD() mutable { - OnEncryptionSuccessRunnableV3( - remote_device, std::unique_ptr(raw_ukey2), - auth_token, raw_auth_token, endpoint_channel, - device_provider); - }); + [this, &device_provider, &remote_device, weak_channel, + raw_ukey2 = ukey2.release(), auth_token, raw_auth_token]() + RUN_ON_PCP_HANDLER_THREAD() mutable { + std::unique_ptr ukey2(raw_ukey2); + auto channel = weak_channel.lock(); + if (!channel) return; + OnEncryptionSuccessRunnableV3( + remote_device, std::move(ukey2), auth_token, + raw_auth_token, channel, device_provider); + }); }, .on_failure_cb = - [this](const std::string& endpoint_id, EndpointChannel* channel) { + [this, weak_channel](const std::string& endpoint_id) { + auto channel = weak_channel.lock(); + if (!channel) return; + RunOnPcpHandlerThread( "encryption-failure", - [this, endpoint_id, channel]() RUN_ON_PCP_HANDLER_THREAD() { - LOG(ERROR) - << "Encryption failed for endpoint_id=" << endpoint_id - << " on medium=" - << location::nearby::proto::connections::Medium_Name( - channel->GetMedium()); - OnEncryptionFailureRunnable(endpoint_id, channel); - }); + [this, endpoint_id, weak_channel]() + RUN_ON_PCP_HANDLER_THREAD() { + auto channel = weak_channel.lock(); + if (!channel) return; + LOG(ERROR) + << "Encryption failed for endpoint_id=" << endpoint_id + << " on medium=" + << location::nearby::proto::connections::Medium_Name( + channel->GetMedium()); + OnEncryptionFailureRunnable(endpoint_id, channel); + }); }, }; } @@ -659,7 +688,7 @@ EncryptionRunner::ResultListener BasePcpHandler::GetResultListenerV3( void BasePcpHandler::OnEncryptionSuccessRunnableV3( const NearbyDevice& remote_device, std::unique_ptr ukey2, absl::string_view auth_token, const ByteArray& raw_auth_token, - const EndpointChannel& endpoint_channel, + std::shared_ptr endpoint_channel, const NearbyDeviceProvider& device_provider) { // Quick fail if we've been removed from pending connections while we were // busy running UKEY2. @@ -674,7 +703,11 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3( } BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second; - + // Verify pointer equality to avoid accidental action on superseded + // channels. + if (endpoint_channel != pending_connection_info.channel) { + return; + } // TODO(b/300149127): Add test coverage. if (!ukey2) { // Fail early, if there is no crypto context. @@ -697,8 +730,15 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3( // // TODO(b/305004353): Authenticate the connection in the responder role for // outgoing connections. - if (!pending_connection_info.is_incoming) { + if (pending_connection_info.is_incoming) { LOG(ERROR) << __func__ << ": only outgoing connections are supported"; + ProcessPreConnectionInitiationFailure( + pending_connection_info.client, pending_connection_info.medium, + remote_device.GetEndpointId(), pending_connection_info.channel.get(), + pending_connection_info.is_incoming, /*log_failure=*/true, + pending_connection_info.start_time, {Status::kConnectionRejected}, + OperationResultCode::DETAIL_UNKNOWN, + pending_connection_info.result.lock().get()); return; } @@ -724,7 +764,8 @@ void BasePcpHandler::OnEncryptionSuccessRunnableV3( void BasePcpHandler::OnEncryptionSuccessRunnable( const std::string& endpoint_id, std::unique_ptr ukey2, - const std::string& auth_token, const ByteArray& raw_auth_token) { + const std::string& auth_token, const ByteArray& raw_auth_token, + std::shared_ptr endpoint_channel) { // Quick fail if we've been removed from pending connections while we were // busy running UKEY2. // TODO(b/316421187): Add test coverage @@ -738,6 +779,12 @@ void BasePcpHandler::OnEncryptionSuccessRunnable( BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second; + // Verify pointer equality to avoid accidental action on superseded + // channels. + if (endpoint_channel != pending_connection_info.channel) { + return; + } + if (!ukey2) { // Fail early, if there is no crypto context. ProcessPreConnectionInitiationFailure( @@ -801,24 +848,21 @@ void BasePcpHandler::RegisterDeviceAfterEncryptionSuccess( } void BasePcpHandler::OnEncryptionFailureRunnable( - const std::string& endpoint_id, EndpointChannel* endpoint_channel) { + const std::string& endpoint_id, + std::shared_ptr endpoint_channel) { auto it = pending_connections_.find(endpoint_id); if (it == pending_connections_.end()) { LOG(INFO) - << "Connection not found on UKEY negotination complete; endpoint_id=" + << "Connection not found on UKEY negotiation complete; endpoint_id=" << endpoint_id; return; } BasePcpHandler::PendingConnectionInfo& pending_connection_info = it->second; - // We had a bug here, caused by a race with EncryptionRunner. We now verify - // the EndpointChannel to avoid it. In a simultaneous connection, we clean - // up one of the two EndpointChannels and then update our pendingConnections - // with the winning channel's state. Closing a channel that was in the - // middle of EncryptionRunner would trigger onEncryptionFailed, and, since - // the map had already updated with the winning EndpointChannel, we closed - // it too by accident. - if (*endpoint_channel != *pending_connection_info.channel) { + + // Verify pointer equality to avoid accidental action on superseded + // channels. + if (endpoint_channel != pending_connection_info.channel) { LOG(INFO) << "Not destroying channel [mismatch]: passed=" << endpoint_channel->GetName() << "; expected=" << pending_connection_info.channel->GetName(); @@ -871,8 +915,8 @@ ConnectionInfo BasePcpHandler::FillConnectionInfo( connection_info.supported_wifi_direct_auth_types = mediums_->GetWifiDirect().GetSupportedWifiDirectAuthTypes(); VLOG(1) << "Set SupportedWifiDirectAuthTypes for WIFI_DIRECT: " - << absl::StrJoin(connection_info.supported_wifi_direct_auth_types, - ","); + << absl::StrJoin(connection_info.supported_wifi_direct_auth_types, + ","); } else { connection_info.supported_wifi_direct_auth_types = {}; } @@ -975,8 +1019,8 @@ Status BasePcpHandler::RequestConnection( client, channel_medium, endpoint_id, channel.get(), /*is_incoming=*/false, /*log_failure=*/true, start_time, {Status::kEndpointIoError}, - client->GetAnalyticsRecorder() - .GetChannelIoErrorResultCodeFromMedium(channel_medium), + AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium( + channel_medium), result.get()); return; } @@ -1005,17 +1049,32 @@ Status BasePcpHandler::RequestConnection( pending_connection_info.medium = channel->GetMedium(); pending_connection_info.channel = std::move(channel); - EndpointChannel* endpoint_channel = - pending_connections_ - .emplace(endpoint_id, std::move(pending_connection_info)) - .first->second.channel.get(); + std::shared_ptr channel_to_close_on_failure = + pending_connection_info.channel; + auto [it, inserted] = pending_connections_.emplace( + endpoint_id, std::move(pending_connection_info)); + if (!inserted) { + LOG(ERROR) << "Failed to add outgoing connection to pending set; " + "endpoint_id=" + << endpoint_id + << ". Likely a collision with an existing pending " + "connection."; + if (channel_to_close_on_failure) { + channel_to_close_on_failure->Close( + location::nearby::proto::connections::DisconnectionReason:: + IO_ERROR); + } + result->Set({Status::kEndpointIoError}); + return; + } + std::shared_ptr endpoint_channel = it->second.channel; LOG(INFO) << "Initiating secure connection: endpoint_id=" << endpoint_id; // Next, we'll set up encryption. When it's done, our future will return // and RequestConnection() will finish. encryption_runner_.StartClient(client, endpoint_id, endpoint_channel, - GetResultListener()); + GetResultListener(endpoint_channel)); }); LOG(INFO) << "Waiting for connection to complete: endpoint_id=" << endpoint_id; @@ -1122,8 +1181,8 @@ Status BasePcpHandler::RequestConnectionV3( client, channel_medium, endpoint_id, channel.get(), /*is_incoming=*/false, /*log_failure=*/true, start_time, {Status::kEndpointIoError}, - client->GetAnalyticsRecorder() - .GetChannelIoErrorResultCodeFromMedium(channel_medium), + AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium( + channel_medium), result.get()); return; } @@ -1144,7 +1203,7 @@ Status BasePcpHandler::RequestConnectionV3( pending_connection_info.client = client; pending_connection_info.remote_endpoint_info = endpoint->endpoint_info; pending_connection_info.nonce = connection_info.nonce; - pending_connection_info.is_incoming = true; + pending_connection_info.is_incoming = false; pending_connection_info.start_time = start_time; pending_connection_info.listener = info.listener; pending_connection_info.connection_options = connection_options; @@ -1152,10 +1211,25 @@ Status BasePcpHandler::RequestConnectionV3( pending_connection_info.medium = channel->GetMedium(); pending_connection_info.channel = std::move(channel); - EndpointChannel* endpoint_channel = - pending_connections_ - .emplace(endpoint_id, std::move(pending_connection_info)) - .first->second.channel.get(); + std::shared_ptr channel_to_close_on_failure = + pending_connection_info.channel; + auto [it, inserted] = pending_connections_.emplace( + endpoint_id, std::move(pending_connection_info)); + if (!inserted) { + LOG(ERROR) << "Failed to add outgoing connection to pending set; " + "endpoint_id=" + << endpoint_id + << ". Likely a collision with an existing pending " + "connection."; + if (channel_to_close_on_failure) { + channel_to_close_on_failure->Close( + location::nearby::proto::connections::DisconnectionReason:: + IO_ERROR); + } + result->Set({Status::kEndpointIoError}); + return; + } + std::shared_ptr endpoint_channel = it->second.channel; LOG(INFO) << "Initiating secure connection: endpoint_id=" << endpoint_id; @@ -1165,7 +1239,7 @@ Status BasePcpHandler::RequestConnectionV3( encryption_runner_.StartClient( client, endpoint_id, endpoint_channel, GetResultListenerV3(*(client->GetLocalDeviceProvider()), - remote_device, *endpoint_channel)); + remote_device, endpoint_channel)); }); LOG(INFO) << "Waiting for connection to complete: endpoint_id=" << endpoint_id; @@ -1231,22 +1305,21 @@ void BasePcpHandler::StripOutUnavailableMediums( } } -std::unique_ptr +OperationResultWithMedium BasePcpHandler::GetOperationResultWithMediumByResultCode( ClientProxy* client, location::nearby::proto::connections::Medium medium, int update_index, location::nearby::proto::connections::OperationResultCode operation_result_code, location::nearby::proto::connections::ConnectionMode connection_mode) { - auto operation_result_with_medium = - std::make_unique(); - operation_result_with_medium->set_medium(medium); - operation_result_with_medium->set_result_code(operation_result_code); - operation_result_with_medium->set_result_category( + OperationResultWithMedium operation_result_with_medium; + operation_result_with_medium.set_medium(medium); + operation_result_with_medium.set_result_code(operation_result_code); + operation_result_with_medium.set_result_category( client->GetAnalyticsRecorder().GetOperationResultCategory( operation_result_code)); - operation_result_with_medium->set_connection_mode(connection_mode); - operation_result_with_medium->set_update_index(update_index); + operation_result_with_medium.set_connection_mode(connection_mode); + operation_result_with_medium.set_update_index(update_index); return operation_result_with_medium; } @@ -1600,8 +1673,7 @@ Status BasePcpHandler::RejectConnection(ClientProxy* client, void BasePcpHandler::OnIncomingFrame( OfflineFrame& frame, const std::string& endpoint_id, ClientProxy* client, - location::nearby::proto::connections::Medium medium, - PacketMetaData& packet_meta_data) { + location::nearby::proto::connections::Medium medium) { CountDownLatch latch(1); RunOnPcpHandlerThread( "incoming-frame", @@ -1967,8 +2039,7 @@ Exception BasePcpHandler::OnIncomingConnection( /*is_incoming=*/true, /*log_failure=*/wrapped_frame.exception() != Exception::kNoData, start_time, {Status::kError}, - client->GetAnalyticsRecorder().GetChannelIoErrorResultCodeFromMedium( - medium), + AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium(medium), nullptr); } return wrapped_frame.GetException(); @@ -2133,14 +2204,23 @@ Exception BasePcpHandler::OnIncomingConnection( pending_connection_info.medium = channel->GetMedium(); pending_connection_info.channel = std::move(channel); - auto* owned_channel = pending_connections_ - .emplace(connection_request.endpoint_id(), - std::move(pending_connection_info)) - .first->second.channel.get(); + auto [it, inserted] = pending_connections_.emplace( + connection_request.endpoint_id(), std::move(pending_connection_info)); + // This should not happen since BreakTie() above should have checked that + // the endpoint_id is not already in pending_connections_. + if (!inserted) { + LOG(ERROR) << "Failed to add incoming connection to pending set; " + "endpoint_id=" + << connection_request.endpoint_id() + << ". Likely a collision with an existing pending connection."; + return {Exception::kIo}; + } + std::shared_ptr endpoint_channel = it->second.channel; // Next, we'll set up encryption. encryption_runner_.StartServer(client, connection_request.endpoint_id(), - owned_channel, GetResultListener()); + endpoint_channel, + GetResultListener(endpoint_channel)); return {Exception::kSuccess}; } @@ -2477,8 +2557,8 @@ ExceptionOr BasePcpHandler::ReadConnectionRequestFrame( return ExceptionOr(wrapped_bytes.exception()); } - ByteArray bytes = std::move(wrapped_bytes.result()); - ExceptionOr wrapped_frame = parser::FromBytes(bytes); + ExceptionOr wrapped_frame = + parser::FromBytes(wrapped_bytes.result().AsStringView()); if (wrapped_frame.GetException().Raised(Exception::kInvalidProtocolBuffer)) { return ExceptionOr(Exception::kIo); } @@ -2510,7 +2590,7 @@ void BasePcpHandler::LogConnectionAttemptFailure( connections_attempt_metadata_params; if (endpoint_channel != nullptr) { connections_attempt_metadata_params = - client->GetAnalyticsRecorder().BuildConnectionAttemptMetadataParams( + AnalyticsRecorder::BuildConnectionAttemptMetadataParams( endpoint_channel->GetTechnology(), endpoint_channel->GetBand(), endpoint_channel->GetFrequency(), endpoint_channel->GetTryCount()); connections_attempt_metadata_params->operation_result_code = @@ -2536,12 +2616,11 @@ void BasePcpHandler::LogConnectionAttemptSuccess( connections_attempt_metadata_params; if (pending_connection_info.channel != nullptr) { connections_attempt_metadata_params = - pending_connection_info.client->GetAnalyticsRecorder() - .BuildConnectionAttemptMetadataParams( - pending_connection_info.channel->GetTechnology(), - pending_connection_info.channel->GetBand(), - pending_connection_info.channel->GetFrequency(), - pending_connection_info.channel->GetTryCount()); + AnalyticsRecorder::BuildConnectionAttemptMetadataParams( + pending_connection_info.channel->GetTechnology(), + pending_connection_info.channel->GetBand(), + pending_connection_info.channel->GetFrequency(), + pending_connection_info.channel->GetTryCount()); connections_attempt_metadata_params->operation_result_code = OperationResultCode::DETAIL_SUCCESS; } else { diff --git a/connections/implementation/base_pcp_handler.h b/connections/implementation/base_pcp_handler.h index a1c3db7c..49cf0b70 100644 --- a/connections/implementation/base_pcp_handler.h +++ b/connections/implementation/base_pcp_handler.h @@ -31,7 +31,7 @@ #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" -#include "connections/implementation/analytics/packet_meta_data.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" @@ -158,10 +158,10 @@ class BasePcpHandler : public PcpHandler, const std::string& endpoint_id) override; // @EndpointManagerReaderThread - void OnIncomingFrame(location::nearby::connections::OfflineFrame& frame, - const std::string& endpoint_id, ClientProxy* client, - location::nearby::proto::connections::Medium medium, - analytics::PacketMetaData& packet_meta_data) override; + void OnIncomingFrame( + location::nearby::connections::OfflineFrame& frame, + const std::string& endpoint_id, ClientProxy* client, + location::nearby::proto::connections::Medium medium) override; // Called when an endpoint disconnects while we're waiting for both sides to // approve/reject the connection. @@ -190,8 +190,7 @@ class BasePcpHandler : public PcpHandler, // If success, the mediums on which we are now advertising/discovering, for // analytics. std::vector mediums; - std::vector + std::vector operation_result_with_mediums; }; @@ -413,8 +412,7 @@ class BasePcpHandler : public PcpHandler, void StripOutWifiHotspotMedium(ConnectionInfo& connection_info); - std::unique_ptr + nearby::analytics::OperationResultWithMedium GetOperationResultWithMediumByResultCode( ClientProxy* client, location::nearby::proto::connections::Medium medium, int update_index, @@ -476,11 +474,11 @@ class BasePcpHandler : public PcpHandler, // Only (possibly) vector for incoming connections. std::vector supported_mediums; - // Keep track of a channel before we pass it to EndpointChannelManager. This - // is owned until the call to OnEncryptionSuccessRunnableV3 or - // OnEncryptionSuccessRunnable when ownership is transferred to the - // EndpointManager. - std::unique_ptr channel; + // Keep track of a channel before it is registered with the + // EndpointManager. This reference is held during the handshake phase and + // passed to the EndpointManager upon successful encryption + // (OnEncryptionSuccessRunnableV3 or OnEncryptionSuccessRunnable). + std::shared_ptr channel; // Crypto context; initially empty; established first thing after channel // creation by running UKey2 session. While it is in progress, we keep track @@ -509,24 +507,27 @@ class BasePcpHandler : public PcpHandler, void OnEncryptionFailureImpl(const std::string& endpoint_id, EndpointChannel* channel); - EncryptionRunner::ResultListener GetResultListener(); + EncryptionRunner::ResultListener GetResultListener( + std::shared_ptr endpoint_channel); EncryptionRunner::ResultListener GetResultListenerV3( const NearbyDeviceProvider& device_provider, const NearbyDevice& remote_device, - const EndpointChannel& endpoint_channel); + std::shared_ptr endpoint_channel); void OnEncryptionSuccessRunnable( const std::string& endpoint_id, std::unique_ptr ukey2, - const std::string& auth_token, const ByteArray& raw_auth_token); + const std::string& auth_token, const ByteArray& raw_auth_token, + std::shared_ptr endpoint_channel); void OnEncryptionSuccessRunnableV3( const NearbyDevice& remote_device, std::unique_ptr<::securegcm::UKey2Handshake> ukey2, absl::string_view auth_token, const ByteArray& raw_auth_token, - const EndpointChannel& endpoint_channel, + std::shared_ptr endpoint_channel, const NearbyDeviceProvider& device_provider); - void OnEncryptionFailureRunnable(const std::string& endpoint_id, - EndpointChannel* endpoint_channel); + void OnEncryptionFailureRunnable( + const std::string& endpoint_id, + std::shared_ptr endpoint_channel); void RegisterDeviceAfterEncryptionSuccess( std::string_view endpoint_id, std::unique_ptr<::securegcm::UKey2Handshake> ukey2, diff --git a/connections/implementation/base_pcp_handler_test.cc b/connections/implementation/base_pcp_handler_test.cc index 10f6bdd7..b8cef7e5 100644 --- a/connections/implementation/base_pcp_handler_test.cc +++ b/connections/implementation/base_pcp_handler_test.cc @@ -32,7 +32,8 @@ #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" -#include "connections/implementation/analytics/packet_meta_data.h" +#include "connections/implementation/analytics/analytics_recorder.h" +#include "connections/implementation/analytics/mock_analytics_recorder.h" #include "connections/implementation/base_endpoint_channel.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" @@ -55,8 +56,6 @@ #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/connection_listening_options.h" -#include "internal/analytics/mock_event_logger.h" -#include "internal/analytics/sharing_log_matchers.h" #include "internal/flags/nearby_flags.h" #include "internal/interop/authentication_status.h" #include "internal/interop/authentication_transport.h" @@ -72,29 +71,21 @@ #include "internal/platform/medium_environment.h" #include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" -#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" #include "proto/connections_enums.proto.h" -namespace nearby { -namespace connections { +namespace nearby::connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::OsInfo; -using ::location::nearby::proto::connections::EventType; using ::location::nearby::proto::connections::Medium; -using ::nearby::analytics::HasEventType; using ::testing::_; using ::testing::AtLeast; -using ::protobuf_matchers::EqualsProto; -using ::testing::Invoke; using ::testing::Matcher; using ::testing::MockFunction; using ::testing::NiceMock; using ::testing::Return; using ::testing::StrictMock; -using ::testing::proto::Partially; constexpr absl::string_view kTestEndpointId = "REMOTETEST"; @@ -171,7 +162,7 @@ class MockEndpointChannel : public BaseEndpointChannel { output_stream_(std::move(writer)) {} ExceptionOr DoRead() { return BaseEndpointChannel::Read(); } - Exception DoWrite(const ByteArray& data) { + Exception DoWrite(absl::string_view data) { if (broken_write_) { return {Exception::kFailed}; } @@ -182,7 +173,7 @@ class MockEndpointChannel : public BaseEndpointChannel { } MOCK_METHOD(ExceptionOr, Read, (), (override)); - MOCK_METHOD(Exception, Write, (const ByteArray& data), (override)); + MOCK_METHOD(Exception, Write, (absl::string_view data), (override)); MOCK_METHOD(void, CloseImpl, (), (override)); MOCK_METHOD(location::nearby::proto::connections::Medium, GetMedium, (), (const, override)); @@ -454,15 +445,20 @@ class BasePcpHandlerTest }; BasePcpHandlerTest() { - client_ = std::make_unique(&mock_event_logger_); + client_ = std::make_unique(CreateAnalyticsRecorder()); } void SetUp() override { MacAddress::FromString("12:34:56:78:9a:bc", remote_mac_address_); } - void TearDown() override { - env_.Stop(); + void TearDown() override { env_.Stop(); } + + std::unique_ptr CreateAnalyticsRecorder() { + auto recorder = + std::make_unique(); + mock_analytics_recorder_ptr_ = recorder.get(); + return recorder; } void StartAdvertising(ClientProxy* client, MockPcpHandler* pcp_handler, @@ -576,26 +572,26 @@ class BasePcpHandlerTest // the peer channel. The rest of the exchange must happen for the benefit of // DH key exchange. EXPECT_CALL(*channel_a, Read()) - .WillRepeatedly(Invoke( - [channel = channel_a.get()]() { return channel->DoRead(); })); + .WillRepeatedly( + [channel = channel_a.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_a, Write(_)) .WillOnce(Return(Exception{Exception::kSuccess})) .WillRepeatedly( - Invoke([channel = channel_a.get()](const ByteArray& data) { + [channel = channel_a.get()](absl::string_view data) { return channel->DoWrite(data); - })); + }); EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_a, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false)); EXPECT_CALL(*channel_b, Read()) - .WillRepeatedly(Invoke( - [channel = channel_b.get()]() { return channel->DoRead(); })); + .WillRepeatedly( + [channel = channel_b.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_b, Write(_)) .WillRepeatedly( - Invoke([channel = channel_b.get()](const ByteArray& data) { + [channel = channel_b.get()](absl::string_view data) { return channel->DoWrite(data); - })); + }); EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_b, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); @@ -622,20 +618,20 @@ class BasePcpHandlerTest // the peer channel. The rest of the exchange must happen for the benefit of // DH key exchange. EXPECT_CALL(*channel_a, Read()) - .WillRepeatedly(Invoke( - [channel = channel_a.get()]() { return channel->DoRead(); })); + .WillRepeatedly( + [channel = channel_a.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_a, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_a, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); EXPECT_CALL(*channel_a, IsPaused).WillRepeatedly(Return(false)); EXPECT_CALL(*channel_b, Read()) - .WillRepeatedly(Invoke( - [channel = channel_b.get()]() { return channel->DoRead(); })); + .WillRepeatedly( + [channel = channel_b.get()]() { return channel->DoRead(); }); EXPECT_CALL(*channel_b, Write(_)) .WillRepeatedly( - Invoke([channel = channel_b.get()](const ByteArray& data) { + [channel = channel_b.get()](absl::string_view data) { return channel->DoWrite(data); - })); + }); EXPECT_CALL(*channel_b, GetMedium).WillRepeatedly(Return(medium)); EXPECT_CALL(*channel_b, GetLastReadTimestamp) .WillRepeatedly(Return(absl::Now())); @@ -646,7 +642,7 @@ class BasePcpHandlerTest void RequestConnection( const std::string& endpoint_id, std::unique_ptr channel_a, - MockEndpointChannel* channel_b, ClientProxy* client, + std::shared_ptr channel_b, ClientProxy* client, MockPcpHandler* pcp_handler, location::nearby::proto::connections::Medium connect_medium, std::atomic_int* flag = nullptr, @@ -675,15 +671,15 @@ class BasePcpHandlerTest auto allowed_mediums = pcp_handler->GetDiscoveryMediums(client); EXPECT_CALL(*pcp_handler, ConnectImpl) - .WillOnce(Invoke([&channel_a, connect_medium]( - ClientProxy* client, - MockPcpHandler::DiscoveredEndpoint* endpoint) { + .WillOnce([&channel_a, connect_medium]( + ClientProxy* client, + MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ .medium = connect_medium, .status = {Status::kSuccess}, .endpoint_channel = std::move(channel_a), }; - })); + }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( @@ -716,7 +712,7 @@ class BasePcpHandlerTest void RequestConnectionV3( const NearbyDevice& remote_device, std::unique_ptr channel_a, - MockEndpointChannel* channel_b, ClientProxy* client, + std::shared_ptr channel_b, ClientProxy* client, MockPcpHandler* pcp_handler, location::nearby::proto::connections::Medium connect_medium, FakePresenceDeviceProvider* fake_presence_device_provider, @@ -756,15 +752,15 @@ class BasePcpHandlerTest EXPECT_CALL(*pcp_handler, ConnectImpl) .WillRepeatedly( - Invoke([&channel_a, connect_medium]( - ClientProxy* client, - MockPcpHandler::DiscoveredEndpoint* endpoint) { + [&channel_a, connect_medium]( + ClientProxy* client, + MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ .medium = connect_medium, .status = {Status::kSuccess}, .endpoint_channel = std::move(channel_a), }; - })); + }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( @@ -796,7 +792,7 @@ class BasePcpHandlerTest void RequestConnectionWifiLanFail( const std::string& endpoint_id, std::unique_ptr channel_a, - MockEndpointChannel* channel_b, ClientProxy* client, + std::shared_ptr channel_b, ClientProxy* client, MockPcpHandler* pcp_handler, std::atomic_int* flag = nullptr, Status expected_result = {Status::kSuccess}) { ConnectionRequestInfo info{ @@ -824,8 +820,8 @@ class BasePcpHandlerTest EXPECT_CALL(*pcp_handler, ConnectImpl) .WillRepeatedly( - Invoke([&channel_a](ClientProxy* client, - MockPcpHandler::DiscoveredEndpoint* endpoint) { + [&channel_a](ClientProxy* client, + MockPcpHandler::DiscoveredEndpoint* endpoint) { if (endpoint->medium == location::nearby::proto::connections::WIFI_LAN) { LOG(INFO) << "Connect with Medium WIFI_LAN failed."; @@ -844,7 +840,7 @@ class BasePcpHandlerTest .endpoint_channel = std::move(channel_a), }; } - })); + }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler->OnEndpointFound( @@ -900,7 +896,7 @@ class BasePcpHandlerTest MediumEnvironment& env_ = MediumEnvironment::Instance(); NiceMock mock_device_; MacAddress remote_mac_address_; - nearby::analytics::MockEventLogger mock_event_logger_; + nearby::analytics::MockAnalyticsRecorder* mock_analytics_recorder_ptr_; std::unique_ptr client_; }; @@ -1137,12 +1133,13 @@ TEST_F(BasePcpHandlerTest, WifiMediumFailFallBackToBT) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a), - channel_b.get(), client_.get(), &pcp_handler); + RequestConnectionWifiLanFail(endpoint_id, std::move(channel_a), channel_b, + client_.get(), &pcp_handler); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); @@ -1162,12 +1159,13 @@ TEST_P(BasePcpHandlerTest, RequestConnectionChangesState) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnection("1234", std::move(channel_a), channel_b.get(), - client_.get(), &pcp_handler, connect_medium); + RequestConnection("1234", std::move(channel_a), channel_b, client_.get(), + &pcp_handler, connect_medium); LOG(INFO) << "RequestConnection complete"; EXPECT_TRUE(pcp_handler.HasOutgoingConnections(client_.get())); EXPECT_FALSE(pcp_handler.HasIncomingConnections(client_.get())); @@ -1208,12 +1206,13 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionPresence) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnection("1234", std::move(channel_a), channel_b.get(), - client_.get(), &pcp_handler, connect_medium); + RequestConnection("1234", std::move(channel_a), channel_b, client_.get(), + &pcp_handler, connect_medium); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); @@ -1237,12 +1236,13 @@ TEST_P(BasePcpHandlerTest, CanRequestConnectionLegacy) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnection("1234", std::move(channel_a), channel_b.get(), - client_.get(), &pcp_handler, connect_medium); + RequestConnection("1234", std::move(channel_a), channel_b, client_.get(), + &pcp_handler, connect_medium); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); bwu.Shutdown(); @@ -1267,11 +1267,12 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - const auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(), + RequestConnectionV3(mock_device_, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &provider); LOG(INFO) << "RequestConnectionV3 complete"; channel_b->Close(); @@ -1298,12 +1299,13 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_AuthenticationFailure) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - const auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); RequestConnectionV3( - mock_device_, std::move(channel_a), channel_b.get(), client_.get(), + mock_device_, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &provider, /*flag=*/nullptr, /*expected_result=*/{Status::kSuccess}, /*expected_authentication_status=*/AuthenticationStatus::kFailure); @@ -1329,7 +1331,8 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) { auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnectionForConnectFailure(connect_medium); - const auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); ConnectionRequestInfo info{ @@ -1353,7 +1356,7 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) { auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get()); EXPECT_CALL(pcp_handler, ConnectImpl) - .WillRepeatedly(Invoke( + .WillRepeatedly( [connect_medium](ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ @@ -1361,7 +1364,7 @@ TEST_P(BasePcpHandlerTest, RequestConnectionV3_ConnectImplFailure) { .status = {Status::kError}, .endpoint_channel = nullptr, }; - })); + }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler.OnEndpointFound( @@ -1404,7 +1407,8 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) { auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnectionForConnectFailure(connect_medium); - const auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); ConnectionRequestInfo info{ @@ -1428,7 +1432,7 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) { auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get()); EXPECT_CALL(pcp_handler, ConnectImpl) - .WillRepeatedly(Invoke( + .WillRepeatedly( [connect_medium](ClientProxy* client, MockPcpHandler::DiscoveredEndpoint* endpoint) { return MockPcpHandler::ConnectImplResult{ @@ -1436,7 +1440,7 @@ TEST_P(BasePcpHandlerTest, RequestConnection_ConnectImplFailure) { .status = {Status::kError}, .endpoint_channel = nullptr, }; - })); + }); for (const auto& discovered_medium : allowed_mediums) { pcp_handler.OnEndpointFound( @@ -1476,12 +1480,13 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionV3Fails) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1)); EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1)); channel_b->broken_write_ = true; EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnectionV3(mock_device_, std::move(channel_a), channel_b.get(), + RequestConnectionV3(mock_device_, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, nullptr, nullptr, {Status::kEndpointIoError}); LOG(INFO) << "RequestConnectionV3 complete"; @@ -1504,13 +1509,14 @@ TEST_P(BasePcpHandlerTest, IoError_RequestConnectionFails) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(AtLeast(1)); EXPECT_CALL(*channel_b, CloseImpl).Times(AtLeast(1)); channel_b->broken_write_ = true; EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(AtLeast(0)); - RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), - client_.get(), &pcp_handler, connect_medium, nullptr, + RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), + &pcp_handler, connect_medium, nullptr, {Status::kEndpointIoError}); LOG(INFO) << "RequestConnection complete"; channel_b->Close(); @@ -1532,11 +1538,12 @@ TEST_P(BasePcpHandlerTest, AcceptConnectionChangesState) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); - RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), - client_.get(), &pcp_handler, connect_medium); + RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), + &pcp_handler, connect_medium); LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id; EXPECT_EQ(pcp_handler.AcceptConnection(client_.get(), endpoint_id, {}), Status{Status::kSuccess}); @@ -1560,9 +1567,10 @@ TEST_P(BasePcpHandlerTest, RejectConnectionChangesState) { auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(mock_connection_listener_.rejected_cb, Call).Times(1); - RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b.get(), + RequestConnection(endpoint_id, std::move(channel_pair.first), channel_b, client_.get(), &pcp_handler, connect_medium); LOG(INFO) << "Attempting to reject connection: id=" << endpoint_id; EXPECT_EQ(pcp_handler.RejectConnection(client_.get(), endpoint_id), @@ -1582,17 +1590,17 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) { EndpointManager em(&ecm); BwuManager bwu(m, em, ecm, {}, {}); MockPcpHandler pcp_handler(&m, &em, &ecm, &bwu); - analytics::PacketMetaData packet_meta_data; StartDiscovery(client_.get(), &pcp_handler); auto mediums = pcp_handler.GetDiscoveryMediums(client_.get()); auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); - RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), - client_.get(), &pcp_handler, connect_medium); + RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), + &pcp_handler, connect_medium); LOG(INFO) << "Attempting to accept connection: id=" << endpoint_id; EXPECT_CALL(mock_connection_listener_.accepted_cb, Call).Times(1); EXPECT_CALL(mock_connection_listener_.disconnected_cb, Call) @@ -1605,7 +1613,7 @@ TEST_P(BasePcpHandlerTest, OnIncomingFrameChangesState) { Status::kSuccess, os_info, /*multiplex_socket_bitmask=*/0)); EXPECT_CALL(mock_connection_listener_.bandwidth_changed_cb, Call).Times(1); pcp_handler.OnIncomingFrame(frame.result(), endpoint_id, client_.get(), - connect_medium, packet_meta_data); + connect_medium); LOG(INFO) << "Closing connection: id=" << endpoint_id; channel_b->Close(); bwu.Shutdown(); @@ -1629,10 +1637,11 @@ TEST_P(BasePcpHandlerTest, DestructorIsCalledOnProtocolEndpoint) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); - RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), + RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &destroyed_flag); mediums_count = mediums.size(); @@ -1671,11 +1680,12 @@ TEST_P(BasePcpHandlerTest, MultipleMediumsProduceSingleEndpointLostEvent) { auto connect_medium = mediums[mediums.size() - 1]; auto channel_pair = SetupConnection(connect_medium); auto& channel_a = channel_pair.first; - auto& channel_b = channel_pair.second; + std::shared_ptr channel_b = + std::move(channel_pair.second); EXPECT_CALL(*channel_a, CloseImpl).Times(1); EXPECT_CALL(*channel_b, CloseImpl).Times(1); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call).Times(1); - RequestConnection(endpoint_id, std::move(channel_a), channel_b.get(), + RequestConnection(endpoint_id, std::move(channel_a), channel_b, client_.get(), &pcp_handler, connect_medium, &destroyed_flag); auto allowed_mediums = pcp_handler.GetDiscoveryMediums(client_.get()); @@ -1787,7 +1797,7 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) { EXPECT_TRUE(client_->IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl(client_.get(), service_id, _)) - .WillOnce(Invoke([&pcp_handler, &endpoint_id]( + .WillOnce([&pcp_handler, &endpoint_id]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { pcp_handler.OnEndpointFound( @@ -1803,7 +1813,7 @@ TEST_F(BasePcpHandlerTest, InjectEndpoint) { MockContext{nullptr}, })); return Status{Status::kSuccess}; - })); + }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ @@ -1851,30 +1861,30 @@ TEST_F(BasePcpHandlerTest, ::testing::InSequence seq; EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call) - .WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id, + .WillOnce([id = endpoint_id](const std::string& endpoint_id, const ByteArray& endpoint_info, const std::string& service_id) { EXPECT_EQ(endpoint_id, id); EXPECT_EQ(endpoint_info, ByteArray{"ABCD"}); - })); + }); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call) - .WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id) { + .WillOnce([id = endpoint_id](const std::string& endpoint_id) { EXPECT_EQ(endpoint_id, id); - })); + }); EXPECT_CALL(mock_discovery_listener_.endpoint_found_cb, Call) - .WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id, + .WillOnce([id = endpoint_id](const std::string& endpoint_id, const ByteArray& endpoint_info, const std::string& service_id) { EXPECT_EQ(endpoint_id, id); EXPECT_EQ(endpoint_info, ByteArray{"ABCDEF"}); - })); + }); EXPECT_CALL(mock_discovery_listener_.endpoint_lost_cb, Call) - .WillOnce(Invoke([id = endpoint_id](const std::string& endpoint_id) { + .WillOnce([id = endpoint_id](const std::string& endpoint_id) { EXPECT_EQ(endpoint_id, id); - })); + }); // Found endpoint on Bluetooth pcp_handler.OnEndpointFound( @@ -1964,7 +1974,7 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) { EXPECT_TRUE(client_->IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl) - .WillOnce(Invoke([&pcp_handler, &endpoint_id]( + .WillOnce([&pcp_handler, &endpoint_id]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { pcp_handler.OnEndpointFound( @@ -1980,7 +1990,7 @@ TEST_F(BasePcpHandlerTest, TestStartStopEndpointLostAlarm) { MockContext{nullptr}, })); return Status{Status::kSuccess}; - })); + }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ @@ -2027,7 +2037,7 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) { EXPECT_TRUE(client_->IsDiscovering()); EXPECT_CALL(pcp_handler, InjectEndpointImpl) - .WillOnce(Invoke([&pcp_handler, &endpoint_id]( + .WillOnce([&pcp_handler, &endpoint_id]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { pcp_handler.OnEndpointFound( @@ -2043,7 +2053,7 @@ TEST_F(BasePcpHandlerTest, TestStartEndpointLostByMediumAlarms) { MockContext{nullptr}, })); return Status{Status::kSuccess}; - })); + }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ @@ -2094,7 +2104,7 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) { EXPECT_CALL(pcp_handler, InjectEndpointImpl) .Times(2) .WillRepeatedly( - Invoke([&pcp_handler, &endpoint_id, &first_call]( + [&pcp_handler, &endpoint_id, &first_call]( ClientProxy* client, const std::string& service_id, const OutOfBandConnectionMetadata& metadata) { ByteArray endpoint_info; @@ -2117,7 +2127,7 @@ TEST_F(BasePcpHandlerTest, TestEndpointFoundStopsAlarm) { MockContext{nullptr}, })); return Status{Status::kSuccess}; - })); + }); pcp_handler.InjectEndpoint( client_.get(), service_id, OutOfBandConnectionMetadata{ @@ -2271,20 +2281,20 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithUnknown) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1()->mutable_connection_request()->clear_connections_device(); frame.mutable_v1()->mutable_connection_request()->clear_presence_device(); ASSERT_FALSE(frame.v1().connection_request().has_connections_device()); ASSERT_FALSE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); EXPECT_TRUE(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2321,20 +2331,20 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithUnknown) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1()->mutable_connection_request()->clear_connections_device(); frame.mutable_v1()->mutable_connection_request()->clear_presence_device(); ASSERT_FALSE(frame.v1().connection_request().has_connections_device()); ASSERT_FALSE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2370,21 +2380,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithConnections) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_connections_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_connections_device()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2420,21 +2430,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForPresenceWithPresence) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_presence_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); EXPECT_TRUE(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2469,21 +2479,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithConnections) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_connections_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_connections_device()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); EXPECT_TRUE(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2518,21 +2528,21 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "ABCD", .local_endpoint_info = ByteArray("local endpoint"), }); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1() ->mutable_connection_request() ->mutable_presence_device() ->set_endpoint_id("ABCD"); ASSERT_TRUE(frame.v1().connection_request().has_presence_device()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2544,7 +2554,8 @@ TEST_F(BasePcpHandlerTest, TestDeviceFilterForConnectionsWithPresence) { } TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) { - env_.Start(); + env_.Start({.use_simulated_clock = true}); + client_ = std::make_unique(CreateAnalyticsRecorder()); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); @@ -2561,6 +2572,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) { MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_analytics_recorder_ptr_, + OnStartedIncomingConnectionListening(_)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) @@ -2568,7 +2581,7 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) { ASSERT_TRUE(client_->IsListeningForIncomingConnections()); ASSERT_TRUE(pcp_handler.CanReceiveIncomingConnection(client_.get())); auto channel_pair = SetupConnection(Medium::BLUETOOTH); - ByteArray serialized_frame = parser::ForConnectionRequestConnections( + std::string serialized_frame = parser::ForConnectionRequestConnections( {}, { .local_endpoint_id = "", .local_endpoint_info = ByteArray("local endpoint"), @@ -2576,53 +2589,19 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) { // At this point the connection request doesn't have an endpoint ID field // set, so we do that here. location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(serialized_frame.AsStringView()); + frame.ParseFromString(serialized_frame); frame.mutable_v1()->mutable_connection_request()->set_endpoint_id(""); ASSERT_TRUE(frame.v1().connection_request().has_endpoint_id()); // do a dummy write to get to the actual write. - channel_pair.first->Write(ByteArray()); - channel_pair.first->Write(ByteArray(frame.SerializeAsString())); - absl::string_view expected_log = R"pb( - event_type: CLIENT_SESSION - client_session { - strategy_session { - connection_attempt { - type: INITIAL - direction: INCOMING - medium: BLUETOOTH - attempt_result: RESULT_ERROR - operation_result { - result_category: CATEGORY_CONNECTIVITY_ERROR - result_code: CONNECTIVITY_CHANNEL_IO_ERROR_ON_BT - } - } - } - } - )pb"; - absl::string_view client_session_log = R"pb( - event_type: CLIENT_SESSION - client_session { duration_millis: 0 } - version: "v1.5.0" - )pb"; - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::STOP_STRATEGY_SESSION)))) - .Times(1); - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::STOP_CLIENT_SESSION)))) - .Times(3); - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::START_CLIENT_SESSION)))) - .Times(3); + channel_pair.first->Write(""); + channel_pair.first->Write(frame.SerializeAsString()); + EXPECT_CALL(*mock_analytics_recorder_ptr_, LogSession()).Times(3); + EXPECT_CALL(*mock_analytics_recorder_ptr_, LogStartSession()).Times(3); EXPECT_CALL( - mock_event_logger_, - Log(Matcher(EqualsProto(client_session_log)))) - .Times(2); - EXPECT_CALL(mock_event_logger_, Log(Matcher( - Partially(EqualsProto(expected_log))))); - + *mock_analytics_recorder_ptr_, + OnIncomingConnectionAttempt( + location::nearby::proto::connections::INITIAL, Medium::BLUETOOTH, + location::nearby::proto::connections::RESULT_ERROR, _, _, _)); EXPECT_EQ(pcp_handler .OnIncomingConnection( client_.get(), ByteArray("remote endpoint"), @@ -2636,7 +2615,7 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionFailsWithEmptyEndpointId) { TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) { env_.Start({.use_simulated_clock = true}); // Recreate ClientProxy so that AnalyticRecorder uses simulated clock. - client_ = std::make_unique(&mock_event_logger_); + client_ = std::make_unique(CreateAnalyticsRecorder()); Mediums m; EndpointChannelManager ecm; EndpointManager em(&ecm); @@ -2653,6 +2632,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) { MockPcpHandler::StartOperationResult{.status = {Status::kSuccess}})); EXPECT_CALL(pcp_handler, CanReceiveIncomingConnection) .WillRepeatedly(Return(true)); + EXPECT_CALL(*mock_analytics_recorder_ptr_, + OnStartedIncomingConnectionListening(_)); EXPECT_TRUE(pcp_handler .StartListeningForIncomingConnections(client_.get(), "service", options, {}) @@ -2664,59 +2645,8 @@ TEST_F(BasePcpHandlerTest, IncomingConnectionWithNoDataFailsWithoutLogging) { std::move(input_a), std::move(output_a)); EXPECT_CALL(*input_channel, Read()) .WillRepeatedly(Return(ExceptionOr(Exception::kNoData))); - absl::string_view expected_log = R"pb( - event_type: CLIENT_SESSION - client_session { - strategy_session { - connection_attempt { - type: INITIAL - direction: INCOMING - attempt_result: RESULT_ERROR - } - } - } - )pb"; - absl::string_view client_session_log = R"pb( - event_type: CLIENT_SESSION - client_session { duration_millis: 0 } - version: "v1.5.0" - )pb"; - absl::string_view client_session_log2 = R"pb( - event_type: CLIENT_SESSION - client_session { - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: UNKNOWN_STRATEGY - role: ADVERTISER - } - } - version: "v1.5.0" - )pb"; - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::STOP_STRATEGY_SESSION)))) - .Times(1); - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::STOP_CLIENT_SESSION)))) - .Times(3); - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::START_CLIENT_SESSION)))) - .Times(3); - EXPECT_CALL( - mock_event_logger_, - Log(Matcher(EqualsProto(client_session_log)))) - .Times(2); - EXPECT_CALL( - mock_event_logger_, - Log(Matcher(EqualsProto(client_session_log2)))); - EXPECT_CALL( - mock_event_logger_, - Log(Matcher(Partially(EqualsProto(expected_log))))) - .Times(0); - + EXPECT_CALL(*mock_analytics_recorder_ptr_, LogSession()).Times(3); + EXPECT_CALL(*mock_analytics_recorder_ptr_, LogStartSession()).Times(3); EXPECT_EQ( pcp_handler .OnIncomingConnection(client_.get(), ByteArray("remote endpoint"), @@ -3020,5 +2950,4 @@ TEST_F(BasePcpHandlerTest, TestForceUpdateEndpointIdAdvertisingOption) { } } // namespace -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/bwu_handler.h b/connections/implementation/bwu_handler.h index cd0fc073..b1704983 100644 --- a/connections/implementation/bwu_handler.h +++ b/connections/implementation/bwu_handler.h @@ -21,7 +21,6 @@ #include "absl/functional/any_invocable.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" namespace nearby { @@ -53,7 +52,7 @@ class BwuHandler { // that hasn't already been done), and returns a serialized UpgradePathInfo // that can be sent to the Responder. // @BwuHandlerThread - virtual ByteArray InitializeUpgradedMediumForEndpoint( + virtual std::string InitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& service_id, const std::string& endpoint_id) = 0; diff --git a/connections/implementation/bwu_manager.cc b/connections/implementation/bwu_manager.cc index fd41cfb2..0cbafc7a 100644 --- a/connections/implementation/bwu_manager.cc +++ b/connections/implementation/bwu_manager.cc @@ -25,9 +25,8 @@ #include "absl/functional/bind_front.h" #include "absl/strings/str_cat.h" #include "absl/time/time.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/analytics/connection_attempt_metadata_params.h" -#include "connections/implementation/awdl_bwu_handler.h" -#include "connections/implementation/bluetooth_bwu_handler.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" @@ -38,16 +37,7 @@ #include "connections/implementation/offline_frames.h" #include "connections/implementation/service_id_constants.h" #include "internal/flags/nearby_flags.h" -#ifdef NO_WEBRTC -#include "connections/implementation/webrtc_bwu_handler_stub.h" -#else -#include "connections/implementation/webrtc_bwu_handler.h" -#endif -#include "connections/implementation/wifi_direct_bwu_handler.h" -#include "connections/implementation/wifi_hotspot_bwu_handler.h" -#include "connections/implementation/wifi_lan_bwu_handler.h" #include "connections/medium_selector.h" -#include "internal/platform/byte_array.h" #include "internal/platform/cancelable_alarm.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/expected.h" @@ -72,6 +62,8 @@ using ::location::nearby::proto::connections::ConnectionAttemptResult; using ::location::nearby::proto::connections::ConnectionAttemptType; using ::location::nearby::proto::connections::DisconnectionReason; using ::location::nearby::proto::connections::OperationResultCode; +using ::nearby::analytics::AnalyticsRecorder; + } // namespace BwuManager::BwuManager( @@ -135,43 +127,37 @@ void BwuManager::InitBwuHandlers() { if (config_.allow_upgrade_to.awdl) { handlers_.emplace( Medium::AWDL, - std::make_unique( - *mediums_, + mediums_->GetAwdl().CreateBwuHandler( absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.wifi_hotspot) { handlers_.emplace( Medium::WIFI_HOTSPOT, - std::make_unique( - *mediums_, + mediums_->GetWifiHotspot().CreateBwuHandler( absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.wifi_direct) { handlers_.emplace( Medium::WIFI_DIRECT, - std::make_unique( - *mediums_, + mediums_->GetWifiDirect().CreateBwuHandler( absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.wifi_lan) { handlers_.emplace( Medium::WIFI_LAN, - std::make_unique( - *mediums_, + mediums_->GetWifiLan().CreateBwuHandler( absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.web_rtc) { handlers_.emplace( Medium::WEB_RTC, - std::make_unique( - *mediums_, + mediums_->GetWebRtc().CreateBwuHandler( absl::bind_front(&BwuManager::OnIncomingConnection, this))); } if (config_.allow_upgrade_to.bluetooth) { handlers_.emplace( Medium::BLUETOOTH, - std::make_unique( - *mediums_, + mediums_->GetBluetoothClassic().CreateBwuHandler( absl::bind_front(&BwuManager::OnIncomingConnection, this))); } } @@ -197,8 +183,9 @@ void BwuManager::Shutdown() { medium_ = Medium::UNKNOWN_MEDIUM; endpoint_id_to_bwu_medium_.clear(); for (auto& medium_handler_pair : handlers_) { - assert(medium_handler_pair.second); - medium_handler_pair.second->RevertInitiatorState(); + if (medium_handler_pair.second != nullptr) { + medium_handler_pair.second->RevertInitiatorState(); + } } handlers_.clear(); @@ -341,12 +328,12 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client, } std::string service_id = channel->GetServiceId(); - ByteArray bytes = handler->InitializeUpgradedMediumForEndpoint( + std::string bytes = handler->InitializeUpgradedMediumForEndpoint( client, service_id, endpoint_id); // Because we grab the endpointChannel first thing, it is possible the // endpointChannel is stale by the time we attempt to write over it. - if (bytes.Empty()) { + if (bytes.empty()) { LOG(ERROR) << "BwuManager couldn't complete the upgrade for endpoint " << endpoint_id << " to medium " << location::nearby::proto::connections::Medium_Name( @@ -401,8 +388,7 @@ void BwuManager::InitiateBwuForEndpoint(ClientProxy* client, void BwuManager::OnIncomingFrame(OfflineFrame& frame, const std::string& endpoint_id, - ClientProxy* client, Medium medium, - PacketMetaData& packet_meta_data) { + ClientProxy* client, Medium medium) { V1Frame::FrameType frame_type = parser::GetFrameType(frame); if (frame_type != V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION) return; @@ -549,7 +535,7 @@ BwuHandler* BwuManager::GetHandlerForMedium(Medium medium) const { } void BwuManager::OnBwuNegotiationFrame( - ClientProxy* client, const BandwidthUpgradeNegotiationFrame frame, + ClientProxy* client, const BandwidthUpgradeNegotiationFrame& frame, const std::string& endpoint_id) { LOG(INFO) << "OnBwuNegotiationFrame: processing incoming " << BandwidthUpgradeNegotiationFrame::EventType_Name( @@ -586,9 +572,19 @@ void BwuManager::OnBwuNegotiationFrame( OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE); break; case BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL: + if (!in_progress_upgrades_.contains(endpoint_id)) { + LOG(ERROR) << "Received LAST_WRITE_TO_PRIOR_CHANNEL for endpoint " + << endpoint_id << " but no upgrade is in progress."; + return; + } ProcessLastWriteToPriorChannelEvent(client, endpoint_id); break; case BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL: + if (!in_progress_upgrades_.contains(endpoint_id)) { + LOG(ERROR) << "Received SAFE_TO_CLOSE_PRIOR_CHANNEL for endpoint " + << endpoint_id << " but no upgrade is in progress."; + return; + } ProcessSafeToClosePriorChannelEvent(client, endpoint_id); break; default: @@ -680,7 +676,7 @@ void BwuManager::OnIncomingConnection( connections_attempt_metadata_params; if (channel != nullptr) { connections_attempt_metadata_params = - client->GetAnalyticsRecorder().BuildConnectionAttemptMetadataParams( + AnalyticsRecorder::BuildConnectionAttemptMetadataParams( channel->GetTechnology(), channel->GetBand(), channel->GetFrequency(), channel->GetTryCount()); connections_attempt_metadata_params->operation_result_code = @@ -891,7 +887,7 @@ void BwuManager::ProcessBwuPathAvailableEvent( if (channel != nullptr) { std::unique_ptr connections_attempt_metadata_params = - client->GetAnalyticsRecorder().BuildConnectionAttemptMetadataParams( + AnalyticsRecorder::BuildConnectionAttemptMetadataParams( channel->GetTechnology(), channel->GetBand(), channel->GetFrequency(), channel->GetTryCount()); connections_attempt_metadata_params->operation_result_code = @@ -1138,7 +1134,7 @@ bool BwuManager::ReadClientIntroductionFrame( auto data = channel->Read(); timeout_alarm.Cancel(); if (!data.ok()) return false; - auto transfer(parser::FromBytes(data.result())); + auto transfer(parser::FromBytes(data.result().AsStringView())); if (!transfer.ok()) { LOG(ERROR) << "In ReadClientIntroductionFrame, attempted to read a " "ClientIntroductionFrame from EndpointChannel " @@ -1189,7 +1185,7 @@ bool BwuManager::ReadClientIntroductionAckFrame(EndpointChannel* channel) { auto data = channel->Read(); timeout_alarm.Cancel(); if (!data.ok()) return false; - auto transfer(parser::FromBytes(data.result())); + auto transfer(parser::FromBytes(data.result().AsStringView())); if (!transfer.ok()) return false; OfflineFrame frame = transfer.result(); if (!frame.has_v1() || !frame.v1().has_bandwidth_upgrade_negotiation()) @@ -1219,9 +1215,8 @@ void BwuManager::ProcessLastWriteToPriorChannelEvent( // loss). But now that we've received this definitive final write over that // prior EndpointChannel, we can let the remote device that they can safely // close their end of this now-dormant EndpointChannel. - EndpointChannel* previous_endpoint_channel = - previous_endpoint_channels_[endpoint_id].get(); - if (!previous_endpoint_channel) { + auto it = previous_endpoint_channels_.find(endpoint_id); + if (it == previous_endpoint_channels_.end()) { LOG(ERROR) << "BwuManager received a BWU_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL " "OfflineFrame for unknown endpoint " @@ -1229,6 +1224,12 @@ void BwuManager::ProcessLastWriteToPriorChannelEvent( successfully_upgraded_endpoints_.emplace(endpoint_id); return; } + EndpointChannel* previous_endpoint_channel = it->second.get(); + if (!previous_endpoint_channel) { + LOG(ERROR) << "previous_endpoint_channel is null for endpoint " + << endpoint_id; + return; + } LOG(INFO) << "ProcessLastWriteToPriorChannelEvent: service_id=" << previous_endpoint_channel->GetServiceId() @@ -1281,6 +1282,13 @@ void BwuManager::ProcessSafeToClosePriorChannelEvent( // or not (as is the case with Android's Bluetooth sockets, where closing // instantly throws an IOException on the remote device). auto item = previous_endpoint_channels_.extract(endpoint_id); + if (item.empty()) { + LOG(ERROR) + << "BwuManager received a BWU_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL " + "OfflineFrame for unknown endpoint " + << endpoint_id << ", can't complete the upgrade protocol."; + return; + } auto& previous_endpoint_channel = item.mapped(); if (previous_endpoint_channel == nullptr) { LOG(ERROR) diff --git a/connections/implementation/bwu_manager.h b/connections/implementation/bwu_manager.h index 2c5c766c..d2f53913 100644 --- a/connections/implementation/bwu_manager.h +++ b/connections/implementation/bwu_manager.h @@ -92,8 +92,7 @@ class BwuManager : public EndpointManager::FrameProcessor { // @EndpointManagerReaderThread void OnIncomingFrame(location::nearby::connections::OfflineFrame& frame, const std::string& endpoint_id, ClientProxy* client, - Medium medium, - PacketMetaData& packet_meta_data) override; + Medium medium) override; // Cleans up in-progress upgrades after endpoint disconnection. // @EndpointManagerReaderThread @@ -144,7 +143,7 @@ class BwuManager : public EndpointManager::FrameProcessor { // upgrade. void OnBwuNegotiationFrame( ClientProxy* client, - const location::nearby::connections::BandwidthUpgradeNegotiationFrame + const location::nearby::connections::BandwidthUpgradeNegotiationFrame& frame, const string& endpoint_id); diff --git a/connections/implementation/bwu_manager_test.cc b/connections/implementation/bwu_manager_test.cc index 40cd3e50..e817ad7c 100644 --- a/connections/implementation/bwu_manager_test.cc +++ b/connections/implementation/bwu_manager_test.cc @@ -22,6 +22,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" #include "connections/connection_options.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" @@ -41,19 +42,17 @@ #include "internal/platform/exception.h" #include "internal/platform/feature_flags.h" #include "internal/platform/service_address.h" -#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" -namespace nearby { -namespace connections { +namespace nearby::connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::connections::MediumRole; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::OsInfo; using ::location::nearby::connections::V1Frame; using ::location::nearby::proto::connections::DisconnectionReason; +using ::nearby::analytics::SafeDisconnectionResult; constexpr absl::string_view kServiceIdA = "ServiceA"; constexpr absl::string_view kServiceIdB = "ServiceB"; @@ -148,7 +147,7 @@ class BwuManagerTest : public ::testing::Test { void UnRegisterChannelForEndpoint(absl::string_view endpoint_id) { ecm_.UnregisterChannelForEndpoint( std::string(endpoint_id), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); } // Upgrade from |initial_medium| to |upgrade_medium|, close down the BLUETOOTH @@ -188,12 +187,12 @@ class BwuManagerTest : public ::testing::Test { parser::FromBytes(parser::ForBwuLastWrite()); bwu_manager_->OnIncomingFrame(last_write_frame.result(), std::string(endpoint_id), &client_, - initial_medium, packet_meta_data_); + initial_medium); ExceptionOr safe_to_close_frame = parser::FromBytes(parser::ForBwuSafeToClose()); bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), std::string(endpoint_id), &client_, - initial_medium, packet_meta_data_); + initial_medium); return upgraded_channel; } @@ -209,7 +208,6 @@ class BwuManagerTest : public ::testing::Test { FakeBwuHandler* fake_wifi_direct_bwu_handler_ = nullptr; FakeBwuHandler* fake_wifi_hotspot_bwu_handler_ = nullptr; std::unique_ptr bwu_manager_; - PacketMetaData packet_meta_data_; }; TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { @@ -233,9 +231,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId1), Medium::WIFI_LAN); EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - ecm.UnregisterChannelForEndpoint( - std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); auto channel2 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); @@ -244,9 +242,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId2), Medium::WIFI_HOTSPOT); EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId2))); - ecm.UnregisterChannelForEndpoint( - std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId2), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); auto channel3 = std::make_unique( Medium::BLUETOOTH, std::string(kServiceIdA)); @@ -255,9 +253,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId3), Medium::WIFI_DIRECT); EXPECT_TRUE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId3))); - ecm.UnregisterChannelForEndpoint( - std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId3), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); auto channel4 = std::make_unique( Medium::WEB_RTC, std::string(kServiceIdA)); @@ -266,9 +264,9 @@ TEST(BwuManagerBaseTest, AllowToUpgradeMedium) { bwu_manager->InitiateBwuForEndpoint(&client, std::string(kEndpointId4), Medium::BLUETOOTH); EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId4))); - ecm.UnregisterChannelForEndpoint( - std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId4), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); bwu_manager->Shutdown(); } @@ -308,9 +306,9 @@ TEST(BwuManagerBaseTest, InitiateBwu_NeedToSwitchRole_Success) { Medium::WIFI_HOTSPOT); EXPECT_FALSE(bwu_manager->IsUpgradeOngoing(std::string(kEndpointId1))); - ecm.UnregisterChannelForEndpoint( - std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + ecm.UnregisterChannelForEndpoint(std::string(kEndpointId1), + DisconnectionReason::LOCAL_DISCONNECTION, + SafeDisconnectionResult::kSafeDisconnection); bwu_manager->Shutdown(); NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: @@ -370,12 +368,12 @@ TEST_P(BwuManagerTestParam, InitiateBwu_Success) { parser::FromBytes(parser::ForBwuLastWrite()); bwu_manager_->OnIncomingFrame(last_write_frame.result(), std::string(kEndpointId1), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); ExceptionOr safe_to_close_frame = parser::FromBytes(parser::ForBwuSafeToClose()); bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), std::string(kEndpointId1), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); // Confirm that upgrade channel is resumed after initial channel is shut down. // Note: If we didn't grab the shared initial channel pointer above, this @@ -501,7 +499,7 @@ TEST_F(BwuManagerTest, CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id, std::string(kEndpointId1), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -515,7 +513,7 @@ TEST_F(BwuManagerTest, CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id, std::string(kEndpointId2), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -549,7 +547,7 @@ TEST_F(BwuManagerTest, CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id, std::string(kEndpointId1), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -569,7 +567,7 @@ TEST_F(BwuManagerTest, CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id, std::string(kEndpointId2), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -606,7 +604,7 @@ TEST_F(BwuManagerTest, EXPECT_EQ(2u, ecm_.GetConnectedEndpointsCount()); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); EXPECT_EQ(1u, ecm_.GetConnectedEndpointsCount()); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_A, std::string(kEndpointId1), latch, @@ -626,7 +624,7 @@ TEST_F(BwuManagerTest, CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); EXPECT_EQ(0u, ecm_.GetConnectedEndpointsCount()); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_B, std::string(kEndpointId2), latch, @@ -660,7 +658,7 @@ TEST_F(BwuManagerTest, EXPECT_EQ(2u, ecm_.GetConnectedEndpointsCount()); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); EXPECT_EQ(1u, ecm_.GetConnectedEndpointsCount()); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_A, std::string(kEndpointId1), latch, @@ -680,7 +678,7 @@ TEST_F(BwuManagerTest, CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); EXPECT_EQ(0u, ecm_.GetConnectedEndpointsCount()); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_B, std::string(kEndpointId2), latch, @@ -736,7 +734,7 @@ TEST_F( CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId1), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_A, std::string(kEndpointId1), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -761,7 +759,7 @@ TEST_F( CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId2), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_A, std::string(kEndpointId2), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -782,7 +780,7 @@ TEST_F( CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId3), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_B, std::string(kEndpointId3), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -803,7 +801,7 @@ TEST_F( CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId4), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_B, std::string(kEndpointId4), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -826,7 +824,7 @@ TEST_F( CountDownLatch latch(1); ecm_.UnregisterChannelForEndpoint( std::string(kEndpointId5), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION); + SafeDisconnectionResult::kUnsafeDisconnection); bwu_manager_->OnEndpointDisconnect( &client_, upgrade_service_id_B, std::string(kEndpointId5), latch, DisconnectionReason::LOCAL_DISCONNECTION); @@ -871,7 +869,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagEnabled) { parser::FromBytes(parser::ForBwuFailure(info)); bwu_manager_->OnIncomingFrame(upgrade_failure.result(), std::string(kEndpointId3), &client_, - Medium::WEB_RTC, packet_meta_data_); + Medium::WEB_RTC); // With the flag enabled, we can safely revert WebRTC just for service B // because service B has no active WebRTC endpoints. @@ -908,7 +906,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnUpgradeFailure_FlagDisabled) { parser::FromBytes(parser::ForBwuFailure(info)); bwu_manager_->OnIncomingFrame(upgrade_failure.result(), std::string(kEndpointId3), &client_, - Medium::WEB_RTC, packet_meta_data_); + Medium::WEB_RTC); // With the flag disabled, we don't revert if there are still connected // endpoints for _any_ service. We don't have service-level bookkeeping; we @@ -924,12 +922,12 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { OfflineFrame frame; CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); - ByteArray bytes = parser::ForBwuWifiDirectPathAvailable( + std::string bytes = parser::ForBwuWifiDirectPathAvailable( /*ssid=*/"", /*password=*/"", /*port=*/2143, /*frequency=*/2412, /*supports_disabling_encryption=*/false, /*gateway=*/"123.234.23.1", /*service_name=*/"NC-WifiDirectTest", /*pin=*/"b592f7d3"); - frame.ParseFromString(std::string(bytes)); + frame.ParseFromString(bytes); ::nearby::connections::V1Frame* v1_frame = frame.mutable_v1(); ::nearby::connections::BandwidthUpgradeNegotiationFrame* sub_frame = @@ -938,7 +936,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_WifiDirect) { upgrade_path_info = sub_frame->mutable_upgrade_path_info(); upgrade_path_info->set_supports_client_introduction_ack(false); bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); CountDownLatch latch(1); bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, std::string(kEndpointId1), latch, @@ -973,7 +971,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Hotspot) { upgrade_path_info->set_supports_client_introduction_ack(false); upgrade_path_info->set_supports_disabling_encryption(true); bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); CountDownLatch latch(1); bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, std::string(kEndpointId1), latch, @@ -1001,7 +999,7 @@ TEST_F(BwuManagerTest, InitiateBwu_Revert_OnDisconnect_Wlan) { upgrade_path_info->set_supports_client_introduction_ack(false); bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId1), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); CountDownLatch latch(1); bwu_manager_->OnEndpointDisconnect(&client_, (std::string)kServiceIdA, std::string(kEndpointId1), latch, @@ -1040,7 +1038,7 @@ TEST_F(BwuManagerTest, BlockBwuFrameBeforeAccept) { upgrade_path_info2->set_supports_client_introduction_ack(false); upgrade_path_info2->set_supports_disabling_encryption(true); bwu_manager_->OnIncomingFrame(frame2, std::string(kEndpointId2), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); CountDownLatch latch2(1); // The BWU frame should be drop, so the inProgressUpgrades should be empty. ASSERT_EQ(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2)), false); @@ -1084,16 +1082,100 @@ TEST_F(BwuManagerTest, BlockBwuFrameFromAdvertiser) { EXPECT_TRUE(client_.IsConnectedToEndpoint(std::string(kEndpointId2))); bwu_manager_->OnIncomingFrame(frame, std::string(kEndpointId2), &client_, - Medium::BLUETOOTH, packet_meta_data_); + Medium::BLUETOOTH); CountDownLatch latch2(1); // The BWU frame should be drop, so the IsUpgradeOngoing should be empty. ASSERT_EQ(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId2)), false); UnRegisterChannelForEndpoint(kEndpointId2); } +TEST_F(BwuManagerTest, ReceiveUnexpectedSafeToClose_NoCrash) { + ExceptionOr safe_to_close_frame = + parser::FromBytes(parser::ForBwuSafeToClose()); + bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); +} + +TEST_F(BwuManagerTest, ReceiveUnexpectedLastWrite_NoCrashOrWedge) { + ExceptionOr last_write_frame = + parser::FromBytes(parser::ForBwuLastWrite()); + bwu_manager_->OnIncomingFrame(last_write_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); +} + +TEST_F(BwuManagerTest, ReceiveEarlyLastWrite_Success) { + CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + std::shared_ptr shared_initial_channel = + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)); + + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WEB_RTC); + ASSERT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId1))); + + ExceptionOr last_write_frame = + parser::FromBytes(parser::ForBwuLastWrite()); + bwu_manager_->OnIncomingFrame(last_write_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + + FakeEndpointChannel* upgraded_channel = + fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection( + /*initialize_call_index=*/0u, bwu_manager_.get()); + + ExceptionOr safe_to_close_frame = + parser::FromBytes(parser::ForBwuSafeToClose()); + bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + + auto old_channel = + dynamic_cast(shared_initial_channel.get()); + EXPECT_FALSE(upgraded_channel->IsPaused()); + EXPECT_TRUE(old_channel->is_closed()); + EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED, + old_channel->disconnection_reason()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + +TEST_F(BwuManagerTest, ReceiveUnexpectedLastWriteBeforeUpgrade_NoWedge) { + ExceptionOr last_write_frame = + parser::FromBytes(parser::ForBwuLastWrite()); + bwu_manager_->OnIncomingFrame(last_write_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + + CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH); + std::shared_ptr shared_initial_channel = + ecm_.GetChannelForEndpoint(std::string(kEndpointId1)); + + bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1), + Medium::WEB_RTC); + + FakeEndpointChannel* upgraded_channel = + fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection( + /*initialize_call_index=*/0u, bwu_manager_.get()); + + bwu_manager_->OnIncomingFrame(last_write_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + + ExceptionOr safe_to_close_frame = + parser::FromBytes(parser::ForBwuSafeToClose()); + bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(), + std::string(kEndpointId1), &client_, + Medium::BLUETOOTH); + + auto old_channel = + dynamic_cast(shared_initial_channel.get()); + EXPECT_FALSE(upgraded_channel->IsPaused()); + EXPECT_TRUE(old_channel->is_closed()); + UnRegisterChannelForEndpoint(kEndpointId1); +} + INSTANTIATE_TEST_SUITE_P(BwuManagerTestParam, BwuManagerTestParam, testing::Bool()); } // namespace -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/client_proxy.cc b/connections/implementation/client_proxy.cc index d53e1a18..f9890267 100644 --- a/connections/implementation/client_proxy.cc +++ b/connections/implementation/client_proxy.cc @@ -38,12 +38,15 @@ #include "connections/discovery_options.h" #include "connections/implementation/analytics/advertising_metadata_params.h" #include "connections/implementation/analytics/analytics_recorder.h" +#include "connections/implementation/analytics/connection_attempt_metadata_params.h" #include "connections/implementation/analytics/discovery_metadata_params.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/mediums/advertisements/dct_advertisement.h" #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/payload.h" +#include "connections/payload_type.h" #include "connections/status.h" #include "connections/strategy.h" #include "connections/v3/bandwidth_info.h" @@ -52,7 +55,6 @@ #include "connections/v3/connections_device.h" #include "connections/v3/connections_device_provider.h" #include "connections/v3/listeners.h" -#include "internal/analytics/event_logger.h" #include "internal/base/file_path.h" #include "internal/base/files.h" #include "internal/flags/nearby_flags.h" @@ -60,7 +62,9 @@ #include "internal/platform/byte_array.h" #include "internal/platform/cancelable_alarm.h" #include "internal/platform/cancellation_flag.h" -#include "internal/platform/device_info_impl.h" +#ifndef NEARBY_CHROMIUM +#include "internal/platform/implementation/device_info.h" +#endif #include "internal/platform/error_code_params.h" #include "internal/platform/error_code_recorder.h" #include "internal/platform/feature_flags.h" @@ -77,9 +81,9 @@ namespace nearby::connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::MediumRole; using ::location::nearby::connections::OsInfo; +using ::nearby::analytics::AnalyticsRecorder; constexpr char kEndpointIdChars[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', @@ -95,11 +99,154 @@ constexpr absl::string_view kAdvertisingTimestamp = "nc.advertising.timestamp"; constexpr absl::Duration kAdvertisingKeepAliveDuration = absl::Seconds(30); +class NoOpAnalyticsRecorder : public AnalyticsRecorder { + public: + NoOpAnalyticsRecorder() = default; + ~NoOpAnalyticsRecorder() override = default; + + // Advertising phase + void OnStartAdvertising( + connections::Strategy strategy, + const std::vector& mediums, + AdvertisingMetadataParams* advertising_metadata_params) override {} + void OnStopAdvertising() override {} + + int GetNextAdvertisingUpdateIndex() override { return 0; } + + // Connection listening + void OnStartedIncomingConnectionListening( + connections::Strategy strategy) override {} + void OnStoppedIncomingConnectionListening() override {} + + // Discovery phase + void OnStartDiscovery( + connections::Strategy strategy, + const std::vector& mediums, + DiscoveryMetadataParams* discovery_metadata_params) override {} + void OnStopDiscovery() override {} + + int GetNextDiscoveryUpdateIndex() override { return 0; } + void OnEndpointFound( + location::nearby::proto::connections::Medium medium) override {} + + // Connection request + void OnRequestConnection(const connections::Strategy& strategy, + const std::string& endpoint_id) override {} + + void OnConnectionRequestReceived( + const std::string& remote_endpoint_id) override {} + void OnConnectionRequestSent( + const std::string& remote_endpoint_id) override {} + void OnRemoteEndpointAccepted( + const std::string& remote_endpoint_id) override {} + void OnLocalEndpointAccepted( + const std::string& remote_endpoint_id) override {} + void OnRemoteEndpointRejected( + const std::string& remote_endpoint_id) override {} + void OnLocalEndpointRejected( + const std::string& remote_endpoint_id) override {} + + // Connection attempt + void OnIncomingConnectionAttempt( + location::nearby::proto::connections::ConnectionAttemptType type, + location::nearby::proto::connections::Medium medium, + location::nearby::proto::connections::ConnectionAttemptResult result, + absl::Duration duration, const std::string& connection_token, + ConnectionAttemptMetadataParams* connection_attempt_metadata_params) + override {} + void OnOutgoingConnectionAttempt( + const std::string& remote_endpoint_id, + location::nearby::proto::connections::ConnectionAttemptType type, + location::nearby::proto::connections::Medium medium, + location::nearby::proto::connections::ConnectionAttemptResult result, + absl::Duration duration, const std::string& connection_token, + ConnectionAttemptMetadataParams* connection_attempt_metadata_params) + override {} + + // Connection established + void OnConnectionEstablished( + const std::string& endpoint_id, + location::nearby::proto::connections::Medium medium, + const std::string& connection_token) override {} + void OnConnectionClosed( + const std::string& endpoint_id, + location::nearby::proto::connections::Medium medium, + location::nearby::proto::connections::DisconnectionReason reason, + nearby::analytics::SafeDisconnectionResult result) override {} + + // Payload + void OnIncomingPayloadStarted(const std::string& endpoint_id, + std::int64_t payload_id, + connections::PayloadType type, + std::int64_t total_size_bytes) override {} + void OnPayloadChunkReceived(const std::string& endpoint_id, + std::int64_t payload_id, + std::int64_t chunk_size_bytes) override {} + void OnIncomingPayloadDone( + const std::string& endpoint_id, std::int64_t payload_id, + location::nearby::proto::connections::PayloadStatus status, + location::nearby::proto::connections::OperationResultCode + operation_result_code) override {} + void OnOutgoingPayloadStarted( + const std::vector& endpoint_ids, std::int64_t payload_id, + connections::PayloadType type, std::int64_t total_size_bytes) override {} + void OnPayloadChunkSent(const std::string& endpoint_id, + std::int64_t payload_id, + std::int64_t chunk_size_bytes) override {} + void OnOutgoingPayloadDone( + const std::string& endpoint_id, std::int64_t payload_id, + location::nearby::proto::connections::PayloadStatus status, + location::nearby::proto::connections::OperationResultCode + operation_result_code) override {} + + // BandwidthUpgrade + void OnBandwidthUpgradeStarted( + const std::string& endpoint_id, + location::nearby::proto::connections::Medium from_medium, + location::nearby::proto::connections::Medium to_medium, + location::nearby::proto::connections::ConnectionAttemptDirection + direction, + const std::string& connection_token) override {} + void UpdateBwUpgradeNetworkInfo(const std::string& endpoint_id, + int num_interfaces, + int num_ipv6_only_interfaces) override {} + void OnBandwidthUpgradeError( + const std::string& endpoint_id, + location::nearby::proto::connections::BandwidthUpgradeResult result, + location::nearby::proto::connections::BandwidthUpgradeErrorStage + error_stage, + location::nearby::proto::connections::OperationResultCode + operation_result_code) override {} + void OnBandwidthUpgradeSuccess(const std::string& endpoint_id) override {} + + // Error Code + void OnErrorCode(const ErrorCodeParams& params) override {} + + void LogStartSession() override {} + void LogSession() override {} + + bool IsSessionLogged() override { return false; } + + location::nearby::proto::connections::OperationResultCategory + GetOperationResultCategory( + location::nearby::proto::connections::OperationResultCode result_code) + override { + return location::nearby::proto::connections::OperationResultCategory:: + CATEGORY_UNKNOWN; + } + + void Sync() override {} +}; + } // namespace -ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger) - : client_id_(Prng().NextInt64()) { - VLOG(1) << "ClientProxy ctor event_logger=" << event_logger; +ClientProxy::ClientProxy(std::unique_ptr analytics_recorder) + : client_id_(Prng().NextInt64()), + analytics_recorder_(std::move(analytics_recorder)) { + if (analytics_recorder_ == nullptr) { + analytics_recorder_ = std::make_unique(); + } + if (NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature:: kEnableNearbyConnectionsPreferences)) { @@ -108,8 +255,6 @@ ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger) is_dct_enabled_ = NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature::kEnableDct); - analytics_recorder_ = - std::make_unique(event_logger); error_code_recorder_ = std::make_unique( [this](const ErrorCodeParams& params) { analytics_recorder_->OnErrorCode(params); @@ -119,14 +264,11 @@ ClientProxy::ClientProxy(::nearby::analytics::EventLogger* event_logger) supports_safe_to_disconnect_ = NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature:: kEnableSafeToDisconnect); - support_auto_reconnect_ = NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature::kEnableAutoReconnect); - local_safe_to_disconnect_version_ = NearbyFlags::GetInstance().GetInt64Flag( - config_package_nearby::nearby_connections_feature:: - kSafeToDisconnectVersion); LOG(INFO) << "[safe-to-disconnect]: Local enabled: " - << supports_safe_to_disconnect_ - << "; Version: " << local_safe_to_disconnect_version_; + << supports_safe_to_disconnect_ << "; Version: " + << NearbyFlags::GetInstance().GetInt64Flag( + config_package_nearby::nearby_connections_feature:: + kSafeToDisconnectVersion); // Generate a 7 bits dedup value. absl::BitGen bitgen; dct_dedup_ = absl::Uniform(bitgen, 0, 1 << 7); @@ -189,6 +331,7 @@ const NearbyDevice* ClientProxy::GetLocalDevice() { } std::string ClientProxy::GetConnectionToken(const std::string& endpoint_id) { + MutexLock lock(&mutex_); ConnectionPair* item = LookupConnection(endpoint_id); if (item != nullptr) { return item->first.connection_token; @@ -219,6 +362,7 @@ std::string ClientProxy::GetSavePath( std::optional ClientProxy::GetBluetoothMacAddress( const std::string& endpoint_id) { + MutexLock lock(&mutex_); auto item = bluetooth_mac_addresses_.find(endpoint_id); if (item != bluetooth_mac_addresses_.end()) return item->second; return std::nullopt; @@ -226,6 +370,7 @@ std::optional ClientProxy::GetBluetoothMacAddress( void ClientProxy::SetBluetoothMacAddress(const std::string& endpoint_id, MacAddress bluetooth_mac_address) { + MutexLock lock(&mutex_); bluetooth_mac_addresses_[endpoint_id] = bluetooth_mac_address; } @@ -263,7 +408,7 @@ void ClientProxy::StartedAdvertising( const std::string& service_id, Strategy strategy, const ConnectionListener& listener, absl::Span mediums, - const std::vector& + const std::vector& operation_result_with_mediums, const AdvertisingOptions& advertising_options) { MutexLock lock(&mutex_); @@ -284,9 +429,9 @@ void ClientProxy::StartedAdvertising( mediums.begin(), mediums.end()); std::unique_ptr advertising_metadata_params; advertising_metadata_params = - GetAnalyticsRecorder().BuildAdvertisingMetadataParams(); + AnalyticsRecorder::BuildAdvertisingMetadataParams(); advertising_metadata_params->operation_result_with_mediums = - std::move(operation_result_with_mediums); + operation_result_with_mediums; analytics_recorder_->OnStartAdvertising(strategy, medium_vector, advertising_metadata_params.get()); } @@ -402,7 +547,7 @@ void ClientProxy::StartedDiscovery( const std::string& service_id, Strategy strategy, DiscoveryListener listener, absl::Span mediums, - const std::vector& + const std::vector& operation_result_with_mediums, const DiscoveryOptions& discovery_options) { MutexLock lock(&mutex_); @@ -412,10 +557,9 @@ void ClientProxy::StartedDiscovery( const std::vector medium_vector( mediums.begin(), mediums.end()); std::unique_ptr discovery_metadata_params; - discovery_metadata_params = - GetAnalyticsRecorder().BuildDiscoveryMetadataParams(); + discovery_metadata_params = AnalyticsRecorder::BuildDiscoveryMetadataParams(); discovery_metadata_params->operation_result_with_mediums = - std::move(operation_result_with_mediums); + operation_result_with_mediums; analytics_recorder_->OnStartDiscovery(strategy, medium_vector, discovery_metadata_params.get()); } @@ -878,16 +1022,19 @@ bool ClientProxy::IsConnectionRejected(const std::string& endpoint_id) const { } bool ClientProxy::LocalConnectionIsAccepted(std::string endpoint_id) const { + MutexLock lock(&mutex_); return ConnectionStatusesContains( endpoint_id, ClientProxy::Connection::kLocalEndpointAccepted); } bool ClientProxy::RemoteConnectionIsAccepted(std::string endpoint_id) const { + MutexLock lock(&mutex_); return ConnectionStatusesContains( endpoint_id, ClientProxy::Connection::kRemoteEndpointAccepted); } bool ClientProxy::AutoUpgradeBandwidth() const { + MutexLock lock(&mutex_); bool result = false; if (IsAdvertising() && (GetAdvertisingOptions().strategy.IsNone() || GetAdvertisingOptions().auto_upgrade_bandwidth)) { @@ -902,6 +1049,7 @@ bool ClientProxy::AutoUpgradeBandwidth() const { } bool ClientProxy::ShouldEnforceTopologyConstraints() const { + MutexLock lock(&mutex_); bool result = false; if (IsAdvertising() && (GetAdvertisingOptions().strategy.IsNone() || @@ -922,6 +1070,7 @@ void ClientProxy::AddCancellationFlag(const std::string& endpoint_id) { return; } + MutexLock lock(&mutex_); auto item = cancellation_flags_.find(endpoint_id); if (item != cancellation_flags_.end()) { // A new flag may be added to the map with the same endpoint, even if a @@ -936,19 +1085,21 @@ void ClientProxy::AddCancellationFlag(const std::string& endpoint_id) { return; } cancellation_flags_.emplace(endpoint_id, - std::make_unique()); + std::make_shared()); } -CancellationFlag* ClientProxy::GetCancellationFlag( +std::shared_ptr ClientProxy::GetCancellationFlag( const std::string& endpoint_id) { + MutexLock lock(&mutex_); const auto item = cancellation_flags_.find(endpoint_id); if (item == cancellation_flags_.end()) { - return default_cancellation_flag_.get(); + return default_cancellation_flag_; } - return item->second.get(); + return item->second; } void ClientProxy::CancelEndpoint(const std::string& endpoint_id) { + MutexLock lock(&mutex_); const auto item = cancellation_flags_.find(endpoint_id); if (item != cancellation_flags_.end()) { item->second->Cancel(); @@ -959,6 +1110,7 @@ const OsInfo& ClientProxy::GetLocalOsInfo() const { return local_os_info_; } std::optional ClientProxy::GetRemoteOsInfo( absl::string_view endpoint_id) const { + MutexLock lock(&mutex_); const ConnectionPair* item = LookupConnection(endpoint_id); if (item != nullptr) { return item->first.os_info; @@ -968,11 +1120,13 @@ std::optional ClientProxy::GetRemoteOsInfo( void ClientProxy::SetLocalOsType( const location::nearby::connections::OsInfo::OsType& os_type) { + MutexLock lock(&mutex_); local_os_info_.set_type(os_type); } void ClientProxy::SetRemoteOsInfo(absl::string_view endpoint_id, const OsInfo& remote_os_info) { + MutexLock lock(&mutex_); ConnectionPair* item = LookupConnection(endpoint_id); if (item != nullptr) { item->first.os_info.emplace(remote_os_info); @@ -1008,14 +1162,6 @@ bool ClientProxy::IsSafeToDisconnectEnabled(absl::string_view endpoint_id) { .min_nc_version_supports_safe_to_disconnect); } -bool ClientProxy::IsAutoReconnectEnabled(absl::string_view endpoint_id) { - return IsSupportAutoReconnect() && - GetRemoteSafeToDisconnectVersion(endpoint_id).has_value() && - (GetRemoteSafeToDisconnectVersion(endpoint_id) >= - FeatureFlags::GetInstance() - .GetFlags() - .min_nc_version_supports_auto_reconnect); -} bool ClientProxy::IsPayloadReceivedAckEnabled(absl::string_view endpoint_id) { return IsSupportSafeToDisconnect() && @@ -1027,8 +1173,9 @@ bool ClientProxy::IsPayloadReceivedAckEnabled(absl::string_view endpoint_id) { } void ClientProxy::CancelAllEndpoints() { + MutexLock lock(&mutex_); for (const auto& item : cancellation_flags_) { - CancellationFlag* cancellation_flag = item.second.get(); + std::shared_ptr cancellation_flag = item.second; if (cancellation_flag->Cancelled()) { continue; } @@ -1131,14 +1278,17 @@ void ClientProxy::AppendConnectionStatus(const std::string& endpoint_id, } AdvertisingOptions ClientProxy::GetAdvertisingOptions() const { + MutexLock lock(&mutex_); return advertising_options_; } DiscoveryOptions ClientProxy::GetDiscoveryOptions() const { + MutexLock lock(&mutex_); return discovery_options_; } v3::ConnectionListeningOptions ClientProxy::GetListeningOptions() const { + MutexLock lock(&mutex_); return listening_options_; } @@ -1216,29 +1366,13 @@ OsInfo::OsType ClientProxy::OSNameToOsInfoType(api::OSName osName) { } std::int32_t ClientProxy::GetLocalMultiplexSocketBitmask() const { - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplex)) { - std::int32_t multiplex_bitmask = - (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexBluetooth) - ? kBtMultiplexEnabled - : 0) | - (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexWifiLan) - ? kWifiLanMultiplexEnabled - : 0); - LOG(INFO) << "ClientProxy [GetLocalMultiplexSocketBitmask]: " - << multiplex_bitmask; - return multiplex_bitmask; - } + MutexLock lock(&mutex_); return 0; } void ClientProxy::SetRemoteMultiplexSocketBitmask( absl::string_view endpoint_id, int remote_multiplex_socket_bitmask) { + MutexLock lock(&mutex_); ConnectionPair* item = LookupConnection(endpoint_id); if (item != nullptr) { item->first.remote_multiplex_socket_bitmask = @@ -1249,6 +1383,7 @@ void ClientProxy::SetRemoteMultiplexSocketBitmask( } bool ClientProxy::IsLocalMultiplexSocketSupported(Medium medium) { + MutexLock lock(&mutex_); int bitmask = GetLocalMultiplexSocketBitmask(); switch (medium) { case Medium::BLUETOOTH: @@ -1264,6 +1399,7 @@ bool ClientProxy::IsLocalMultiplexSocketSupported(Medium medium) { std::optional ClientProxy::GetRemoteMultiplexSocketBitmask( absl::string_view endpoint_id) const { + MutexLock lock(&mutex_); const ConnectionPair* item = LookupConnection(endpoint_id); if (item != nullptr) { return item->first.remote_multiplex_socket_bitmask; @@ -1273,6 +1409,7 @@ std::optional ClientProxy::GetRemoteMultiplexSocketBitmask( bool ClientProxy::IsMultiplexSocketSupported(absl::string_view endpoint_id, Medium medium) { + MutexLock lock(&mutex_); ConnectionPair* item = LookupConnection(endpoint_id); if (item == nullptr) { return false; @@ -1290,20 +1427,31 @@ bool ClientProxy::IsMultiplexSocketSupported(absl::string_view endpoint_id, } } -bool ClientProxy::GetWebRtcNonCellular() { return webrtc_non_cellular_; } +bool ClientProxy::GetWebRtcNonCellular() { + MutexLock lock(&mutex_); + return webrtc_non_cellular_; +} void ClientProxy::SetWebRtcNonCellular(bool webrtc_non_cellular) { + MutexLock lock(&mutex_); VLOG(1) << "ClientProxy: client=" << GetClientId() << (webrtc_non_cellular ? " disallow" : " allow") << " to use mobile data."; webrtc_non_cellular_ = webrtc_non_cellular; } -bool ClientProxy::IsDctEnabled() const { return is_dct_enabled_; } +bool ClientProxy::IsDctEnabled() const { + MutexLock lock(&mutex_); + return is_dct_enabled_; +} -uint8_t ClientProxy::GetDctDedup() const { return dct_dedup_; } +uint8_t ClientProxy::GetDctDedup() const { + MutexLock lock(&mutex_); + return dct_dedup_; +} void ClientProxy::UpdateDctDeviceName(absl::string_view device_name) { + MutexLock lock(&mutex_); if (!dct_device_name_.empty() && dct_device_name_ != device_name) { // Need to update dedup value if device name is changed. absl::BitGen bitgen; @@ -1325,6 +1473,7 @@ void ClientProxy::UpdateDctDeviceName(absl::string_view device_name) { std::optional ClientProxy::GetMediumRole( absl::string_view endpoint_id) const { + MutexLock lock(&mutex_); const ConnectionPair* item = LookupConnection(endpoint_id); if (item != nullptr) { return item->first.connection_options.connection_info.medium_role; @@ -1333,6 +1482,7 @@ std::optional ClientProxy::GetMediumRole( } std::optional ClientProxy::GetEndpointIdForDct() const { + MutexLock lock(&mutex_); if (dct_endpoint_id_.empty()) { return std::nullopt; } @@ -1340,13 +1490,20 @@ std::optional ClientProxy::GetEndpointIdForDct() const { return dct_endpoint_id_; } +#ifdef NEARBY_CHROMIUM +void ClientProxy::InitializePreferencesManager() { + // This method is not currently used by Chromium. + NOTREACHED(); +} +#else void ClientProxy::InitializePreferencesManager() { LOG(INFO) << "ClientProxy [InitializePreferencesManager]: client=" << GetClientId(); - auto device_info_ = std::make_unique(); + std::unique_ptr device_info_ = + nearby::api::ImplementationPlatform::CreateDeviceInfo(); FilePath preferences_path = - device_info_->GetAppDataPath().append(FilePath(kPreferencesFilePath)); + device_info_->GetLocalAppDataPath(FilePath(kPreferencesFilePath)); if (!Files::FileExists(preferences_path)) { Files::CreateDirectories(preferences_path); @@ -1361,6 +1518,7 @@ void ClientProxy::InitializePreferencesManager() { << GetClientId(); } } +#endif void ClientProxy::SaveClientInfoToPreferences() { MutexLock lock(&mutex_); diff --git a/connections/implementation/client_proxy.h b/connections/implementation/client_proxy.h index 05406a27..c5400fe5 100644 --- a/connections/implementation/client_proxy.h +++ b/connections/implementation/client_proxy.h @@ -32,6 +32,7 @@ #include "connections/connection_options.h" #include "connections/discovery_options.h" #include "connections/implementation/analytics/analytics_recorder.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/listeners.h" #include "connections/medium_selector.h" @@ -41,7 +42,6 @@ #include "connections/v3/connection_listening_options.h" #include "connections/v3/connections_device_provider.h" #include "connections/v3/listeners.h" -#include "internal/analytics/event_logger.h" #include "internal/interop/device.h" #include "internal/interop/device_provider.h" #include "internal/platform/byte_array.h" @@ -54,7 +54,6 @@ #include "internal/platform/mutex.h" #include "internal/platform/os_name.h" #include "internal/platform/scheduled_executor.h" -#include "internal/proto/analytics/connections_log.pb.h" namespace nearby::connections { @@ -66,8 +65,8 @@ class ClientProxy final { static constexpr absl::Duration kHighPowerAdvertisementEndpointIdCacheTimeout = absl::Seconds(30); - explicit ClientProxy( - ::nearby::analytics::EventLogger* event_logger = nullptr); + explicit ClientProxy(std::unique_ptr + analytics_recorder = nullptr); ~ClientProxy(); ClientProxy(ClientProxy&&) = default; ClientProxy& operator=(ClientProxy&&) = default; @@ -109,8 +108,7 @@ class ClientProxy final { const std::string& service_id, Strategy strategy, const ConnectionListener& connection_lifecycle_listener, absl::Span mediums, - const std::vector& + const std::vector& operation_result_with_medium, const AdvertisingOptions& advertising_options = AdvertisingOptions{}); // Marks this client as not advertising. @@ -134,8 +132,7 @@ class ClientProxy final { const std::string& service_id, Strategy strategy, DiscoveryListener discovery_listener, absl::Span mediums, - const std::vector& + const std::vector& operation_result_with_medium, const DiscoveryOptions& discovery_options = DiscoveryOptions{}); // Marks this client as not discovering at all. @@ -264,7 +261,8 @@ class ClientProxy final { // Adds a CancellationFlag for endpoint id. void AddCancellationFlag(const std::string& endpoint_id); // Returns the CancellationFlag for endpoint id, - CancellationFlag* GetCancellationFlag(const std::string& endpoint_id); + std::shared_ptr GetCancellationFlag( + const std::string& endpoint_id); // Sets the CancellationFlag to true for endpoint id. void CancelEndpoint(const std::string& endpoint_id); // Cancels all CancellationFlags. @@ -303,18 +301,12 @@ class ClientProxy final { return supports_safe_to_disconnect_; } - bool IsSupportAutoReconnect() const { return support_auto_reconnect_; } - - const std::int32_t& GetLocalSafeToDisconnectVersion() const { - return local_safe_to_disconnect_version_; - } std::optional GetRemoteSafeToDisconnectVersion( absl::string_view endpoint_id) const; void SetRemoteSafeToDisconnectVersion( absl::string_view endpoint_id, const std::int32_t& safe_to_disconnect_version); bool IsSafeToDisconnectEnabled(absl::string_view endpoint_id); - bool IsAutoReconnectEnabled(absl::string_view endpoint_id); bool IsPayloadReceivedAckEnabled(absl::string_view endpoint_id); // Returns the multiplex socket supports status for local device. @@ -525,11 +517,11 @@ class ClientProxy final { // Maps endpoint_id to CancellationFlag. CancellationFlags are passed around // as raw pointers to other classes in Nearby Connections, so it is important // that objects in this map are not cleared, even if they are cancelled. - absl::flat_hash_map> + absl::flat_hash_map> cancellation_flags_; // A default cancellation flag with isCancelled set be true. - std::unique_ptr default_cancellation_flag_ = - std::make_unique(true); + std::shared_ptr default_cancellation_flag_ = + std::make_shared(true); // An app lifecycle monitor for monitoring the app lifecycle state. std::unique_ptr app_lifecycle_monitor_; @@ -549,8 +541,6 @@ class ClientProxy final { // For Nearby Connections' own device provider. std::unique_ptr connections_device_provider_; bool supports_safe_to_disconnect_; - bool support_auto_reconnect_; - std::int32_t local_safe_to_disconnect_version_; // Allowed to use WebRTC over non-cellular networks. bool webrtc_non_cellular_ = false; // Whether DCT is enabled. diff --git a/connections/implementation/client_proxy_test.cc b/connections/implementation/client_proxy_test.cc index 172a58d8..d54a236b 100644 --- a/connections/implementation/client_proxy_test.cc +++ b/connections/implementation/client_proxy_test.cc @@ -14,6 +14,7 @@ #include "connections/implementation/client_proxy.h" +#include #include #include #include @@ -32,17 +33,18 @@ #include "connections/advertising_options.h" #include "connections/connection_options.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/mock_analytics_recorder.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/payload.h" #include "connections/status.h" #include "connections/strategy.h" +#include "connections/v3/bandwidth_info.h" #include "connections/v3/connection_listening_options.h" #include "connections/v3/connection_result.h" #include "connections/v3/connections_device_provider.h" #include "connections/v3/listeners.h" -#include "internal/analytics/mock_event_logger.h" #include "internal/flags/nearby_flags.h" #include "internal/interop/device.h" #include "internal/interop/device_provider.h" @@ -51,19 +53,18 @@ #include "internal/platform/count_down_latch.h" #include "internal/platform/feature_flags.h" #include "internal/platform/medium_environment.h" -#include "internal/platform/mutex.h" -#include "internal/platform/mutex_lock.h" +#include "internal/platform/single_thread_executor.h" #include "proto/connections_enums.pb.h" namespace nearby { namespace connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::OsInfo; using ::location::nearby::proto::connections::CLIENT_SESSION; using ::location::nearby::proto::connections::START_CLIENT_SESSION; using ::location::nearby::proto::connections::STOP_CLIENT_SESSION; +using ::testing::_; using ::testing::IsEmpty; using ::testing::MockFunction; using ::testing::StrictMock; @@ -77,46 +78,6 @@ constexpr FeatureFlags::Flags kTestCases[] = { }, }; -class FakeEventLogger : public ::nearby::analytics::MockEventLogger { - public: - explicit FakeEventLogger() = default; - - void Log(const ConnectionsLog& message) override { - MutexLock lock(&mutex_); - logs_.push_back(message); - } - - int GetCompleteClientSessionCount() { - MutexLock lock(&mutex_); - bool has_start_client_session = false; - bool has_client_session = false; - int session_count = 0; - // We expect series of START_CLIENT_SESSION, CLIENT_SESSION and - // STOP_CLIENT_SESSION events, possibly interleaved with other events. - for (const auto& log : logs_) { - if (log.event_type() == START_CLIENT_SESSION) { - EXPECT_FALSE(has_start_client_session); - EXPECT_FALSE(has_client_session); - has_start_client_session = true; - } else if (log.event_type() == CLIENT_SESSION) { - EXPECT_TRUE(has_start_client_session); - EXPECT_FALSE(has_client_session); - has_client_session = true; - } else if (log.event_type() == STOP_CLIENT_SESSION) { - EXPECT_TRUE(has_start_client_session); - EXPECT_TRUE(has_client_session); - has_start_client_session = false; - has_client_session = false; - ++session_count; - } - } - return session_count; - } - - Mutex mutex_; - std::vector logs_; -}; - class MockDeviceProvider : public nearby::NearbyDeviceProvider { public: MOCK_METHOD((const NearbyDevice*), GetLocalDevice, (), (override)); @@ -165,8 +126,14 @@ class ClientProxyTest : public ::testing::TestWithParam { /*use_simulated_clock=*/true, /*use_temporary_directory_for_app_path=*/true}; env_.Start(config); - client1_ = std::make_unique(&event_logger1_); - client2_ = std::make_unique(&event_logger2_); + auto analytics_recorder1 = + std::make_unique(); + mock_analytics_recorder1_ptr_ = analytics_recorder1.get(); + client1_ = std::make_unique(std::move(analytics_recorder1)); + auto analytics_recorder2 = + std::make_unique(); + mock_analytics_recorder2_ptr_ = analytics_recorder2.get(); + client2_ = std::make_unique(std::move(analytics_recorder2)); } void TearDown() override { @@ -360,10 +327,7 @@ class ClientProxyTest : public ::testing::TestWithParam { ClientProxy* client2() { return client2_.get(); } void FastForward(absl::Duration duration) { - (*env_.GetSimulatedClock()) - ->FastForward( - ClientProxy::kHighPowerAdvertisementEndpointIdCacheTimeout + - absl::Milliseconds(100)); + env_.FastForward(duration); // make sure the timer based callback is executed. absl::SleepFor(absl::Milliseconds(100)); } @@ -383,8 +347,8 @@ class ClientProxyTest : public ::testing::TestWithParam { MediumEnvironment& env_ = MediumEnvironment::Instance(); Strategy strategy_{Strategy::kP2pPointToPoint}; const std::string service_id_{"service"}; - FakeEventLogger event_logger1_; - FakeEventLogger event_logger2_; + analytics::MockAnalyticsRecorder* mock_analytics_recorder1_ptr_; + analytics::MockAnalyticsRecorder* mock_analytics_recorder2_ptr_; std::unique_ptr client1_; std::unique_ptr client2_; std::string auth_token_ = "auth_token"; @@ -437,7 +401,7 @@ TEST_P(ClientProxyTest, CanCancelEndpoint) { // `CancellationFlag` pointers are passed to other classes in Nearby // Connections, and by using the pointers directly, we test their // consumption of `CancellationFlag` pointers. - CancellationFlag* cancellation_flag = + std::shared_ptr cancellation_flag = client2()->GetCancellationFlag(advertising_endpoint.id); EXPECT_FALSE( @@ -473,7 +437,7 @@ TEST_P(ClientProxyTest, CanCancelAllEndpoints) { // `CancellationFlag` pointers are passed to other classes in Nearby // Connections, and by using the pointers directly, we test their // consumption of `CancellationFlag` pointers. - CancellationFlag* cancellation_flag = + std::shared_ptr cancellation_flag = client2()->GetCancellationFlag(advertising_endpoint.id); EXPECT_FALSE( @@ -540,6 +504,26 @@ TEST_P(ClientProxyTest, CanCancelAllEndpointsWithDifferentEndpoint) { } } +TEST_P(ClientProxyTest, GetCancellationFlagRace) { + std::string endpoint_id = "test_endpoint"; + client1()->AddCancellationFlag(endpoint_id); + + std::atomic run{true}; + SingleThreadExecutor executor; + executor.Execute([&]() { + while (run) { + client1()->GetCancellationFlag(endpoint_id); + } + }); + + for (int i = 0; i < 10000; ++i) { + client1()->Reset(); + client1()->AddCancellationFlag(endpoint_id); + } + + run = false; +} + INSTANTIATE_TEST_SUITE_P(ParametrisedClientProxyTest, ClientProxyTest, ::testing::ValuesIn(kTestCases)); @@ -1161,11 +1145,13 @@ TEST_F(ClientProxyTest, NotLogSessionForStoppedAdvertisingWithConnection) { // After StopAdvertising(client1()); // No Advertising - EXPECT_EQ(event_logger1_.GetCompleteClientSessionCount(), 0); + EXPECT_CALL(*mock_analytics_recorder1_ptr_, LogSession()).Times(1); } TEST_F(ClientProxyTest, LogSessionForStoppedAdvertisingWhenNoConnectionsAndNoDiscovering) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); @@ -1174,36 +1160,47 @@ TEST_F(ClientProxyTest, advertising_endpoint.id)); // No Connections EXPECT_FALSE(client1()->IsDiscovering()); // No Discovery EXPECT_TRUE(client1()->IsAdvertising()); // Advertising - EXPECT_EQ(event_logger1_.GetCompleteClientSessionCount(), 0); // After + EXPECT_CALL(*mock_analytics_recorder1_ptr_, OnStopAdvertising()); StopAdvertising(client1()); - EXPECT_GT(event_logger1_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, NotLogSessionForStoppedDiscoveryWithConnection) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnStartDiscovery(strategy_, mediums_, _)); StartDiscovery(client2(), GetDiscoveryListener()); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnEndpointFound(Medium::BLUETOOTH)); OnDiscoveryEndpointFound(client2(), advertising_endpoint); // Before + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnConnectionRequestReceived(advertising_endpoint.id)); OnDiscoveryConnectionInitiated( client2(), advertising_endpoint); // Connections are available EXPECT_FALSE(client2()->IsAdvertising()); // No Advertising EXPECT_TRUE(client2()->IsDiscovering()); // Discovering // After + EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery()); StopDiscovery(client2()); - EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, NotLogSessionForStoppedDiscoveryWithoutConnectionsAndAdvertising) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnStartDiscovery(strategy_, mediums_, _)); StartDiscovery(client2(), GetDiscoveryListener()); // Before @@ -1213,30 +1210,40 @@ TEST_F(ClientProxyTest, advertising_endpoint.id)); // No Connections // After + EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery()); StopDiscovery(client2()); - EXPECT_GT(event_logger2_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, LogSessionOnDisconnectedWithOneConnection) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnStartDiscovery(strategy_, mediums_, _)); StartDiscovery(client2(), GetDiscoveryListener()); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnEndpointFound(Medium::BLUETOOTH)); OnDiscoveryEndpointFound(client2(), advertising_endpoint); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnConnectionRequestReceived(advertising_endpoint.id)); OnDiscoveryConnectionInitiated(client2(), advertising_endpoint); // Before EXPECT_FALSE(client2()->IsAdvertising()); // No Advertising + EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery()); StopDiscovery(client2()); // No Discovery EXPECT_TRUE(client2()->HasPendingConnectionToEndpoint( advertising_endpoint.id)); // One Connection // After OnDiscoveryConnectionDisconnected(client2(), advertising_endpoint); - EXPECT_GT(event_logger2_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, NotLogSessionOnDisconnectedWithoutConnectionsDiscoveringAdvertising) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); @@ -1248,13 +1255,16 @@ TEST_F(ClientProxyTest, // After client2()->OnDisconnected(advertising_endpoint.id, /*notify=*/false); - EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, NotLogSessionOnDisconnectedWhenMoreThanOneConnection) { ClientProxy client3; + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint_1 = StartAdvertising(client1(), advertising_connection_listener_); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint_2 = StartAdvertising(client2(), advertising_connection_listener_); StartDiscovery(&client3, GetDiscoveryListener()); @@ -1275,15 +1285,22 @@ TEST_F(ClientProxyTest, NotLogSessionOnDisconnectedWhenMoreThanOneConnection) { // After client2()->OnDisconnected(advertising_endpoint_1.id, /*notify=*/false); - EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, NotLogSessionOnDisconnectedForDiscoveringWithOnlyOneConnection) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnStartDiscovery(strategy_, mediums_, _)); StartDiscovery(client2(), GetDiscoveryListener()); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnEndpointFound(Medium::BLUETOOTH)); OnDiscoveryEndpointFound(client2(), advertising_endpoint); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnConnectionRequestReceived(advertising_endpoint.id)); OnDiscoveryConnectionInitiated(client2(), advertising_endpoint); // Before @@ -1294,26 +1311,27 @@ TEST_F(ClientProxyTest, // After OnDiscoveryConnectionDisconnected(client2(), advertising_endpoint); - // Since we are no longer checking IsDiscovering(), we complete sessions now - // solely based on advertising. - EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 1); } TEST_F(ClientProxyTest, LogSessionForResetClientProxy) { + EXPECT_CALL(*mock_analytics_recorder1_ptr_, + OnStartAdvertising(strategy_, mediums_, _)); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnStartDiscovery(strategy_, mediums_, _)); StartDiscovery(client2(), GetDiscoveryListener()); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnEndpointFound(Medium::BLUETOOTH)); OnDiscoveryEndpointFound(client2(), advertising_endpoint); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, + OnConnectionRequestReceived(advertising_endpoint.id)); OnDiscoveryConnectionInitiated(client2(), advertising_endpoint); - EXPECT_EQ(event_logger1_.GetCompleteClientSessionCount(), 0); + EXPECT_CALL(*mock_analytics_recorder1_ptr_, OnStopAdvertising()); client1()->Reset(); - // TODO(b/290936886): Why are there more than one complete sessions? - EXPECT_GT(event_logger1_.GetCompleteClientSessionCount(), 0); - - EXPECT_EQ(event_logger2_.GetCompleteClientSessionCount(), 0); + EXPECT_CALL(*mock_analytics_recorder2_ptr_, OnStopDiscovery()); client2()->Reset(); - EXPECT_GT(event_logger2_.GetCompleteClientSessionCount(), 0); } TEST_F(ClientProxyTest, GetLocalInfoCorrect) { @@ -1484,51 +1502,10 @@ TEST_F(ClientProxyTest, TestAutoBwuWhenListeningWithAutoBwu) { } TEST_F(ClientProxyTest, TestMultiplexSocketBitmask) { - if (!NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplex)) { - EXPECT_EQ(client1()->GetLocalMultiplexSocketBitmask(), 0); - } - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableMultiplex, - true); EXPECT_EQ(client1()->GetLocalMultiplexSocketBitmask(), 0); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexBluetooth, - true); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexWifiLan, - true); - EXPECT_EQ( - client1()->GetLocalMultiplexSocketBitmask(), - ClientProxy::kBtMultiplexEnabled | ClientProxy::kWifiLanMultiplexEnabled); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableMultiplex, - false); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexBluetooth, - false); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexWifiLan, - false); } TEST_F(ClientProxyTest, TestRemoteMultiplexSocketBitmask) { - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableMultiplex, - true); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexBluetooth, - true); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexWifiLan, - true); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); OnAdvertisingConnectionInitiated(client1(), advertising_endpoint); @@ -1543,23 +1520,12 @@ TEST_F(ClientProxyTest, TestRemoteMultiplexSocketBitmask) { ->GetRemoteMultiplexSocketBitmask(advertising_endpoint.id) .value(), ClientProxy::kBtMultiplexEnabled | ClientProxy::kWifiLanMultiplexEnabled); - EXPECT_TRUE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id, - Medium::BLUETOOTH)); - EXPECT_TRUE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id, - Medium::WIFI_LAN)); + EXPECT_FALSE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id, + Medium::BLUETOOTH)); + EXPECT_FALSE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id, + Medium::WIFI_LAN)); EXPECT_FALSE(client1()->IsMultiplexSocketSupported(advertising_endpoint.id, Medium::WIFI_AWARE)); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableMultiplex, - false); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexBluetooth, - false); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexWifiLan, - false); } TEST_F(ClientProxyTest, SaveClientInfoFromPreferences) { @@ -1567,7 +1533,7 @@ TEST_F(ClientProxyTest, SaveClientInfoFromPreferences) { config_package_nearby::nearby_connections_feature:: kEnableNearbyConnectionsPreferences, true); - client1_ = std::make_unique(&event_logger1_); + client1_ = std::make_unique(); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); std::string endpoint_id = advertising_endpoint.id; @@ -1575,7 +1541,7 @@ TEST_F(ClientProxyTest, SaveClientInfoFromPreferences) { // Destroy the client and create a new one. client1_.reset(); - client1_ = std::make_unique(&event_logger1_); + client1_ = std::make_unique(); // The new client should load the same endpoint ID. EXPECT_EQ(client1()->GetLocalEndpointId(), endpoint_id); @@ -1590,7 +1556,7 @@ TEST_F(ClientProxyTest, NotLoadClientInfoFromPreferencesOnExpired) { config_package_nearby::nearby_connections_feature:: kEnableNearbyConnectionsPreferences, true); - client1_ = std::make_unique(&event_logger1_); + client1_ = std::make_unique(); Endpoint advertising_endpoint = StartAdvertising(client1(), advertising_connection_listener_); std::string endpoint_id = advertising_endpoint.id; @@ -1600,7 +1566,7 @@ TEST_F(ClientProxyTest, NotLoadClientInfoFromPreferencesOnExpired) { client1_.reset(); FastForward(absl::Hours(25)); - client1_ = std::make_unique(&event_logger1_); + client1_ = std::make_unique(); // The new client should load the same endpoint ID. EXPECT_NE(client1()->GetLocalEndpointId(), endpoint_id); diff --git a/connections/implementation/connections_authentication_transport.cc b/connections/implementation/connections_authentication_transport.cc index c98edbbe..f4bb001d 100644 --- a/connections/implementation/connections_authentication_transport.cc +++ b/connections/implementation/connections_authentication_transport.cc @@ -14,30 +14,30 @@ #include "connections/implementation/connections_authentication_transport.h" +#include #include +#include #include "absl/strings/string_view.h" #include "connections/implementation/endpoint_channel.h" -#include "internal/platform/byte_array.h" #include "internal/platform/logging.h" namespace nearby { namespace connections { ConnectionsAuthenticationTransport::ConnectionsAuthenticationTransport( - const EndpointChannel& channel) { - channel_ = const_cast(&channel); -} + std::shared_ptr channel) + : channel_(std::move(channel)) {} void ConnectionsAuthenticationTransport::WriteMessage( absl::string_view message) const { - // channel_ should never be null. + // channel_ is guaranteed valid by shared_ptr ownership CHECK(channel_ != nullptr); - channel_->Write(ByteArray(message.data(), message.size())); + channel_->Write(message); } std::string ConnectionsAuthenticationTransport::ReadMessage() const { - // channel_ should never be null. + // channel_ is guaranteed valid by shared_ptr ownership CHECK(channel_ != nullptr); auto response = channel_->Read(); if (response.ok()) { diff --git a/connections/implementation/connections_authentication_transport.h b/connections/implementation/connections_authentication_transport.h index ab7886d4..a4bcafac 100644 --- a/connections/implementation/connections_authentication_transport.h +++ b/connections/implementation/connections_authentication_transport.h @@ -15,6 +15,7 @@ #ifndef THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_CONNECTIONS_AUTHENTICATION_TRANSPORT_H_ #define THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_CONNECTIONS_AUTHENTICATION_TRANSPORT_H_ +#include #include #include "absl/strings/string_view.h" @@ -30,12 +31,13 @@ namespace connections { class ConnectionsAuthenticationTransport : public nearby::AuthenticationTransport { public: - explicit ConnectionsAuthenticationTransport(const EndpointChannel& channel); + explicit ConnectionsAuthenticationTransport( + std::shared_ptr channel); void WriteMessage(absl::string_view message) const override; std::string ReadMessage() const override; private: - EndpointChannel* channel_; + std::shared_ptr channel_; }; } // namespace connections diff --git a/connections/implementation/connections_authentication_transport_test.cc b/connections/implementation/connections_authentication_transport_test.cc index 11ebd2eb..333a4da2 100644 --- a/connections/implementation/connections_authentication_transport_test.cc +++ b/connections/implementation/connections_authentication_transport_test.cc @@ -14,7 +14,6 @@ #include "connections/implementation/connections_authentication_transport.h" -#include #include #include #include @@ -23,12 +22,9 @@ #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "connections/implementation/analytics/analytics_recorder.h" -#include "connections/implementation/endpoint_channel.h" +#include "connections/implementation/mock_endpoint_channel.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" -#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { @@ -36,84 +32,40 @@ namespace { using ::testing::_; -class MockEndpointChannel : public EndpointChannel { - public: - MOCK_METHOD(ExceptionOr, Read, (), (override)); - MOCK_METHOD(ExceptionOr, Read, (PacketMetaData&), (override)); - MOCK_METHOD(Exception, Write, (const ByteArray& data), (override)); - MOCK_METHOD(Exception, Write, (absl::string_view data, PacketMetaData&), - (override)); - MOCK_METHOD(void, Close, (), (override)); - MOCK_METHOD( - void, Close, - (location::nearby::proto::connections::DisconnectionReason reason), - (override)); - MOCK_METHOD(void, Close, - (location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result), - (override)); - MOCK_METHOD(bool, IsClosed, (), (const, override)); - MOCK_METHOD(std::string, GetType, (), (const, override)); - MOCK_METHOD(std::string, GetServiceId, (), (const, override)); - MOCK_METHOD(std::string, GetName, (), (const, override)); - MOCK_METHOD(location::nearby::proto::connections::Medium, GetMedium, (), - (const, override)); - MOCK_METHOD(location::nearby::proto::connections::ConnectionTechnology, - GetTechnology, (), (const, override)); - MOCK_METHOD(location::nearby::proto::connections::ConnectionBand, GetBand, (), - (const, override)); - MOCK_METHOD(int, GetFrequency, (), (const, override)); - MOCK_METHOD(int, GetTryCount, (), (const, override)); - MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const, override)); - MOCK_METHOD(void, EnableEncryption, (std::shared_ptr), - (override)); - MOCK_METHOD(void, DisableEncryption, (), (override)); - MOCK_METHOD(bool, IsEncrypted, (), (override)); - MOCK_METHOD(ExceptionOr, TryDecrypt, (const ByteArray& data), - (override)); - MOCK_METHOD(bool, IsPaused, (), (const, override)); - MOCK_METHOD(void, Pause, (), (override)); - MOCK_METHOD(void, Resume, (), (override)); - MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const, override)); - MOCK_METHOD(absl::Time, GetLastWriteTimestamp, (), (const, override)); - MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override)); - MOCK_METHOD(void, SetAnalyticsRecorder, - (analytics::AnalyticsRecorder*, const std::string&), (override)); - - std::vector messages_; -}; - TEST(ConnectionsAuthenticationTransportTest, TestWriteMessage) { - MockEndpointChannel channel; + std::vector messages; + auto channel = std::make_shared(); ConnectionsAuthenticationTransport transport(channel); - EXPECT_CALL(channel, Write(_)).WillOnce([&channel](const ByteArray& data) { - channel.messages_.push_back(data.string_data()); - return Exception{ - .value = Exception::Value::kSuccess, - }; - }); + EXPECT_CALL(*channel, Write(_)) + .WillOnce([&messages](absl::string_view data) { + messages.push_back(std::string(data)); + return Exception{ + .value = Exception::Value::kSuccess, + }; + }); transport.WriteMessage("hello world"); - EXPECT_THAT(channel.messages_, testing::ElementsAre("hello world")); + EXPECT_THAT(messages, testing::ElementsAre("hello world")); } TEST(ConnectionsAuthenticationTransportTest, TestReadMessage) { - MockEndpointChannel channel; + std::vector messages; + auto channel = std::make_shared(); ConnectionsAuthenticationTransport transport(channel); - channel.messages_.push_back("hello world"); - EXPECT_CALL(channel, Read()).WillOnce([&channel]() { - std::string ret = channel.messages_[0]; - channel.messages_.erase(channel.messages_.begin()); + messages.push_back("hello world"); + EXPECT_CALL(*channel, Read()).WillOnce([&messages]() { + std::string ret = messages[0]; + messages.erase(messages.begin()); return ExceptionOr(ByteArray(ret)); }); EXPECT_EQ(transport.ReadMessage(), "hello world"); } TEST(ConnectionsAuthenticationTransportTest, TestReadMessageFail) { - MockEndpointChannel channel; + std::vector messages; + auto channel = std::make_shared(); ConnectionsAuthenticationTransport transport(channel); - channel.messages_.push_back("hello world"); - EXPECT_CALL(channel, Read()).WillOnce([]() { + messages.push_back("hello world"); + EXPECT_CALL(*channel, Read()).WillOnce([]() { return ExceptionOr(Exception::Value::kIo); }); EXPECT_EQ(transport.ReadMessage(), ""); diff --git a/connections/implementation/encryption_runner.cc b/connections/implementation/encryption_runner.cc index a74a4b8e..a3ade421 100644 --- a/connections/implementation/encryption_runner.cc +++ b/connections/implementation/encryption_runner.cc @@ -14,7 +14,6 @@ #include "connections/implementation/encryption_runner.h" -#include #include #include #include @@ -22,7 +21,6 @@ #include "securegcm/ukey2_handshake.h" #include "absl/strings/ascii.h" -#include "absl/time/clock.h" #include "absl/time/time.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" @@ -70,9 +68,9 @@ bool HandleEncryptionSuccess(const std::string& endpoint_id, return true; } -void CancelableAlarmRunnable(ClientProxy* client, - const std::string& endpoint_id, - EndpointChannel* endpoint_channel) { +void CancelableAlarmRunnable( + ClientProxy* client, const std::string& endpoint_id, + std::shared_ptr endpoint_channel) { LOG(INFO) << "Timing out encryption for client " << client->GetClientId() << " to endpoint_id=" << endpoint_id << " after " << absl::FormatDuration(kTimeout); @@ -82,18 +80,31 @@ void CancelableAlarmRunnable(ClientProxy* client, class ServerRunnable final { public: ServerRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, - const std::string& endpoint_id, EndpointChannel* channel, + const std::string& endpoint_id, + std::shared_ptr channel, EncryptionRunner::ResultListener listener) : client_(client), alarm_executor_(alarm_executor), endpoint_id_(endpoint_id), - channel_(channel), + weak_channel_(channel), listener_(std::move(listener)) {} void operator()() { + // Lock the weak pointer. If it fails, the channel was freed. + auto channel = weak_channel_.lock(); + // The IsClosed() check is to provide an early exit if channel has been + // closed. Otherwise the Read() and Write() calls on the channel below will + // return error and exit. + if (!channel || channel->IsClosed()) { + return; + } CancelableAlarm timeout_alarm( "EncryptionRunner.StartServer() timeout", - [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, + [this, weak_channel = weak_channel_]() { + if (auto channel = weak_channel.lock()) { + CancelableAlarmRunnable(client_, endpoint_id_, channel); + } + }, kTimeout, alarm_executor_); std::unique_ptr server = @@ -105,7 +116,7 @@ class ServerRunnable final { } // Message 1 (Client Init) - ExceptionOr client_init = channel_->Read(); + ExceptionOr client_init = channel->Read(); if (!client_init.ok()) { LogException(); HandleHandshakeOrIoException(&timeout_alarm); @@ -119,7 +130,7 @@ class ServerRunnable final { if (!parse_result.success) { LogException(); if (parse_result.alert_to_send != nullptr) { - HandleAlertException(parse_result); + HandleAlertException(parse_result, channel); } HandleHandshakeOrIoException(&timeout_alarm); return; @@ -139,8 +150,7 @@ class ServerRunnable final { return; } - Exception write_exception = - channel_->Write(ByteArray(std::move(*server_init))); + Exception write_exception = channel->Write(*server_init); if (!write_exception.Ok()) { LogException(); HandleHandshakeOrIoException(&timeout_alarm); @@ -151,7 +161,7 @@ class ServerRunnable final { << endpoint_id_ << ")."; // Message 3 (Client Finish) - ExceptionOr client_finish = channel_->Read(); + ExceptionOr client_finish = channel->Read(); if (!client_finish.ok()) { LogException(); @@ -166,7 +176,7 @@ class ServerRunnable final { if (!parse_result.success) { LogException(); if (parse_result.alert_to_send != nullptr) { - HandleAlertException(parse_result); + HandleAlertException(parse_result, channel); } HandleHandshakeOrIoException(&timeout_alarm); return; @@ -192,13 +202,13 @@ class ServerRunnable final { void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) { timeout_alarm->Cancel(); - listener_.CallFailureCallback(endpoint_id_, channel_); + listener_.CallFailureCallback(endpoint_id_); } void HandleAlertException( - const securegcm::UKey2Handshake::ParseResult& parse_result) const { - Exception write_exception = - channel_->Write(ByteArray(*parse_result.alert_to_send)); + const securegcm::UKey2Handshake::ParseResult& parse_result, + std::shared_ptr channel) const { + Exception write_exception = channel->Write(*parse_result.alert_to_send); if (!write_exception.Ok()) { LOG(WARNING) << "In StartServer(), client " << client_->GetClientId() << " failed to pass the alert error message to endpoint(id=" @@ -209,25 +219,39 @@ class ServerRunnable final { ClientProxy* client_; ScheduledExecutor* alarm_executor_; const std::string endpoint_id_; - EndpointChannel* channel_; + std::weak_ptr weak_channel_; EncryptionRunner::ResultListener listener_; }; class ClientRunnable final { public: ClientRunnable(ClientProxy* client, ScheduledExecutor* alarm_executor, - const std::string& endpoint_id, EndpointChannel* channel, + const std::string& endpoint_id, + std::shared_ptr channel, EncryptionRunner::ResultListener listener) : client_(client), alarm_executor_(alarm_executor), endpoint_id_(endpoint_id), - channel_(channel), + weak_channel_(channel), listener_(std::move(listener)) {} void operator()() { + // Lock the weak pointer. If it fails, the channel was freed. + auto channel = weak_channel_.lock(); + // The IsClosed() check is to provide an early exit if channel has been + // closed. Otherwise the Read() and Write() calls on the channel below will + // return error and exit. + if (!channel || channel->IsClosed()) { + return; + } + CancelableAlarm timeout_alarm( "EncryptionRunner.StartClient() timeout", - [this]() { CancelableAlarmRunnable(client_, endpoint_id_, channel_); }, + [this, weak_channel = weak_channel_]() { + if (auto channel = weak_channel.lock()) { + CancelableAlarmRunnable(client_, endpoint_id_, channel); + } + }, kTimeout, alarm_executor_); std::unique_ptr crypto = @@ -251,7 +275,7 @@ class ClientRunnable final { return; } - Exception write_init_exception = channel_->Write(ByteArray(*client_init)); + Exception write_init_exception = channel->Write(*client_init); if (!write_init_exception.Ok()) { LogException(); HandleHandshakeOrIoException(&timeout_alarm); @@ -262,7 +286,7 @@ class ClientRunnable final { << endpoint_id_ << ")."; // Message 2 (Server Init) - ExceptionOr server_init = channel_->Read(); + ExceptionOr server_init = channel->Read(); if (!server_init.ok()) { LogException(); @@ -277,7 +301,7 @@ class ClientRunnable final { if (!parse_result.success) { LogException(); if (parse_result.alert_to_send != nullptr) { - HandleAlertException(parse_result); + HandleAlertException(parse_result, channel); } HandleHandshakeOrIoException(&timeout_alarm); return; @@ -297,8 +321,7 @@ class ClientRunnable final { return; } - Exception write_finish_exception = - channel_->Write(ByteArray(*client_finish)); + Exception write_finish_exception = channel->Write(*client_finish); if (!write_finish_exception.Ok()) { LogException(); HandleHandshakeOrIoException(&timeout_alarm); @@ -325,13 +348,13 @@ class ClientRunnable final { void HandleHandshakeOrIoException(CancelableAlarm* timeout_alarm) { timeout_alarm->Cancel(); - listener_.CallFailureCallback(endpoint_id_, channel_); + listener_.CallFailureCallback(endpoint_id_); } void HandleAlertException( - const securegcm::UKey2Handshake::ParseResult& parse_result) const { - Exception write_exception = - channel_->Write(ByteArray(*parse_result.alert_to_send)); + const securegcm::UKey2Handshake::ParseResult& parse_result, + std::shared_ptr channel) const { + Exception write_exception = channel->Write(*parse_result.alert_to_send); if (!write_exception.Ok()) { LOG(WARNING) << "In StartClient(), client " << client_->GetClientId() << " failed to pass the alert error message to endpoint(id=" @@ -342,7 +365,7 @@ class ClientRunnable final { ClientProxy* client_; ScheduledExecutor* alarm_executor_; const std::string endpoint_id_; - EndpointChannel* channel_; + std::weak_ptr weak_channel_; EncryptionRunner::ResultListener listener_; }; @@ -350,19 +373,19 @@ class ClientRunnable final { EncryptionRunner::~EncryptionRunner() { Shutdown(); } -void EncryptionRunner::StartServer(ClientProxy* client, - const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - EncryptionRunner::ResultListener listener) { +void EncryptionRunner::StartServer( + ClientProxy* client, const std::string& endpoint_id, + std::shared_ptr endpoint_channel, + EncryptionRunner::ResultListener listener) { ServerRunnable runnable(client, &alarm_executor_, endpoint_id, endpoint_channel, std::move(listener)); server_executor_.Execute("encryption-server", std::move(runnable)); } -void EncryptionRunner::StartClient(ClientProxy* client, - const std::string& endpoint_id, - EndpointChannel* endpoint_channel, - EncryptionRunner::ResultListener listener) { +void EncryptionRunner::StartClient( + ClientProxy* client, const std::string& endpoint_id, + std::shared_ptr endpoint_channel, + EncryptionRunner::ResultListener listener) { ClientRunnable runnable(client, &alarm_executor_, endpoint_id, endpoint_channel, std::move(listener)); client_executor_.Execute("encryption-client", std::move(runnable)); @@ -391,9 +414,9 @@ void EncryptionRunner::ResultListener::CallSuccessCallback( } void EncryptionRunner::ResultListener::CallFailureCallback( - const std::string& endpoint_id, EndpointChannel* channel) { + const std::string& endpoint_id) { if (on_failure_cb) { - std::move(on_failure_cb)(endpoint_id, channel); + std::move(on_failure_cb)(endpoint_id); } Reset(); } diff --git a/connections/implementation/encryption_runner.h b/connections/implementation/encryption_runner.h index e8e8c186..6e2236d7 100644 --- a/connections/implementation/encryption_runner.h +++ b/connections/implementation/encryption_runner.h @@ -45,8 +45,7 @@ class EncryptionRunner { std::unique_ptr ukey2, const std::string& auth_token, const ByteArray& raw_auth_token); - void CallFailureCallback(const std::string& endpoint_id, - EndpointChannel* channel); + void CallFailureCallback(const std::string& endpoint_id); void Reset(); // @EncryptionRunnerThread @@ -56,27 +55,19 @@ class EncryptionRunner { const ByteArray& raw_auth_token) &&> on_success_cb; - // Encryption has failed. The remote_endpoint_id and channel are given so - // that any pending state can be cleaned up. - // - // We return the EndpointChannel because, at this stage, simultaneous - // connections are a possibility. Use this channel to verify that the state - // you're cleaning up is for this EndpointChannel, and not state for another - // channel to the same endpoint. + // Encryption has failed. // // @EncryptionRunnerThread - absl::AnyInvocable - on_failure_cb; + absl::AnyInvocable on_failure_cb; }; // @AnyThread void StartServer(ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, + std::shared_ptr endpoint_channel, ResultListener result_listener); // @AnyThread void StartClient(ClientProxy* client, const std::string& endpoint_id, - EndpointChannel* endpoint_channel, + std::shared_ptr endpoint_channel, ResultListener result_listener); // @AnyThread diff --git a/connections/implementation/encryption_runner_test.cc b/connections/implementation/encryption_runner_test.cc index c5ec1964..743c1658 100644 --- a/connections/implementation/encryption_runner_test.cc +++ b/connections/implementation/encryption_runner_test.cc @@ -35,8 +35,7 @@ #include "proto/connections_enums.pb.h" #include "third_party/ukey2/src/main/cpp/include/securegcm/ukey2_handshake.h" -namespace nearby { -namespace connections { +namespace nearby::connections { namespace { using ::location::nearby::proto::connections::Medium; @@ -52,16 +51,8 @@ class FakeEndpointChannel : public EndpointChannel { read_timestamp_ = SystemClock::ElapsedRealtime(); return in_ ? in_->Read(kChunkSize) : ExceptionOr{Exception::kIo}; } - ExceptionOr Read(PacketMetaData& packet_meta_data) override { - read_timestamp_ = SystemClock::ElapsedRealtime(); - return in_ ? in_->Read(kChunkSize) : ExceptionOr{Exception::kIo}; - } - Exception Write(const ByteArray& data) override { - write_timestamp_ = SystemClock::ElapsedRealtime(); - return out_ ? out_->Write(data.AsStringView()) : Exception{Exception::kIo}; - } - Exception Write(absl::string_view data, - PacketMetaData& packet_meta_data) override { + + Exception Write(absl::string_view data) override { write_timestamp_ = SystemClock::ElapsedRealtime(); return out_ ? out_->Write(data) : Exception{Exception::kIo}; } @@ -73,10 +64,8 @@ class FakeEndpointChannel : public EndpointChannel { override { Close(); } - void Close( - location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result) override { + void Close(location::nearby::proto::connections::DisconnectionReason reason, + nearby::analytics::SafeDisconnectionResult result) override { Close(); } bool IsClosed() const override { return false; } @@ -124,21 +113,24 @@ class FakeEndpointChannel : public EndpointChannel { }; struct User { - User(InputStream* reader, OutputStream* writer) : channel(reader, writer) {} + User(InputStream* reader, OutputStream* writer) + : channel(std::make_shared(reader, writer)) {} - FakeEndpointChannel channel; + std::shared_ptr channel; EncryptionRunner crypto; ClientProxy client; }; struct Response { + Response() : latch(2) {} + explicit Response(int count) : latch(count) {} enum class Status { kUnknown = 0, kDone = 1, kFailed = 2, }; - CountDownLatch latch{2}; + CountDownLatch latch; Status server_status = Status::kUnknown; Status client_status = Status::kUnknown; }; @@ -155,7 +147,7 @@ TEST(EncryptionRunnerTest, ReadWrite) { Response response; user_a.crypto.StartServer( - &user_a.client, "endpoint_id", &user_a.channel, + &user_a.client, "endpoint_id", user_a.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -166,15 +158,14 @@ TEST(EncryptionRunnerTest, ReadWrite) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_a](const std::string& endpoint_id) { + user_a.channel->Close(); response.server_status = Response::Status::kFailed; response.latch.CountDown(); }, }); user_b.crypto.StartClient( - &user_b.client, "endpoint_id", &user_b.channel, + &user_b.client, "endpoint_id", user_b.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -185,9 +176,8 @@ TEST(EncryptionRunnerTest, ReadWrite) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_b](const std::string& endpoint_id) { + user_b.channel->Close(); response.client_status = Response::Status::kFailed; response.latch.CountDown(); }, @@ -204,14 +194,13 @@ TEST(EncryptionRunnerTest, ClientWriteFails) { /*writer=*/from_a_to_b.second.get()); User user_b(/*reader=*/from_a_to_b.first.get(), /*writer=*/from_b_to_a.second.get()); - Response response; - response.latch = CountDownLatch(1); + Response response(1); // Close server's input stream, so client can't write to it. from_b_to_a.first->Close(); user_b.crypto.StartClient( - &user_b.client, "endpoint_id", &user_b.channel, + &user_b.client, "endpoint_id", user_b.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -222,9 +211,8 @@ TEST(EncryptionRunnerTest, ClientWriteFails) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_a](const std::string& endpoint_id) { + user_a.channel->Close(); response.client_status = Response::Status::kFailed; response.latch.CountDown(); }, @@ -240,14 +228,13 @@ TEST(EncryptionRunnerTest, ServerWriteFails) { /*writer=*/from_a_to_b.second.get()); User user_b(/*reader=*/from_a_to_b.first.get(), /*writer=*/from_b_to_a.second.get()); - Response response; - response.latch = CountDownLatch(1); + Response response(1); // Close client's input stream, so server can't write to it. from_a_to_b.first->Close(); user_a.crypto.StartServer( - &user_a.client, "endpoint_id", &user_a.channel, + &user_a.client, "endpoint_id", user_a.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -258,24 +245,22 @@ TEST(EncryptionRunnerTest, ServerWriteFails) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_a](const std::string& endpoint_id) { + user_a.channel->Close(); response.server_status = Response::Status::kFailed; response.latch.CountDown(); }, }); user_b.crypto.StartClient( - &user_b.client, "endpoint_id", &user_b.channel, + &user_b.client, "endpoint_id", user_b.channel, { - .on_success_cb = - [](const std::string& endpoint_id, - std::unique_ptr ukey2, - const std::string& auth_token, - const ByteArray& raw_auth_token) {}, + .on_success_cb = [](const std::string& endpoint_id, + std::unique_ptr ukey2, + const std::string& auth_token, + const ByteArray& raw_auth_token) {}, .on_failure_cb = - [](const std::string& endpoint_id, EndpointChannel* channel) { - channel->Close(); + [&user_b](const std::string& endpoint_id) { + user_b.channel->Close(); }, }); EXPECT_TRUE(response.latch.Await(absl::Milliseconds(5000)).result()); @@ -287,11 +272,10 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage1) { auto from_client_to_server = CreatePipe(); User user_a(/*reader=*/from_client_to_server.first.get(), /*writer=*/from_server_to_client.second.get()); - Response response; - response.latch = CountDownLatch(1); + Response response(1); user_a.crypto.StartServer( - &user_a.client, "endpoint_id", &user_a.channel, + &user_a.client, "endpoint_id", user_a.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -302,9 +286,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage1) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_a](const std::string& endpoint_id) { + user_a.channel->Close(); response.server_status = Response::Status::kFailed; response.latch.CountDown(); }, @@ -328,11 +311,10 @@ TEST(EncryptionRunnerTest, ServerSendsGarbageMessage2) { auto from_client_to_server = CreatePipe(); User user_b(/*reader=*/from_server_to_client.first.get(), /*writer=*/from_client_to_server.second.get()); - Response response; - response.latch = CountDownLatch(1); + Response response(1); user_b.crypto.StartClient( - &user_b.client, "endpoint_id", &user_b.channel, + &user_b.client, "endpoint_id", user_b.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -343,9 +325,8 @@ TEST(EncryptionRunnerTest, ServerSendsGarbageMessage2) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_b](const std::string& endpoint_id) { + user_b.channel->Close(); response.client_status = Response::Status::kFailed; response.latch.CountDown(); }, @@ -374,11 +355,10 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) { /*writer=*/from_server_to_client.second.get()); User user_b(/*reader=*/from_server_to_client.first.get(), /*writer=*/from_client_to_server.second.get()); - Response response; - response.latch = CountDownLatch(1); + Response response(1); user_a.crypto.StartServer( - &user_a.client, "endpoint_id", &user_a.channel, + &user_a.client, "endpoint_id", user_a.channel, { .on_success_cb = [&response](const std::string& endpoint_id, @@ -389,9 +369,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) { response.latch.CountDown(); }, .on_failure_cb = - [&response](const std::string& endpoint_id, - EndpointChannel* channel) { - channel->Close(); + [&response, &user_a](const std::string& endpoint_id) { + user_a.channel->Close(); response.server_status = Response::Status::kFailed; response.latch.CountDown(); }, @@ -411,7 +390,8 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) { EXPECT_TRUE(server_init.ok()); // Client crypto parses message 2. - client_crypto->ParseHandshakeMessage(std::string(server_init.result())); + client_crypto->ParseHandshakeMessage( + std::string(server_init.result().data(), server_init.result().size())); // Client sends garbage instead of message 3 from_client_to_server.second->Write("Garbage"); @@ -427,5 +407,4 @@ TEST(EncryptionRunnerTest, ClientSendsGarbageMessage3) { } } // namespace -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/endpoint_channel.h b/connections/implementation/endpoint_channel.h index b4e9cbe3..1b286475 100644 --- a/connections/implementation/endpoint_channel.h +++ b/connections/implementation/endpoint_channel.h @@ -23,14 +23,10 @@ #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "connections/implementation/analytics/analytics_recorder.h" -#include "connections/implementation/analytics/packet_meta_data.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" -namespace nearby { -namespace connections { - -using analytics::PacketMetaData; +namespace nearby::connections { class EndpointChannel { public: @@ -41,15 +37,9 @@ class EndpointChannel { virtual ExceptionOr Read() = 0; // throws Exception::IO, Exception::INTERRUPTED - virtual ExceptionOr Read(PacketMetaData& packet_meta_data) = 0; + virtual Exception Write(absl::string_view data) = 0; // throws Exception::IO - virtual Exception Write(const ByteArray& data) = 0; // throws Exception::IO - - virtual Exception Write( - absl::string_view data, - PacketMetaData& packet_meta_data) = 0; // throws Exception::IO // Closes this EndpointChannel, without tracking the closure in analytics. - virtual void Close() = 0; // Closes this EndpointChannel and records the closure with the given reason. @@ -60,8 +50,7 @@ class EndpointChannel { // and safe disconnection result. virtual void Close( location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result) = 0; + nearby::analytics::SafeDisconnectionResult result) = 0; // True if the EndpointChannel is currently closed. virtual bool IsClosed() const = 0; @@ -150,7 +139,6 @@ inline bool operator!=(const EndpointChannel& lhs, const EndpointChannel& rhs) { return !(lhs == rhs); } -} // namespace connections -} // namespace nearby +} // namespace nearby::connections #endif // CORE_INTERNAL_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/endpoint_channel_manager.cc b/connections/implementation/endpoint_channel_manager.cc index b093b6f3..ab2af35d 100644 --- a/connections/implementation/endpoint_channel_manager.cc +++ b/connections/implementation/endpoint_channel_manager.cc @@ -29,10 +29,7 @@ #include "internal/platform/mutex.h" #include "internal/platform/mutex_lock.h" -namespace nearby { -namespace connections { -using ::location::nearby::analytics::proto::ConnectionsLog; - +namespace nearby::connections { namespace { const absl::Duration kDataTransferDelay = absl::Milliseconds(500); } @@ -46,7 +43,7 @@ EndpointChannelManager::~EndpointChannelManager() { void EndpointChannelManager::RegisterChannelForEndpoint( ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel) { + std::shared_ptr channel) { MutexLock lock(&mutex_); LOG(INFO) << "EndpointChannelManager registered channel of type " @@ -59,7 +56,7 @@ void EndpointChannelManager::RegisterChannelForEndpoint( void EndpointChannelManager::ReplaceChannelForEndpoint( ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel, bool enable_encryption) { + std::shared_ptr channel, bool enable_encryption) { MutexLock lock(&mutex_); if (client->IsSafeToDisconnectEnabled(endpoint_id) && channel_state_.IsWaitingForSafeToDisconnectTimeout(endpoint_id)) { @@ -106,7 +103,7 @@ std::shared_ptr EndpointChannelManager::GetChannelForEndpoint( void EndpointChannelManager::SetActiveEndpointChannel( ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel, bool enable_encryption) { + std::shared_ptr channel, bool enable_encryption) { // Update the channel first, then encrypt this new channel, if // crypto context is present. channel->SetAnalyticsRecorder(&client->GetAnalyticsRecorder(), endpoint_id); @@ -183,13 +180,13 @@ void EndpointChannelManager::ChannelState::DestroyAll() { for (auto& item : endpoints_) { RemoveEndpoint(item.first, DisconnectionReason::SHUTDOWN, /* safe_to_disconnect_enabled */ false, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); } endpoints_.clear(); } void EndpointChannelManager::ChannelState::UpdateChannelForEndpoint( - const std::string& endpoint_id, std::unique_ptr channel) { + const std::string& endpoint_id, std::shared_ptr channel) { // Create EndpointData instance, if necessary, and populate channel. endpoints_[endpoint_id].channel = std::move(channel); } @@ -365,5 +362,4 @@ bool EndpointChannelManager::UnregisterChannelForEndpoint( return true; } -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/endpoint_channel_manager.h b/connections/implementation/endpoint_channel_manager.h index cbc5556a..47878023 100644 --- a/connections/implementation/endpoint_channel_manager.h +++ b/connections/implementation/endpoint_channel_manager.h @@ -21,18 +21,16 @@ #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/time/time.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "internal/platform/mutex.h" -#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" -namespace nearby { -namespace connections { +namespace nearby::connections { using DisconnectionReason = ::location::nearby::proto::connections::DisconnectionReason; -using SafeDisconnectionResult = ::location::nearby::analytics::proto:: - ConnectionsLog::EstablishedConnection::SafeDisconnectionResult; +using SafeDisconnectionResult = nearby::analytics::SafeDisconnectionResult; // NOTE(std::string): // All the strings in internal class public interfaces should be exchanged as @@ -59,7 +57,7 @@ class EndpointChannelManager final { // be closed before continuing the registration. void RegisterChannelForEndpoint(ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel) + std::shared_ptr channel) ABSL_LOCKS_EXCLUDED(mutex_); // Replaces the EndpointChannel to be associated with an endpoint from here on @@ -67,7 +65,7 @@ class EndpointChannelManager final { // to the newly-provided EndpointChannel. void ReplaceChannelForEndpoint(ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel, + std::shared_ptr channel, bool enable_encryption) ABSL_LOCKS_EXCLUDED(mutex_); @@ -168,7 +166,7 @@ class EndpointChannelManager final { // Stores a new EndpointChannel for the endpoint. // Prevoius one is destroyed, if it existed. void UpdateChannelForEndpoint(const std::string& endpoint_id, - std::unique_ptr channel); + std::shared_ptr channel); // Stores a new EncryptionContext for the endpoint. // Prevoius one is destroyed, if it existed. @@ -207,7 +205,7 @@ class EndpointChannelManager final { void SetActiveEndpointChannel(ClientProxy* client, const std::string& endpoint_id, - std::unique_ptr channel, + std::shared_ptr channel, bool enable_encryption) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); @@ -215,7 +213,6 @@ class EndpointChannelManager final { ChannelState channel_state_; }; -} // namespace connections -} // namespace nearby +} // namespace nearby::connections #endif // CORE_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_ diff --git a/connections/implementation/endpoint_channel_manager_test.cc b/connections/implementation/endpoint_channel_manager_test.cc index 23f61bd4..0bdbb6d1 100644 --- a/connections/implementation/endpoint_channel_manager_test.cc +++ b/connections/implementation/endpoint_channel_manager_test.cc @@ -27,6 +27,7 @@ #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/base_endpoint_channel.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/encryption_runner.h" @@ -39,16 +40,14 @@ #include "internal/platform/multi_thread_executor.h" #include "internal/platform/output_stream.h" #include "internal/platform/pipe.h" -#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" -namespace nearby { -namespace connections { +namespace nearby::connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::proto::connections::DisconnectionReason; using ::location::nearby::proto::connections::Medium; +using ::nearby::analytics::SafeDisconnectionResult; using EncryptionContext = BaseEndpointChannel::EncryptionContext; constexpr size_t kChunkSize = 64 * 1024; @@ -110,8 +109,8 @@ std::function MakeDataMonitor(absl::string_view label, std::pair, std::unique_ptr> -DoDhKeyExchange(BaseEndpointChannel* channel_a, - BaseEndpointChannel* channel_b) { +DoDhKeyExchange(std::shared_ptr channel_a, + std::shared_ptr channel_b) { std::unique_ptr context_a; std::unique_ptr context_b; EncryptionRunner crypto_a; @@ -136,8 +135,7 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a, latch.CountDown(); }, .on_failure_cb = - [&latch](const std::string& endpoint_id, - EndpointChannel* channel) { + [&latch](const std::string& endpoint_id) { LOG(INFO) << "client-A side key negotiation failed"; latch.CountDown(); }, @@ -159,8 +157,7 @@ DoDhKeyExchange(BaseEndpointChannel* channel_a, latch.CountDown(); }, .on_failure_cb = - [&latch](const std::string& endpoint_id, - EndpointChannel* channel) { + [&latch](const std::string& endpoint_id) { LOG(INFO) << "client-B side key negotiation failed"; latch.CountDown(); }, @@ -185,9 +182,9 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { // to server "b". auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes // to server "a". - auto channel_a = std::make_unique(server_a.first.get(), + auto channel_a = std::make_shared(server_a.first.get(), client_a.second.get()); - auto channel_b = std::make_unique(server_b.first.get(), + auto channel_b = std::make_shared(server_b.first.get(), client_b.second.get()); auto channel_a_raw = channel_a.get(); auto channel_b_raw = channel_b.get(); @@ -208,7 +205,7 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { MakeDataMonitor(kMonitorB, &capture_b, &mutex))); // Run DH key exchange; setup encryption contexts for channels. - auto context = DoDhKeyExchange(channel_a.get(), channel_b.get()); + auto context = DoDhKeyExchange(channel_a, channel_b); ASSERT_NE(context.first, nullptr); ASSERT_NE(context.second, nullptr); @@ -227,12 +224,12 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { EXPECT_EQ(channel_a_raw->GetType(), "ENCRYPTED_BLUETOOTH"); EXPECT_EQ(channel_b_raw->GetType(), "ENCRYPTED_BLUETOOTH"); - ByteArray tx_message{"data message"}; + absl::string_view tx_message = "data message"; channel_a_raw->Write(tx_message); ByteArray rx_message = std::move(channel_b_raw->Read().result()); // Verify expectations. - EXPECT_EQ(rx_message, tx_message); + EXPECT_EQ(rx_message.AsStringView(), tx_message); { absl::MutexLock lock(mutex); std::string message{tx_message}; @@ -245,10 +242,10 @@ TEST(BaseEndpointChannelManagerTest, RegisterChannelEncryptedReadwrite) { channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION); ecm_a.UnregisterChannelForEndpoint( std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); ecm_b.UnregisterChannelForEndpoint( std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); } TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { @@ -266,9 +263,9 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { // to server "b". auto server_b = CreatePipe(); // Data pump "b" reads from client "b", writes // to server "a". - auto channel_a = std::make_unique(server_a.first.get(), + auto channel_a = std::make_shared(server_a.first.get(), client_a.second.get()); - auto channel_b = std::make_unique(server_b.first.get(), + auto channel_b = std::make_shared(server_b.first.get(), client_b.second.get()); auto channel_a_raw = channel_a.get(); auto channel_b_raw = channel_b.get(); @@ -289,7 +286,7 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { MakeDataMonitor(kMonitorB, &capture_b, &mutex))); // Run DH key exchange; setup encryption contexts for channels. - auto context = DoDhKeyExchange(channel_a.get(), channel_b.get()); + auto context = DoDhKeyExchange(channel_a, channel_b); ASSERT_NE(context.first, nullptr); ASSERT_NE(context.second, nullptr); @@ -313,12 +310,11 @@ TEST(BaseEndpointChannelManagerTest, ReplaceChannelNoEncrypted) { channel_b_raw->Close(DisconnectionReason::REMOTE_DISCONNECTION); ecm_a.UnregisterChannelForEndpoint( std::string(kEndpointId), DisconnectionReason::LOCAL_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); ecm_b.UnregisterChannelForEndpoint( std::string(kEndpointId), DisconnectionReason::REMOTE_DISCONNECTION, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); } } // namespace -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/endpoint_manager.cc b/connections/implementation/endpoint_manager.cc index ecde9b08..31b4454b 100644 --- a/connections/implementation/endpoint_manager.cc +++ b/connections/implementation/endpoint_manager.cc @@ -24,8 +24,7 @@ #include "absl/functional/any_invocable.h" #include "absl/time/time.h" #include "connections/connection_options.h" -#include "connections/implementation/analytics/packet_meta_data.h" -#include "connections/implementation/analytics/throughput_recorder.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/endpoint_channel_manager.h" @@ -34,7 +33,6 @@ #include "connections/implementation/service_id_constants.h" #include "connections/listeners.h" #include "connections/medium_selector.h" -#include "connections/payload_type.h" #include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" @@ -45,20 +43,17 @@ #include "internal/platform/mutex_lock.h" #include "internal/platform/runnable.h" #include "internal/platform/single_thread_executor.h" -#include "internal/proto/analytics/connections_log.pb.h" #include "proto/connections_enums.pb.h" -namespace nearby { -namespace connections { +namespace nearby::connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::KeepAliveFrame; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::PayloadTransferFrame; using ::location::nearby::connections::V1Frame; using ::location::nearby::proto::connections::DisconnectionReason; -using ::nearby::analytics::PacketMetaData; +using ::nearby::analytics::SafeDisconnectionResult; // We set this to 11s to provide sufficient time for an in-progress WebRTC // bandwidth upgrade to resolve. This is chosen to be slightly longer than the @@ -207,7 +202,7 @@ ExceptionOr EndpointManager::TryDecryptFrame( if (decrypted.ok()) { VLOG(1) << "Message decrypted after " << SystemClock::ElapsedRealtime() - start_time; - return parser::FromBytes(decrypted.result()); + return parser::FromBytes(decrypted.result().AsStringView()); } if (decrypted.exception() == Exception::kExecution) { return decrypted.exception(); @@ -235,8 +230,7 @@ ExceptionOr EndpointManager::HandleData( // a replacement for this endpoint since we last checked with the // EndpointChannelManager. while (true) { - PacketMetaData packet_meta_data; - ExceptionOr bytes = endpoint_channel->Read(packet_meta_data); + ExceptionOr bytes = endpoint_channel->Read(); if (!bytes.ok()) { LOG(INFO) << "Stop reading on read-time exception: " << bytes.exception(); // Treat kNoData as kIo. @@ -245,7 +239,8 @@ ExceptionOr EndpointManager::HandleData( } return ExceptionOr(bytes.exception()); } - ExceptionOr wrapped_frame = parser::FromBytes(bytes.result()); + ExceptionOr wrapped_frame = + parser::FromBytes(bytes.result().AsStringView()); if (!wrapped_frame.ok() && try_decrypting) { // Workaround for a race condition where the remote party has sent an // encrypted message but our end was still configured as unencrypted when @@ -316,8 +311,7 @@ ExceptionOr EndpointManager::HandleData( } frame_processor->OnIncomingFrame(frame, endpoint_id, client, - endpoint_channel->GetMedium(), - packet_meta_data); + endpoint_channel->GetMedium()); } } @@ -456,7 +450,6 @@ EndpointManager::~EndpointManager() { MutexLock lock(&mutex_); is_shutdown_ = true; } - analytics::ThroughputRecorderContainer::GetInstance().Shutdown(); CountDownLatch latch(1); RunOnEndpointManagerThread("bring-down-endpoints", [this, &latch]() { LOG(INFO) << "Bringing down endpoints"; @@ -539,103 +532,94 @@ void EndpointManager::RegisterEndpoint( ClientProxy* client, const std::string& endpoint_id, const ConnectionResponseInfo& info, const ConnectionOptions& connection_options, - std::unique_ptr channel, + std::shared_ptr channel, const ConnectionListener& listener, const std::string& connection_token) { CountDownLatch latch(1); - // NOTE (unique_ptr<> capture): - // std::unique_ptr<> is not copyable, so we can not pass it to - // lambda capture, because lambda eventually is converted to - // std::function<>. Instead, we release() a pointer, and pass a raw pointer, - // which is copyalbe. We ignore the risk of job not scheduled (and an - // associated risk of memory leak), because this may only happen during - // service shutdown. - RunOnEndpointManagerThread( - "register-endpoint", - [this, client, channel = channel.release(), &endpoint_id, &info, - &connection_options, &listener, &connection_token, &latch]() { - if (endpoints_.contains(endpoint_id)) { - LOG(WARNING) << "Registering duplicate endpoint " << endpoint_id; - // We must remove old endpoint state before registering a new one - // for the same endpoint_id. - RemoveEndpointState(endpoint_id); - } + RunOnEndpointManagerThread("register-endpoint", [this, client, channel, + &endpoint_id, &info, + &connection_options, + &listener, &connection_token, + &latch]() { + if (endpoints_.contains(endpoint_id)) { + LOG(WARNING) << "Registering duplicate endpoint " << endpoint_id; + // We must remove old endpoint state before registering a new one + // for the same endpoint_id. + RemoveEndpointState(endpoint_id); + } - absl::Duration keep_alive_interval = - absl::Milliseconds(connection_options.keep_alive_interval_millis); - absl::Duration keep_alive_timeout = - absl::Milliseconds(connection_options.keep_alive_timeout_millis); - LOG(INFO) << "Registering endpoint " << endpoint_id << " for client " - << client->GetClientId() - << " with keep-alive frame as interval=" - << absl::FormatDuration(keep_alive_interval) - << ", timeout=" << absl::FormatDuration(keep_alive_timeout); + absl::Duration keep_alive_interval = + absl::Milliseconds(connection_options.keep_alive_interval_millis); + absl::Duration keep_alive_timeout = + absl::Milliseconds(connection_options.keep_alive_timeout_millis); + LOG(INFO) << "Registering endpoint " << endpoint_id << " for client " + << client->GetClientId() << " with keep-alive frame as interval=" + << absl::FormatDuration(keep_alive_interval) + << ", timeout=" << absl::FormatDuration(keep_alive_timeout); - // Pass ownership of channel to EndpointChannelManager - LOG(INFO) << "Registering endpoint with channel manager: endpoint " - << endpoint_id; - channel_manager_->RegisterChannelForEndpoint( - client, endpoint_id, std::unique_ptr(channel)); + // Pass ownership of channel to EndpointChannelManager + LOG(INFO) << "Registering endpoint with channel manager: endpoint " + << endpoint_id; + channel_manager_->RegisterChannelForEndpoint(client, endpoint_id, channel); - EndpointState& endpoint_state = - endpoints_ - .emplace(endpoint_id, - EndpointState(endpoint_id, channel_manager_)) - .first->second; + EndpointState& endpoint_state = + endpoints_ + .emplace(endpoint_id, EndpointState(endpoint_id, channel_manager_)) + .first->second; - LOG(INFO) << "Starting workers: endpoint " << endpoint_id; - // For every endpoint, there's normally only one Read handler instance - // running on a dedicated thread. This instance reads data from the - // endpoint and delegates incoming frames to various FrameProcessors. - // Once the frame has been properly handled, it starts reading again - // for the next frame. If the handler fails its read and no other - // EndpointChannels are available for this endpoint, a disconnection - // will be initiated. - endpoint_state.StartEndpointReader([this, client, endpoint_id]() { + LOG(INFO) << "Starting workers: endpoint " << endpoint_id; + // For every endpoint, there's normally only one Read handler instance + // running on a dedicated thread. This instance reads data from the + // endpoint and delegates incoming frames to various FrameProcessors. + // Once the frame has been properly handled, it starts reading again + // for the next frame. If the handler fails its read and no other + // EndpointChannels are available for this endpoint, a disconnection + // will be initiated. + endpoint_state.StartEndpointReader([this, client, endpoint_id]() { + EndpointChannelLoopRunnable( + "Read", client, endpoint_id, + [this, client, endpoint_id](EndpointChannel* channel) { + return HandleData(endpoint_id, client, channel); + }); + }); + + // For every endpoint, there's only one KeepAliveManager instance + // running on a dedicated thread. This instance will periodically send + // out a ping* to the endpoint while listening for an incoming pong**. + // If it fails to send the ping, or if no pong is heard within + // keep_alive_timeout, it initiates a disconnection. + // + // (*) Bluetooth requires a constant outgoing stream of messages. If + // there's silence, Android will break the socket. This is why we + // ping. + // (**) Wifi Hotspots can fail to notice a connection has been lost, + // and they will happily keep writing to /dev/null. This is why we + // listen for the pong. + VLOG(1) << "EndpointManager enabling KeepAlive for endpoint " + << endpoint_id; + endpoint_state.StartEndpointKeepAliveManager( + [this, client, endpoint_id, keep_alive_interval, keep_alive_timeout]( + Mutex* keep_alive_waiter_mutex, + ConditionVariable* keep_alive_waiter) { EndpointChannelLoopRunnable( - "Read", client, endpoint_id, - [this, client, endpoint_id](EndpointChannel* channel) { - return HandleData(endpoint_id, client, channel); + "KeepAliveManager", client, endpoint_id, + [this, keep_alive_interval, keep_alive_timeout, + keep_alive_waiter_mutex, + keep_alive_waiter](EndpointChannel* channel) { + return HandleKeepAlive( + channel, keep_alive_interval, keep_alive_timeout, + keep_alive_waiter_mutex, keep_alive_waiter); }); }); + LOG(INFO) << "Registering endpoint " << endpoint_id + << ", workers started and notifying client."; - // For every endpoint, there's only one KeepAliveManager instance - // running on a dedicated thread. This instance will periodically send - // out a ping* to the endpoint while listening for an incoming pong**. - // If it fails to send the ping, or if no pong is heard within - // keep_alive_timeout, it initiates a disconnection. - // - // (*) Bluetooth requires a constant outgoing stream of messages. If - // there's silence, Android will break the socket. This is why we - // ping. - // (**) Wifi Hotspots can fail to notice a connection has been lost, - // and they will happily keep writing to /dev/null. This is why we - // listen for the pong. - VLOG(1) << "EndpointManager enabling KeepAlive for endpoint " - << endpoint_id; - endpoint_state.StartEndpointKeepAliveManager( - [this, client, endpoint_id, keep_alive_interval, - keep_alive_timeout](Mutex* keep_alive_waiter_mutex, - ConditionVariable* keep_alive_waiter) { - EndpointChannelLoopRunnable( - "KeepAliveManager", client, endpoint_id, - [this, keep_alive_interval, keep_alive_timeout, - keep_alive_waiter_mutex, - keep_alive_waiter](EndpointChannel* channel) { - return HandleKeepAlive( - channel, keep_alive_interval, keep_alive_timeout, - keep_alive_waiter_mutex, keep_alive_waiter); - }); - }); - LOG(INFO) << "Registering endpoint " << endpoint_id - << ", workers started and notifying client."; - - // It's now time to let the client know of this new connection so that - // they can accept or reject it. - client->OnConnectionInitiated(endpoint_id, info, connection_options, - listener, connection_token); - latch.CountDown(); - }); + // It's now time to let the client know of this new connection so that + // they can accept or reject it. + client->OnConnectionInitiated(endpoint_id, info, connection_options, + listener, connection_token); + latch.CountDown(); + }); latch.Await(); } @@ -666,17 +650,15 @@ int EndpointManager::GetMaxTransmitPacketSize(const std::string& endpoint_id) { std::vector EndpointManager::SendPayloadChunk( const PayloadTransferFrame::PayloadHeader& payload_header, const PayloadTransferFrame::PayloadChunk& payload_chunk, - const std::vector& endpoint_ids, - PacketMetaData& packet_meta_data) { - ByteArray bytes = + const std::vector& endpoint_ids) { + std::string bytes = parser::ForDataPayloadTransfer(payload_header, payload_chunk); return SendTransferFrameBytes( endpoint_ids, bytes, payload_header.id(), /*offset=*/payload_chunk.offset(), /*packet_type=*/ - PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::DATA), - packet_meta_data); + PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::DATA)); } // Designed to run asynchronously. It is called from IO thread pools, and @@ -722,7 +704,7 @@ void EndpointManager::DiscardEndpoint(ClientProxy* client, // of `serial_executor_` and will still have access to a valid // `is_shutdown_`. // - // TODO(b/280653613): Develop a more robost solution to prevent + // TODO(b/280653613): Develop a more robust solution to prevent // accessing an already destroyed `ClientProxy` during destruction. { MutexLock lock(&mutex_); @@ -743,15 +725,13 @@ std::vector EndpointManager::SendControlMessage( const PayloadTransferFrame::PayloadHeader& header, const PayloadTransferFrame::ControlMessage& control, const std::vector& endpoint_ids) { - ByteArray bytes = parser::ForControlPayloadTransfer(header, control); - PacketMetaData packet_meta_data; + std::string bytes = parser::ForControlPayloadTransfer(header, control); return SendTransferFrameBytes( endpoint_ids, bytes, header.id(), /*offset=*/control.offset(), /*packet_type=*/ - PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::CONTROL), - packet_meta_data); + PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::CONTROL)); } // @EndpointManagerThread @@ -762,7 +742,7 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client, << ", reason: " << reason; SafeDisconnectionResult safe_disconnect_result = - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION; + SafeDisconnectionResult::kSafeDisconnection; // Grab the service ID before we destroy the channel. EndpointChannel* channel = @@ -775,17 +755,15 @@ void EndpointManager::RemoveEndpoint(ClientProxy* client, bool is_safe_disconnection = ApplySafeToDisconnect(endpoint_id, channel, reason); safe_disconnect_result = - is_safe_disconnection - ? ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION - : ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION; + is_safe_disconnection ? SafeDisconnectionResult::kSafeDisconnection + : SafeDisconnectionResult::kUnsafeDisconnection; LOG(INFO) << "[safe-to-disconnect] safe_disconnect_result:" - << (safe_disconnect_result ? "true" : "false"); + << (safe_disconnect_result == + SafeDisconnectionResult::kSafeDisconnection + ? "true" + : "false"); } } - if (safe_disconnect_result == - ConnectionsLog::EstablishedConnection::UNSAFE_DISCONNECTION) { - // TODO(b/297259496): Autoreconnect - } // Unregistering from channel_manager_ will also serve to terminate // the dedicated handler and KeepAlive threads we started when we registered @@ -924,21 +902,19 @@ CountDownLatch EndpointManager::NotifyFrameProcessorsOnEndpointDisconnect( std::vector EndpointManager::SendPayloadAck( std::int64_t payload_id, const std::vector& endpoint_ids) { - ByteArray bytes = parser::ForPayloadAckPayloadTransfer(payload_id); - PacketMetaData packet_meta_data; + std::string bytes = parser::ForPayloadAckPayloadTransfer(payload_id); return SendTransferFrameBytes( endpoint_ids, bytes, payload_id, /* offset= */ -1, /*packet_type=*/ - PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::PAYLOAD_ACK), - packet_meta_data); + PayloadTransferFrame::PacketType_Name(PayloadTransferFrame::PAYLOAD_ACK)); } std::vector EndpointManager::SendTransferFrameBytes( - const std::vector& endpoint_ids, const ByteArray& bytes, + const std::vector& endpoint_ids, const std::string& bytes, std::int64_t payload_id, std::int64_t offset, - const std::string& packet_type, PacketMetaData& packet_meta_data) { + const std::string& packet_type) { std::vector failed_endpoint_ids; for (const std::string& endpoint_id : endpoint_ids) { std::shared_ptr channel = @@ -957,16 +933,12 @@ std::vector EndpointManager::SendTransferFrameBytes( continue; } - Exception write_exception = - channel->Write(bytes.AsStringView(), packet_meta_data); + Exception write_exception = channel->Write(bytes); if (!write_exception.Ok()) { failed_endpoint_ids.push_back(endpoint_id); LOG(INFO) << "Failed to send packet; endpoint_id=" << endpoint_id; continue; } - analytics::ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(payload_id, PayloadDirection::OUTGOING_PAYLOAD) - ->OnFrameSent(channel->GetMedium(), packet_meta_data); } return failed_endpoint_ids; @@ -982,7 +954,7 @@ EndpointManager::EndpointState::~EndpointState() { VLOG(1) << "EndpointState destructor " << endpoint_id_; channel_manager_->UnregisterChannelForEndpoint( endpoint_id_, DisconnectionReason::SHUTDOWN, - ConnectionsLog::EstablishedConnection::SAFE_DISCONNECTION); + SafeDisconnectionResult::kSafeDisconnection); } // Make sure the KeepAlive thread isn't blocking shutdown. @@ -1011,5 +983,4 @@ void EndpointManager::RunOnEndpointManagerThread(const std::string& name, serial_executor_->Execute(name, std::move(runnable)); } -} // namespace connections -} // namespace nearby +} // namespace nearby::connections diff --git a/connections/implementation/endpoint_manager.h b/connections/implementation/endpoint_manager.h index 8b2b0b81..2250a958 100644 --- a/connections/implementation/endpoint_manager.h +++ b/connections/implementation/endpoint_manager.h @@ -16,7 +16,6 @@ #define CORE_INTERNAL_ENDPOINT_MANAGER_H_ #include -#include #include #include #include @@ -24,10 +23,9 @@ #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/time/time.h" -#include "connections/implementation/analytics/packet_meta_data.h" +#include "connections/connection_options.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/endpoint_channel_manager.h" @@ -36,6 +34,8 @@ #include "internal/platform/byte_array.h" #include "internal/platform/condition_variable.h" #include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" +#include "internal/platform/mutex.h" #include "internal/platform/runnable.h" #include "internal/platform/single_thread_executor.h" @@ -79,8 +79,7 @@ class EndpointManager { virtual void OnIncomingFrame( location::nearby::connections::OfflineFrame& offline_frame, const std::string& from_endpoint_id, ClientProxy* to_client, - location::nearby::proto::connections::Medium current_medium, - analytics::PacketMetaData& packet_meta_data) = 0; + location::nearby::proto::connections::Medium current_medium) = 0; // Implementations must call barrier.CountDown() once // they're done. This parallelizes the disconnection event across all frame @@ -114,7 +113,7 @@ class EndpointManager { void RegisterEndpoint(ClientProxy* client, const std::string& endpoint_id, const ConnectionResponseInfo& info, const ConnectionOptions& connection_options, - std::unique_ptr channel, + std::shared_ptr channel, const ConnectionListener& listener, const std::string& connection_token); // Called when a client explicitly asks to disconnect from this endpoint. In @@ -133,8 +132,7 @@ class EndpointManager { payload_header, const location::nearby::connections::PayloadTransferFrame::PayloadChunk& payload_chunk, - const std::vector& endpoint_ids, - analytics::PacketMetaData& packet_meta_data); + const std::vector& endpoint_ids); std::vector SendControlMessage( const location::nearby::connections::PayloadTransferFrame::PayloadHeader& payload_header, @@ -283,9 +281,8 @@ class EndpointManager { std::vector SendTransferFrameBytes( const std::vector& endpoint_ids, - const ByteArray& payload_transfer_frame_bytes, std::int64_t payload_id, - std::int64_t offset, const std::string& packet_type, - analytics::PacketMetaData& packet_meta_data); + const std::string& payload_transfer_frame_bytes, std::int64_t payload_id, + std::int64_t offset, const std::string& packet_type); // Executes all jobs sequentially, on a serial_executor_. void RunOnEndpointManagerThread(const std::string& name, Runnable runnable); diff --git a/connections/implementation/endpoint_manager_test.cc b/connections/implementation/endpoint_manager_test.cc index 0f906e3c..70a85949 100644 --- a/connections/implementation/endpoint_manager_test.cc +++ b/connections/implementation/endpoint_manager_test.cc @@ -29,11 +29,10 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "connections/connection_options.h" -#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/client_proxy.h" -#include "connections/implementation/endpoint_channel.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "connections/implementation/mock_endpoint_channel.h" #include "connections/implementation/offline_frames.h" #include "connections/listeners.h" #include "connections/status.h" @@ -63,68 +62,12 @@ using ::testing::MockFunction; using ::testing::Return; using ::testing::StrictMock; -class MockEndpointChannel : public EndpointChannel { - public: - MOCK_METHOD(ExceptionOr, Read, (), (override)); - MOCK_METHOD(ExceptionOr, Read, (PacketMetaData & packet_meta_data), - (override)); - MOCK_METHOD(Exception, Write, (const ByteArray& data), (override)); - MOCK_METHOD(Exception, Write, - (absl::string_view data, PacketMetaData& packet_meta_data), - (override)); - MOCK_METHOD(void, Close, (), (override)); - MOCK_METHOD(void, Close, (DisconnectionReason reason), (override)); - MOCK_METHOD(void, Close, - (DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result), - (override)); - MOCK_METHOD(location::nearby::proto::connections::ConnectionTechnology, - GetTechnology, (), (const, override)); - MOCK_METHOD(location::nearby::proto::connections::ConnectionBand, GetBand, (), - (const, override)); - MOCK_METHOD(int, GetFrequency, (), (const, override)); - MOCK_METHOD(int, GetTryCount, (), (const, override)); - MOCK_METHOD(std::string, GetType, (), (const, override)); - MOCK_METHOD(std::string, GetServiceId, (), (const, override)); - MOCK_METHOD(std::string, GetName, (), (const, override)); - MOCK_METHOD(Medium, GetMedium, (), (const, override)); - MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const, override)); - MOCK_METHOD(void, EnableEncryption, - (std::shared_ptr context), (override)); - MOCK_METHOD(void, DisableEncryption, (), (override)); - MOCK_METHOD(bool, IsPaused, (), (const, override)); - MOCK_METHOD(bool, IsEncrypted, (), (override)); - MOCK_METHOD(ExceptionOr, TryDecrypt, (const ByteArray& data), - (override)); - MOCK_METHOD(void, Pause, (), (override)); - MOCK_METHOD(void, Resume, (), (override)); - MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const, override)); - MOCK_METHOD(absl::Time, GetLastWriteTimestamp, (), (const, override)); - MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override)); - MOCK_METHOD(void, SetAnalyticsRecorder, - (analytics::AnalyticsRecorder*, const std::string&), (override)); - - bool IsClosed() const override { - absl::MutexLock lock(mutex_); - return closed_; - } - void DoClose() { - absl::MutexLock lock(mutex_); - closed_ = true; - } - - private: - mutable absl::Mutex mutex_; - bool closed_ = false; -}; - class MockFrameProcessor : public EndpointManager::FrameProcessor { public: MOCK_METHOD(void, OnIncomingFrame, (OfflineFrame & offline_frame, const std::string& from_endpoint_id, ClientProxy* to_client, - Medium current_medium, PacketMetaData& packet_meta_data), + Medium current_medium), (override)); MOCK_METHOD(void, OnEndpointDisconnect, @@ -136,16 +79,13 @@ class MockFrameProcessor : public EndpointManager::FrameProcessor { class SetSafeToDisconnect { public: - SetSafeToDisconnect(bool safe_to_disconnect, bool auto_reconnect, + SetSafeToDisconnect(bool safe_to_disconnect, bool payload_received_ack, std::int32_t safe_to_disconnect_version) { NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnableSafeToDisconnect, safe_to_disconnect); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableAutoReconnect, - auto_reconnect); NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnablePayloadReceivedAck, @@ -187,7 +127,7 @@ class EndpointManagerTest : public ::testing::Test { EXPECT_TRUE(done.Await(absl::Milliseconds(1000)).result()); } } - SetSafeToDisconnect set_safe_to_disconnect_{true, false, true, 5}; + SetSafeToDisconnect set_safe_to_disconnect_{true, true, 5}; std::unique_ptr client_ = std::make_unique(); ConnectionOptions connection_options_{ .keep_alive_interval_millis = 5000, @@ -280,11 +220,12 @@ TEST_F(EndpointManagerTest, RegisterFrameProcessorWorks) { 0 /*keep_alive_interval_millis*/, 0 /*keep_alive_timeout_millis*/}; - auto read_data = parser::ForConnectionRequestConnections({}, connection_info); + std::string read_data = + parser::ForConnectionRequestConnections({}, connection_info); EXPECT_CALL(*connect_request, OnIncomingFrame); EXPECT_CALL(*connect_request, OnEndpointDisconnect); - EXPECT_CALL(*endpoint_channel, Read(_)) - .WillOnce(Return(ExceptionOr(read_data))) + EXPECT_CALL(*endpoint_channel, Read()) + .WillOnce(Return(ExceptionOr(ByteArray(read_data)))) .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); EXPECT_CALL(*endpoint_channel, Write(_)) .WillRepeatedly(Return(Exception{Exception::kSuccess})); @@ -321,6 +262,8 @@ TEST_F(EndpointManagerTest, UnregisterFrameProcessorWorks) { TEST_F(EndpointManagerTest, SendControlMessageAndPayloadAckWorks) { auto endpoint_channel = std::make_unique(); + absl::Mutex close_mutex; + bool closed = false; PayloadTransferFrame::PayloadHeader header; PayloadTransferFrame::ControlMessage control; header.set_id(12345); @@ -329,22 +272,24 @@ TEST_F(EndpointManagerTest, SendControlMessageAndPayloadAckWorks) { control.set_offset(150); control.set_event(PayloadTransferFrame::ControlMessage::PAYLOAD_CANCELED); - ON_CALL(*endpoint_channel, Read(_)) - .WillByDefault([channel = endpoint_channel.get()]() { - if (channel->IsClosed()) return ExceptionOr(Exception::kIo); + ON_CALL(*endpoint_channel, Read()) + .WillByDefault([&, channel = endpoint_channel.get()]() { + absl::MutexLock lock(close_mutex); + if (closed) return ExceptionOr(Exception::kIo); LOG(INFO) << "Simulate read delay: wait"; absl::SleepFor(absl::Milliseconds(100)); LOG(INFO) << "Simulate read delay: done"; - if (channel->IsClosed()) return ExceptionOr(Exception::kIo); + if (closed) return ExceptionOr(Exception::kIo); return ExceptionOr(ByteArray{}); }); ON_CALL(*endpoint_channel, Close(_)) .WillByDefault( - [channel = endpoint_channel.get()](DisconnectionReason reason) { - channel->DoClose(); + [&, channel = endpoint_channel.get()](DisconnectionReason reason) { + absl::MutexLock lock(close_mutex); + closed = true; LOG(INFO) << "Channel closed"; }); - EXPECT_CALL(*endpoint_channel, Write(_, _)) + EXPECT_CALL(*endpoint_channel, Write(_)) .WillRepeatedly(Return(Exception{Exception::kSuccess})); RegisterEndpoint(std::move(endpoint_channel), false); @@ -361,7 +306,7 @@ TEST_F(EndpointManagerTest, SendControlMessageAndPayloadAckWorks) { TEST_F(EndpointManagerTest, SingleReadOnReadError) { auto endpoint_channel = std::make_unique(); - EXPECT_CALL(*endpoint_channel, Read(_)) + EXPECT_CALL(*endpoint_channel, Read()) .WillOnce( Return(ExceptionOr(Exception::kInvalidProtocolBuffer))); EXPECT_CALL(*endpoint_channel, Write(_)) @@ -379,7 +324,7 @@ TEST_F(EndpointManagerTest, ReadInvalidUnencryptedPayloadIgnoresFrame) { CountDownLatch latch(1); const ByteArray payload("not a valid frame"); auto endpoint_channel = std::make_unique(); - EXPECT_CALL(*endpoint_channel, Read(_)) + EXPECT_CALL(*endpoint_channel, Read()) .WillOnce(Return(ExceptionOr(payload))) .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); EXPECT_CALL(*endpoint_channel, TryDecrypt(Eq(payload))) @@ -403,7 +348,7 @@ class EndpointManagerFuzzTest // too. // 4. Invalid frame is ignored. No bad side effects. auto endpoint_channel = std::make_unique(); - EXPECT_CALL(*endpoint_channel, Read(_)) + EXPECT_CALL(*endpoint_channel, Read()) .WillOnce(Return(ExceptionOr(payload))) .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); EXPECT_CALL(*endpoint_channel, TryDecrypt(Eq(payload))) @@ -419,7 +364,7 @@ class EndpointManagerFuzzTest // 2. EndpointManager receives an invalid encrypted frame. // 3. No calls to TryDecrypt. auto endpoint_channel = std::make_unique(); - EXPECT_CALL(*endpoint_channel, Read(_)) + EXPECT_CALL(*endpoint_channel, Read()) .WillOnce(Return(ExceptionOr(payload))) .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); EXPECT_CALL(*endpoint_channel, IsEncrypted()).WillRepeatedly(Return(true)); @@ -432,7 +377,9 @@ class EndpointManagerFuzzTest auto InvalidPayloadDomain() { return Filter( - [](ByteArray payload) { return !parser::FromBytes(payload).ok(); }, + [](ByteArray payload) { + return !parser::FromBytes(payload.AsStringView()).ok(); + }, Map([](std::string payloadString) { return ByteArray(payloadString); }, String())); } @@ -464,16 +411,16 @@ TEST_F(EndpointManagerTest, TryDecrypt) { std::vector{Medium::BLE} /*supported_mediums*/, 0 /*keep_alive_interval_millis*/, 0 /*keep_alive_timeout_millis*/}; - ByteArray decrypted_data = + std::string decrypted_data = parser::ForConnectionRequestConnections({}, connection_info); EXPECT_CALL(*connect_request, OnIncomingFrame); EXPECT_CALL(*connect_request, OnEndpointDisconnect); - EXPECT_CALL(*endpoint_channel, Read(_)) + EXPECT_CALL(*endpoint_channel, Read()) .WillOnce(Return(ExceptionOr(payload))) .WillRepeatedly(Return(ExceptionOr(Exception::kIo))); EXPECT_CALL(*endpoint_channel, TryDecrypt(Eq(payload))) .WillOnce(Return(ExceptionOr(Exception::kFailed))) - .WillOnce(Return(ExceptionOr(decrypted_data))); + .WillOnce(Return(ExceptionOr(ByteArray(decrypted_data)))); EXPECT_CALL(*endpoint_channel, Write(_)) .WillRepeatedly(Return(Exception{Exception::kSuccess})); em_.RegisterFrameProcessor(V1Frame::CONNECTION_REQUEST, diff --git a/connections/implementation/fake_bwu_handler.h b/connections/implementation/fake_bwu_handler.h index c26a91e6..fd1fb1dc 100644 --- a/connections/implementation/fake_bwu_handler.h +++ b/connections/implementation/fake_bwu_handler.h @@ -87,9 +87,9 @@ class FakeBwuHandler : public BaseBwuHandler { medium_, *handle_initialize_calls_[initialize_call_index].service_id); FakeEndpointChannel* upgraded_channel_raw = upgraded_channel.get(); upgraded_channel->set_read_output( - ExceptionOr(parser::ForBwuIntroduction( + ExceptionOr(ByteArray(parser::ForBwuIntroduction( *handle_initialize_calls_[initialize_call_index].endpoint_id, - false /* supports_disabling_encryption */))); + false /* supports_disabling_encryption */)))); auto connection = std::make_unique(); connection->channel = std::move(upgraded_channel); @@ -133,7 +133,7 @@ class FakeBwuHandler : public BaseBwuHandler { } // BaseBwuHandler: - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final { handle_initialize_calls_.push_back({.client = client, @@ -188,7 +188,7 @@ class FakeBwuHandler : public BaseBwuHandler { case location::nearby::proto::connections::BLE_L2CAP: case location::nearby::proto::connections::USB: case location::nearby::proto::connections::AWDL: - return ByteArray{}; + return {}; } } diff --git a/connections/implementation/fake_endpoint_channel.h b/connections/implementation/fake_endpoint_channel.h index fa1bc3f7..01bb92fe 100644 --- a/connections/implementation/fake_endpoint_channel.h +++ b/connections/implementation/fake_endpoint_channel.h @@ -27,8 +27,7 @@ #include "internal/platform/exception.h" #include "internal/platform/implementation/system_clock.h" -namespace nearby { -namespace connections { +namespace nearby::connections { // An endpoint channel implementation used for testing. The read and write // output can be set. @@ -46,16 +45,7 @@ class FakeEndpointChannel : public EndpointChannel { read_timestamp_ = SystemClock::ElapsedRealtime(); return read_output_; } - ExceptionOr Read(PacketMetaData& packet_meta_data) override { - read_timestamp_ = SystemClock::ElapsedRealtime(); - return read_output_; - } - Exception Write(const ByteArray& data) override { - write_timestamp_ = SystemClock::ElapsedRealtime(); - return write_output_; - } - Exception Write(absl::string_view data, - PacketMetaData& packet_meta_data) override { + Exception Write(absl::string_view data) override { write_timestamp_ = SystemClock::ElapsedRealtime(); return write_output_; } @@ -65,10 +55,8 @@ class FakeEndpointChannel : public EndpointChannel { is_closed_ = true; disconnection_reason_ = reason; } - void Close( - location::nearby::proto::connections::DisconnectionReason reason, - location::nearby::analytics::proto::ConnectionsLog:: - EstablishedConnection::SafeDisconnectionResult result) override { + void Close(location::nearby::proto::connections::DisconnectionReason reason, + nearby::analytics::SafeDisconnectionResult result) override { Close(reason); } bool IsClosed() const override { return is_closed_; } @@ -128,7 +116,6 @@ class FakeEndpointChannel : public EndpointChannel { mutable uint32_t next_keep_alive_seq_no_ = 0; }; -} // namespace connections -} // namespace nearby +} // namespace nearby::connections #endif // NEARBY_CONNECTIONS_IMPLEMENTATION_FAKE_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/flags/nearby_connections_feature_flags.h b/connections/implementation/flags/nearby_connections_feature_flags.h old mode 100644 new mode 100755 index 8dbe6dbc..9b322ee5 --- a/connections/implementation/flags/nearby_connections_feature_flags.h +++ b/connections/implementation/flags/nearby_connections_feature_flags.h @@ -31,15 +31,9 @@ namespace nearby_connections_feature { // The timeout in millis to report peripheral device lost. constexpr auto kBlePeripheralLostTimeoutMillis = flags::Flag(kConfigPackage, "45411439", 12000); -// Disable instant on lost on BLE without extended feature. -constexpr auto kDisableInstantOnLostOnBleWithoutExtended = - flags::Flag(kConfigPackage, "45687098", true); // When true, enable advertising for instant on lost feature. constexpr auto kEnableAdvertisingForInstantOnLost = flags::Flag(kConfigPackage, "45708614", true); -// Enable/Disable auto_reconnect feature. -constexpr auto kEnableAutoReconnect = - flags::Flag(kConfigPackage, "45427690", false); // Enable/Disable AWDL in Nearby connections SDK. constexpr auto kEnableAwdl = flags::Flag(kConfigPackage, "45690762", false); @@ -58,13 +52,6 @@ constexpr auto kEnableDynamicRoleSwitch = // Enable/Disable GATT client disconnection. constexpr auto kEnableGattClientDisconnection = flags::Flag(kConfigPackage, "45698964", false); -// When true, enable instant on lost feature. -// When true, enable multiplexing in NC. -constexpr auto kEnableMultiplex = - flags::Flag(kConfigPackage, "45647946", false); -// Enable/disable multiplex in NC for AWDL. -constexpr auto kEnableMultiplexAwdl = - flags::Flag(kConfigPackage, "45690761", false); // When true, enable multiplexing in NC for Bluetooth. constexpr auto kEnableMultiplexBluetooth = flags::Flag(kConfigPackage, "45676646", false); @@ -83,9 +70,13 @@ constexpr auto kEnablePayloadReceivedAck = // Enable/Disable safe-to-disconnect feature. constexpr auto kEnableSafeToDisconnect = flags::Flag(kConfigPackage, "45425789", false); -// When true, enable scanning for instant on lost feature. -constexpr auto kEnableScanningForInstantOnLost = - flags::Flag(kConfigPackage, "45708613", true); +// Enable/Disable usage of shared CBPeripheralManager for GATT and L2CAP +// servers. +constexpr auto kEnableSharedPeripheralManager = + flags::Flag(kConfigPackage, "45770787", false); +// Enable/Disable single copy read/write for input/output buffers. +constexpr auto kEnableSingleCopy = + flags::Flag(kConfigPackage, "45782646", true); // Stop BLE_V2 scanning when upgrading to WIFI Hotspot or WFD. constexpr auto kEnableStopBleScanningOnWifiUpgrade = flags::Flag(kConfigPackage, "45687902", false); @@ -95,6 +86,9 @@ constexpr auto kEnableWifiDirect = // by default, enable Wi-Fi Hotspot client. constexpr auto kEnableWifiHotspotClient = flags::Flag(kConfigPackage, "45648734", true); +// When true, fix the BleServerSocket deadlock/use-after-free (b/494335036). +constexpr auto kFixBleServerSocketDeadlock = + flags::Flag(kConfigPackage, "45782647", true); // Default max transmit packet size for medium. constexpr auto kMediumDefaultMaxTransmitPacketSize = flags::Flag(kConfigPackage, "45669529", 65536); @@ -105,7 +99,8 @@ constexpr auto kMediumMaxAllowedReadBytes = constexpr auto kRefactorBleL2cap = flags::Flag(kConfigPackage, "45737079", false); // Set the safe-to-disconnect version. -// 0. Disabled all. 1. safe-to-disconnect 2. reserved 3. auto-reconnect +// 0. Disabled all. 1. safe-to-disconnect 2. reserved 3. +// auto-reconnect(deprecated) // 4. auto-resume 5. non-distance-constraint-recovery 6. payload_ack constexpr auto kSafeToDisconnectVersion = flags::Flag(kConfigPackage, "45425841", 0); diff --git a/connections/implementation/fuzzers/BUILD b/connections/implementation/fuzzers/BUILD index 2ef4e0d5..490dac2f 100644 --- a/connections/implementation/fuzzers/BUILD +++ b/connections/implementation/fuzzers/BUILD @@ -24,11 +24,10 @@ cc_test( ], tags = ["componentid:148515"], deps = [ - "//connections/implementation:internal", - "//internal/platform:base", + "//connections/implementation:offline_frames", "//internal/platform/implementation/g3", - "//testing/fuzzing:fuzztest", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings:string_view", "@com_google_googletest//:gtest_main", ], ) diff --git a/connections/implementation/fuzzers/offline_frames_fuzzer.cc b/connections/implementation/fuzzers/offline_frames_fuzzer.cc index 256f112c..5f3aaafe 100644 --- a/connections/implementation/fuzzers/offline_frames_fuzzer.cc +++ b/connections/implementation/fuzzers/offline_frames_fuzzer.cc @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "absl/strings/string_view.h" #include "connections/implementation/offline_frames.h" -#include "internal/platform/byte_array.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - nearby::ByteArray byte_array; - byte_array.SetData(reinterpret_cast(data), size); - + absl::string_view byte_array(reinterpret_cast(data), size); nearby::connections::parser::FromBytes(byte_array); return 0; diff --git a/connections/implementation/mediums/BUILD b/connections/implementation/mediums/BUILD index e12c6e42..d533c0ae 100644 --- a/connections/implementation/mediums/BUILD +++ b/connections/implementation/mediums/BUILD @@ -21,46 +21,75 @@ cc_library( name = "mediums", srcs = [ "awdl.cc", + "awdl_bwu_handler.cc", + "awdl_endpoint_channel.cc", "ble.cc", + "ble_endpoint_channel.cc", + "ble_l2cap_endpoint_channel.cc", + "bluetooth_bwu_handler.cc", "bluetooth_classic.cc", + "bluetooth_endpoint_channel.cc", "bluetooth_radio.cc", "mediums.cc", - "webrtc.cc", - "webrtc_stub.cc", "wifi_direct.cc", + "wifi_direct_bwu_handler.cc", + "wifi_direct_endpoint_channel.cc", "wifi_hotspot.cc", + "wifi_hotspot_bwu_handler.cc", + "wifi_hotspot_endpoint_channel.cc", "wifi_lan.cc", + "wifi_lan_bwu_handler.cc", + "wifi_lan_endpoint_channel.cc", ], hdrs = [ "awdl.h", + "awdl_bwu_handler.h", + "awdl_endpoint_channel.h", "ble.h", + "ble_endpoint_channel.h", + "ble_l2cap_endpoint_channel.h", + "bluetooth_bwu_handler.h", "bluetooth_classic.h", + "bluetooth_endpoint_channel.h", "bluetooth_radio.h", "mediums.h", - "webrtc.h", - "webrtc_stub.h", "wifi.h", "wifi_direct.h", + "wifi_direct_bwu_handler.h", + "wifi_direct_endpoint_channel.h", "wifi_hotspot.h", + "wifi_hotspot_bwu_handler.h", + "wifi_hotspot_endpoint_channel.h", "wifi_lan.h", + "wifi_lan_bwu_handler.h", + "wifi_lan_endpoint_channel.h", ], - copts = ["-DNO_WEBRTC"], + local_defines = select({ + "//:webrtc_enabled": [], + "//conditions:default": ["NO_WEBRTC"], + }), visibility = [ "//connections/implementation:__subpackages__", ], deps = [ ":utils", - ":webrtc_utils", + ":webrtc", + ":webrtc_peer_id", + ":webrtc_socket", "//connections:core_types", + "//connections/implementation:bwu_handler", + "//connections/implementation:client_proxy", + "//connections/implementation:endpoint_channel", + "//connections/implementation:offline_frames", + "//connections/implementation:service_id_constants", "//connections/implementation:types", "//connections/implementation/flags:connections_flags", "//connections/implementation/mediums/ble", "//connections/implementation/mediums/ble:ble_advertisement_header", "//connections/implementation/mediums/ble:ble_socket", "//connections/implementation/mediums/ble:bloom_filter", - "//connections/implementation/mediums/multiplex", - "//connections/implementation/mediums/webrtc", "//connections/implementation/proto:offline_wire_formats_cc_proto", + "//internal/base:masker", "//internal/flags:nearby_flags", "//internal/platform:base", "//internal/platform:cancellation_flag", @@ -73,9 +102,8 @@ cc_library( "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:wifi_utils", - "//proto/mediums:web_rtc_signaling_frames_cc_proto", - # TODO: Support WebRTC "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", @@ -86,21 +114,18 @@ cc_library( "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", - ], + ] + select({ + "//:webrtc_enabled": [ + "//connections/implementation/mediums/webrtc:webrtc_impl", + ], + "//conditions:default": [], + }), ) cc_library( - name = "webrtc_utils", - srcs = [ - "webrtc_peer_id.cc", - "webrtc_peer_id_stub.cc", - ], - hdrs = [ - "webrtc_peer_id.h", - "webrtc_peer_id_stub.h", - "webrtc_socket.h", - "webrtc_socket_stub.h", - ], + name = "webrtc_peer_id", + srcs = ["webrtc_peer_id.cc"], + hdrs = ["webrtc_peer_id.h"], visibility = [ "//connections/implementation:__pkg__", "//connections/implementation/mediums:__pkg__", @@ -108,7 +133,6 @@ cc_library( ], deps = [ ":utils", - "//connections/implementation/mediums/webrtc:data_types", "//internal/platform:base", "@com_google_absl//absl/strings", ], @@ -130,12 +154,10 @@ cc_library( name = "utils", srcs = ["utils.cc"], hdrs = ["utils.h"], - copts = ["-DNO_WEBRTC"], visibility = [ "//connections/implementation:__pkg__", "//connections/implementation/mediums/advertisements:__pkg__", "//connections/implementation/mediums/ble:__subpackages__", - "//connections/implementation/mediums/multiplex:__pkg__", "//internal/platform/implementation/windows:__pkg__", ], deps = [ @@ -144,6 +166,31 @@ cc_library( ], ) +cc_library( + name = "webrtc_socket", + hdrs = ["webrtc_socket.h"], + visibility = ["//connections/implementation:__subpackages__"], + deps = [ + "//internal/platform:base", + "@com_google_absl//absl/strings:string_view", + ], +) + +cc_library( + name = "webrtc", + hdrs = ["webrtc.h"], + visibility = ["//connections/implementation:__subpackages__"], + deps = [ + ":webrtc_peer_id", + ":webrtc_socket", + "//connections/implementation:bwu_handler", + "//connections/implementation/proto:offline_wire_formats_cc_proto", + "//internal/platform:base", + "//internal/platform:cancellation_flag", + "@com_google_absl//absl/functional:any_invocable", + ], +) + cc_test( name = "core_internal_mediums_test", size = "small", @@ -179,19 +226,53 @@ cc_test( "//internal/platform/implementation:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) +cc_test( + name = "bwu_handler_test", + size = "small", + srcs = [ + "awdl_bwu_handler_test.cc", + "bluetooth_bwu_handler_test.cc", + "wifi_direct_bwu_handler_test.cc", + "wifi_hotspot_bwu_handler_test.cc", + "wifi_lan_bwu_handler_test.cc", + ], + deps = [ + ":mediums", + "//connections/implementation:bwu_handler", + "//connections/implementation:client_proxy", + "//connections/implementation:endpoint_channel", + "//connections/implementation:offline_frames", + "//connections/implementation/flags:connections_flags", + "//internal/flags:nearby_flags", + "//internal/platform:base", + "//internal/platform:cancellation_flag", + "//internal/platform:comm", + "//internal/platform:logging", + "//internal/platform:mock_platform", + "//internal/platform:test_util", + "//internal/platform:types", + "//internal/platform/flags:platform_flags", + "//internal/platform/implementation:comm", + "//internal/platform/implementation:platform", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "core_internal_mediums_webrtc_test", size = "small", srcs = [ "webrtc_peer_id_test.cc", - "webrtc_test.cc", ], shard_count = 16, tags = [ @@ -199,8 +280,8 @@ cc_test( "requires-net:external", ], deps = [ - ":mediums", - ":webrtc_utils", + ":webrtc_peer_id", + ":webrtc_socket", "//internal/platform:base", "//internal/platform:cancellation_flag", "//internal/platform:comm", diff --git a/connections/implementation/mediums/awdl.cc b/connections/implementation/mediums/awdl.cc index cf380fcb..ba2539f1 100644 --- a/connections/implementation/mediums/awdl.cc +++ b/connections/implementation/mediums/awdl.cc @@ -23,28 +23,23 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "connections/implementation/mediums/multiplex/multiplex_socket.h" +#include "connections/implementation/bwu_handler.h" +#include "connections/implementation/mediums/awdl_bwu_handler.h" #include "connections/implementation/mediums/utils.h" -#include "connections/medium_selector.h" #include "internal/platform/awdl.h" -#include "internal/platform/base64_utils.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/psk_info.h" -#include "internal/platform/implementation/wifi_utils.h" #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" #include "internal/platform/nsd_service_info.h" -#include "internal/platform/socket.h" -#include "internal/platform/types.h" namespace nearby { namespace connections { namespace { -using MultiplexSocket = mediums::multiplex::MultiplexSocket; using location::nearby::proto::connections::OperationResultCode; constexpr absl::string_view kAwdlServiceIdSuffixForServiceType = "_AWDL"; @@ -479,5 +474,11 @@ ErrorOr Awdl::InternalConnect( return socket; } +std::unique_ptr Awdl::CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback) { + return std::make_unique( + this, std::move(incoming_connection_callback)); +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/awdl.h b/connections/implementation/mediums/awdl.h index b2a620d5..cb4f1910 100644 --- a/connections/implementation/mediums/awdl.h +++ b/connections/implementation/mediums/awdl.h @@ -16,6 +16,7 @@ #define CORE_INTERNAL_MEDIUMS_AWDL_H_ #include +#include #include #include #include @@ -24,12 +25,9 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/functional/any_invocable.h" -#include "connections/implementation/flags/nearby_connections_feature_flags.h" -#include "connections/implementation/mediums/multiplex/multiplex_socket.h" -#include "internal/flags/nearby_flags.h" +#include "connections/implementation/bwu_handler.h" #include "internal/platform/awdl.h" #include "internal/platform/cancellation_flag.h" -#include "internal/platform/exception.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/psk_info.h" #include "internal/platform/multi_thread_executor.h" @@ -133,6 +131,9 @@ class Awdl { AwdlCredential GetCredentials(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback); + private: struct AdvertisingInfo { bool Empty() const { return nsd_service_infos.empty(); } diff --git a/connections/implementation/awdl_bwu_handler.cc b/connections/implementation/mediums/awdl_bwu_handler.cc similarity index 94% rename from connections/implementation/awdl_bwu_handler.cc rename to connections/implementation/mediums/awdl_bwu_handler.cc index 45baead2..8f8e5287 100644 --- a/connections/implementation/awdl_bwu_handler.cc +++ b/connections/implementation/mediums/awdl_bwu_handler.cc @@ -12,29 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/awdl_bwu_handler.h" +#include "connections/implementation/mediums/awdl_bwu_handler.h" #include #include #include +#include "absl/base/nullability.h" #include "absl/functional/bind_front.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "connections/implementation/awdl_endpoint_channel.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/awdl.h" -#include "connections/implementation/mediums/mediums.h" +#include "connections/implementation/mediums/awdl_endpoint_channel.h" #include "connections/implementation/mediums/utils.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/service_id_constants.h" #include "internal/base/masker.h" #include "internal/platform/awdl.h" #include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/psk_info.h" @@ -56,9 +57,10 @@ constexpr absl::string_view kAwdlServiceIdSuffixForServiceType = "_AWDL"; } // namespace AwdlBwuHandler::AwdlBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + Awdl* absl_nonnull awdl_medium, + IncomingConnectionCallback incoming_connection_callback) : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} + awdl_medium_(*awdl_medium) {} // Called by BWU target. Retrieves a new medium info from incoming message, // and establishes connection over AWDL using this info. @@ -148,9 +150,10 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel( << service_name << ", service_type:" << service_type << ") for endpoint " << endpoint_id; - ErrorOr socket_result = - awdl_medium_.Connect(upgrade_service_id, nsd_service_info, psk_info, - client->GetCancellationFlag(endpoint_id)); + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint_id); + ErrorOr socket_result = awdl_medium_.Connect( + upgrade_service_id, nsd_service_info, psk_info, cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "Failed to connect to the AWDL service (service_name:" << service_name << ", service_type:" << service_type @@ -185,7 +188,7 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel( // Called by BWU initiator. Set up AWDL upgraded medium for this endpoint, // and returns a upgrade path info (service_name, port) for remote party to // perform discovery. -ByteArray AwdlBwuHandler::HandleInitializeUpgradedMediumForEndpoint( +std::string AwdlBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) { if (!awdl_medium_.IsAcceptingConnections(upgrade_service_id)) { diff --git a/connections/implementation/awdl_bwu_handler.h b/connections/implementation/mediums/awdl_bwu_handler.h similarity index 87% rename from connections/implementation/awdl_bwu_handler.h rename to connections/implementation/mediums/awdl_bwu_handler.h index 25e921ec..56a89290 100644 --- a/connections/implementation/awdl_bwu_handler.h +++ b/connections/implementation/mediums/awdl_bwu_handler.h @@ -12,21 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_AWDL_BWU_HANDLER_H_ -#define CORE_INTERNAL_AWDL_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_AWDL_BWU_HANDLER_H_ +#define CORE_INTERNAL_MEDIUMS_AWDL_BWU_HANDLER_H_ #include #include -#include +#include "absl/base/nullability.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/awdl.h" -#include "connections/implementation/mediums/mediums.h" #include "internal/platform/awdl.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" #include "internal/platform/nsd_service_info.h" @@ -37,8 +35,8 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class AwdlBwuHandler : public BaseBwuHandler { public: - explicit AwdlBwuHandler( - Mediums& mediums, + AwdlBwuHandler( + Awdl* absl_nonnull awdl_medium, IncomingConnectionCallback incoming_connection_callback); private: @@ -68,7 +66,7 @@ class AwdlBwuHandler : public BaseBwuHandler { const std::string& endpoint_id) final {} // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final; void HandleRevertInitiatorStateForService( @@ -82,12 +80,11 @@ class AwdlBwuHandler : public BaseBwuHandler { std::string GenerateServiceName(); std::string GeneratePassword(); - Mediums& mediums_; - Awdl& awdl_medium_{mediums_.GetAwdl()}; + Awdl& awdl_medium_; NsdServiceInfo nsd_service_info_; }; } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_AWDL_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_MEDIUMS_AWDL_BWU_HANDLER_H_ diff --git a/connections/implementation/mediums/awdl_bwu_handler_test.cc b/connections/implementation/mediums/awdl_bwu_handler_test.cc new file mode 100644 index 00000000..0080fec0 --- /dev/null +++ b/connections/implementation/mediums/awdl_bwu_handler_test.cc @@ -0,0 +1,495 @@ +// Copyright 2026 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 "connections/implementation/mediums/awdl_bwu_handler.h" + +#include +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "connections/implementation/bwu_handler.h" +#include "connections/implementation/client_proxy.h" +#include "connections/implementation/mediums/awdl.h" +#include "connections/implementation/mediums/awdl_endpoint_channel.h" +#include "connections/implementation/mediums/mediums.h" +#include "internal/platform/awdl.h" +#include "internal/platform/cancellation_flag.h" +#include "internal/platform/count_down_latch.h" +#include "internal/platform/exception.h" +#include "internal/platform/implementation/awdl.h" +#include "internal/platform/implementation/platform.h" +#include "internal/platform/implementation/psk_info.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/medium_environment.h" +#include "internal/platform/mock_input_stream.h" +#include "internal/platform/mock_output_stream.h" +#include "internal/platform/nsd_service_info.h" +#include "internal/platform/output_stream.h" + +namespace nearby { + +class MockAwdlSocket : public api::AwdlSocket { + public: + MOCK_METHOD(InputStream&, GetInputStream, (), (override)); + MOCK_METHOD(OutputStream&, GetOutputStream, (), (override)); + MOCK_METHOD(Exception, Close, (), (override)); +}; + +class MockAwdlServerSocket : public api::AwdlServerSocket { + public: + MOCK_METHOD(std::string, GetIPAddress, (), (const, override)); + MOCK_METHOD(int, GetPort, (), (const, override)); + MOCK_METHOD(std::unique_ptr, Accept, (), (override)); + MOCK_METHOD(Exception, Close, (), (override)); +}; + +class MockAwdlMedium : public api::AwdlMedium { + public: + MOCK_METHOD(bool, IsNetworkConnected, (), (const, override)); + MOCK_METHOD(bool, StartAdvertising, (const NsdServiceInfo& nsd_service_info), + (override)); + MOCK_METHOD(bool, StopAdvertising, (const NsdServiceInfo& nsd_service_info), + (override)); + MOCK_METHOD(bool, StartDiscovery, + (const std::string& service_type, + DiscoveredServiceCallback callback), + (override)); + MOCK_METHOD(bool, StopDiscovery, (const std::string& service_type), + (override)); + MOCK_METHOD(std::unique_ptr, ConnectToService, + (const NsdServiceInfo& remote_service_info, + CancellationFlag* cancellation_flag), + (override)); + MOCK_METHOD(std::unique_ptr, ConnectToService, + (const NsdServiceInfo& remote_service_info, + const api::PskInfo& psk_info, + CancellationFlag* cancellation_flag), + (override)); + MOCK_METHOD(std::unique_ptr, ListenForService, + (int port), (override)); + MOCK_METHOD(std::unique_ptr, ListenForService, + (const api::PskInfo& psk_info, int port), (override)); + MOCK_METHOD((std::optional>), + GetDynamicPortRange, (), (override)); +}; + +MockAwdlMedium* awdl_medium_mock = nullptr; + +namespace connections { +namespace { + +using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; +using ::location::nearby::connections::OfflineFrame; +using ::location::nearby::connections::V1Frame; +using ::location::nearby::proto::connections::OperationResultCode; +using ::testing::_; +using ::testing::ByMove; +using ::protobuf_matchers::EqualsProto; +using ::testing::MockFunction; +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::StrictMock; + +constexpr absl::string_view kServiceId{"service_id"}; +constexpr absl::string_view kEndpointId{"endpoint_id"}; +constexpr absl::string_view kServiceName{"awdl_srv"}; +constexpr absl::string_view kServiceType{"_awdl._tcp"}; +constexpr absl::string_view kPassword{"password123"}; +constexpr absl::string_view kChannelName{"channel_name"}; + +class AwdlBwuHandlerTest : public ::testing::Test { + protected: + AwdlBwuHandlerTest() + : handler_(&mediums_.GetAwdl(), + incoming_connection_callback_.AsStdFunction()) {} + + void SetUp() override { + // By default, network is connected. + ON_CALL(*awdl_medium_mock, IsNetworkConnected()) + .WillByDefault(Return(true)); + } + + Mediums mediums_; + MockFunction)> + incoming_connection_callback_; + AwdlBwuHandler handler_; + MockInputStream mock_input_stream_; + MockOutputStream mock_output_stream_; +}; + +TEST_F(AwdlBwuHandlerTest, + CreateUpgradedEndpointChannel_InvalidCredentials_Fails) { + ClientProxy client; + BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info; + path_info.mutable_awdl_credentials(); // Empty credentials + + auto result = + static_cast(&handler_)->CreateUpgradedEndpointChannel( + &client, "service_id", "endpoint_id", path_info); + + ASSERT_TRUE(result.has_error()); + EXPECT_EQ(result.error().operation_result_code().value(), + OperationResultCode::CONNECTIVITY_AWDL_INVALID_CREDENTIAL); +} + +TEST_F(AwdlBwuHandlerTest, CreateUpgradedEndpointChannel_Success) { + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + MockInputStream input_stream; + MockOutputStream output_stream; + auto awdl_socket = std::make_unique(); + EXPECT_CALL(*awdl_socket, GetInputStream()) + .WillRepeatedly(ReturnRef(input_stream)); + EXPECT_CALL(*awdl_socket, GetOutputStream()) + .WillRepeatedly(ReturnRef(output_stream)); + + EXPECT_CALL(*awdl_medium_mock, StartDiscovery(_, _)) + .WillOnce([](const std::string& service_type, + api::AwdlMedium::DiscoveredServiceCallback callback) { + NsdServiceInfo service_info; + service_info.SetServiceName(std::string(kServiceName)); + service_info.SetServiceType(service_type); + if (callback.service_discovered_cb) { + NsdServiceInfo service_info_copy = service_info; + callback.service_discovered_cb(service_info_copy); + } + return true; + }); + EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(*awdl_medium_mock, ConnectToService(_, _, _)) + .WillOnce(Return(ByMove(std::move(awdl_socket)))); + + BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info; + auto* credentials = path_info.mutable_awdl_credentials(); + credentials->set_service_name(kServiceName); + credentials->set_service_type(kServiceType); + credentials->set_password(kPassword); + + auto result = + static_cast(&handler_)->CreateUpgradedEndpointChannel( + &client, std::string(kServiceId), std::string(kEndpointId), + path_info); + + EXPECT_TRUE(result.has_value()); +} + +TEST_F(AwdlBwuHandlerTest, + InitializeUpgradedMediumForEndpoint_StartAcceptingConnectionsFails) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0)) + .WillOnce(Return(ByMove(nullptr))); + + std::string result = handler_.InitializeUpgradedMediumForEndpoint( + &client, std::string(kServiceId), std::string(kEndpointId)); + + EXPECT_TRUE(result.empty()); + MediumEnvironment::Instance().Stop(); +} + +TEST_F(AwdlBwuHandlerTest, InitializeUpgradedMediumForEndpoint_Success) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + // The reason for putting ClientProxy inside a C++ { } block so it destructs + // before the simulated clock is restored. Otherwise, the simulated clock + // would stopped before ClientProxy went out of scope, causing its destructor + // to log the session duration using the real system clock. If 1 or more + // real-world milliseconds elapsed between the test start and test end, this + // duration evaluated to something > 0. + { + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + auto awdl_server_socket = std::make_unique(); + auto* awdl_server_socket_ptr = awdl_server_socket.get(); + EXPECT_CALL(*awdl_server_socket_ptr, GetPort()) + .WillRepeatedly(Return(8080)); + EXPECT_CALL(*awdl_server_socket_ptr, Accept()) + .WillOnce(Return(ByMove(nullptr))); + EXPECT_CALL(*awdl_server_socket_ptr, Close()) + .WillRepeatedly(Return(Exception{Exception::kSuccess})); + + EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0)) + .WillOnce(Return(ByMove(std::move(awdl_server_socket)))); + + std::string captured_service_name; + std::string captured_service_type; + EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)) + .WillOnce([&](const NsdServiceInfo& nsd_service_info) { + captured_service_name = nsd_service_info.GetServiceName(); + captured_service_type = nsd_service_info.GetServiceType(); + return true; + }); + + std::string result = handler_.InitializeUpgradedMediumForEndpoint( + &client, std::string(kServiceId), std::string(kEndpointId)); + + EXPECT_FALSE(result.empty()); + OfflineFrame expected_frame; + expected_frame.set_version(OfflineFrame::V1); + expected_frame.mutable_v1()->set_type( + V1Frame::BANDWIDTH_UPGRADE_NEGOTIATION); + auto* bwu_frame = + expected_frame.mutable_v1()->mutable_bandwidth_upgrade_negotiation(); + bwu_frame->set_event_type( + BandwidthUpgradeNegotiationFrame::UPGRADE_PATH_AVAILABLE); + auto* upgrade_path_info = bwu_frame->mutable_upgrade_path_info(); + upgrade_path_info->set_medium( + BandwidthUpgradeNegotiationFrame::UpgradePathInfo::AWDL); + upgrade_path_info->set_supports_client_introduction_ack(true); + upgrade_path_info->set_supports_disabling_encryption(true); + auto* awdl_credentials = upgrade_path_info->mutable_awdl_credentials(); + awdl_credentials->set_service_name(captured_service_name); + awdl_credentials->set_service_type(captured_service_type); + + // The password is automatically generated and set in the handle start, we + // can obtain it from the credential Since we mock StartAcceptingConnections + // instead of using real awdl, GetPskInfo won't work perfectly. However + // InitializeUpgradedMediumForEndpoint internally calls + // parser::ForBwuAwdlPathAvailable which puts the generated password. We + // will extract it from result directly to build expected frame. + OfflineFrame result_frame; + EXPECT_TRUE(result_frame.ParseFromString(result)); + awdl_credentials->set_password(result_frame.v1() + .bandwidth_upgrade_negotiation() + .upgrade_path_info() + .awdl_credentials() + .password()); + + EXPECT_THAT(result_frame, EqualsProto(expected_frame)); + + handler_.RevertInitiatorState(); + } + MediumEnvironment::Instance().Stop(); +} + +TEST_F(AwdlBwuHandlerTest, OnIncomingAwdlConnection_Success) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + auto awdl_server_socket = std::make_unique(); + auto* awdl_server_socket_ptr = awdl_server_socket.get(); + EXPECT_CALL(*awdl_server_socket_ptr, Close()) + .WillRepeatedly(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(*awdl_server_socket_ptr, Accept()) + .WillOnce([this]() { + auto awdl_socket = std::make_unique(); + EXPECT_CALL(*awdl_socket, GetInputStream()) + .WillRepeatedly(ReturnRef(mock_input_stream_)); + EXPECT_CALL(*awdl_socket, GetOutputStream()) + .WillRepeatedly(ReturnRef(mock_output_stream_)); + return awdl_socket; + }) + .WillRepeatedly([]() { + absl::SleepFor(absl::Seconds(5)); + return nullptr; + }); + + EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0)) + .WillOnce(Return(ByMove(std::move(awdl_server_socket)))); + EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)).WillOnce(Return(true)); + + CountDownLatch latch(1); + EXPECT_CALL(incoming_connection_callback_, Call(&client, _)) + .WillOnce([&latch](ClientProxy* client, + std::unique_ptr + connection) { latch.CountDown(); }); + + std::string result = handler_.InitializeUpgradedMediumForEndpoint( + &client, std::string(kServiceId), std::string(kEndpointId)); + EXPECT_FALSE(result.empty()); + + auto await_result = latch.Await(absl::Seconds(5)); + EXPECT_TRUE(await_result.ok()); + + handler_.RevertInitiatorState(); + MediumEnvironment::Instance().Stop(); +} + +TEST_F(AwdlBwuHandlerTest, AwdlIncomingSocket_ToStringAndClose) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + auto awdl_server_socket = std::make_unique(); + auto* awdl_server_socket_ptr = awdl_server_socket.get(); + EXPECT_CALL(*awdl_server_socket_ptr, Close()) + .WillRepeatedly(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(*awdl_server_socket_ptr, Accept()) + .WillOnce([this]() { + auto awdl_socket = std::make_unique(); + EXPECT_CALL(*awdl_socket, GetInputStream()) + .WillRepeatedly(ReturnRef(mock_input_stream_)); + EXPECT_CALL(*awdl_socket, GetOutputStream()) + .WillRepeatedly(ReturnRef(mock_output_stream_)); + EXPECT_CALL(*awdl_socket, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + return awdl_socket; + }) + .WillRepeatedly([]() { + absl::SleepFor(absl::Seconds(5)); + return nullptr; + }); + + EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0)) + .WillOnce(Return(ByMove(std::move(awdl_server_socket)))); + EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)).WillOnce(Return(true)); + + CountDownLatch latch(1); + EXPECT_CALL(incoming_connection_callback_, Call(&client, _)) + .WillOnce([&latch](ClientProxy* client, + std::unique_ptr + connection) { + EXPECT_FALSE(connection->socket->ToString().empty()); + connection->socket->Close(); + latch.CountDown(); + }); + + std::string result = handler_.InitializeUpgradedMediumForEndpoint( + &client, std::string(kServiceId), std::string(kEndpointId)); + EXPECT_FALSE(result.empty()); + + auto await_result = latch.Await(absl::Seconds(5)); + EXPECT_TRUE(await_result.ok()); + + handler_.RevertInitiatorState(); + MediumEnvironment::Instance().Stop(); +} + +TEST_F(AwdlBwuHandlerTest, HandleRevertInitiatorStateForService_Success) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + auto awdl_server_socket = std::make_unique(); + auto* awdl_server_socket_ptr = awdl_server_socket.get(); + EXPECT_CALL(*awdl_server_socket_ptr, Close()) + .WillRepeatedly(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(*awdl_server_socket_ptr, Accept()).WillRepeatedly([]() { + absl::SleepFor(absl::Seconds(10)); + return nullptr; + }); + + EXPECT_CALL(*awdl_medium_mock, ListenForService(_, 0)) + .WillOnce(Return(ByMove(std::move(awdl_server_socket)))); + EXPECT_CALL(*awdl_medium_mock, StartAdvertising(_)).WillOnce(Return(true)); + EXPECT_CALL(*awdl_medium_mock, StopAdvertising(_)).WillOnce(Return(true)); + + handler_.InitializeUpgradedMediumForEndpoint(&client, std::string(kServiceId), + std::string(kEndpointId)); + + handler_.RevertInitiatorState(); + MediumEnvironment::Instance().Stop(); +} + +TEST_F(AwdlBwuHandlerTest, GetUpgradeMedium_ReturnsAwdl) { + auto* bwu_handler = static_cast(&handler_); + EXPECT_EQ(bwu_handler->GetUpgradeMedium(), + location::nearby::proto::connections::Medium::AWDL); +} + +TEST_F(AwdlBwuHandlerTest, OnEndpointDisconnect_DoesNotCrash) { + ClientProxy client; + auto* bwu_handler = static_cast(&handler_); + // This method is a no-op, just verifying it doesn't crash. + bwu_handler->OnEndpointDisconnect(&client, std::string(kEndpointId)); +} + +class AwdlEndpointChannelTest : public ::testing::Test { + protected: + void SetUp() override { + ON_CALL(*awdl_medium_mock, IsNetworkConnected()) + .WillByDefault(Return(true)); + mock_socket_ = std::make_unique>(); + EXPECT_CALL(*mock_socket_, GetInputStream()) + .WillRepeatedly(ReturnRef(mock_input_stream_)); + EXPECT_CALL(*mock_socket_, GetOutputStream()) + .WillRepeatedly(ReturnRef(mock_output_stream_)); + } + + std::unique_ptr> mock_socket_; + StrictMock mock_input_stream_; + StrictMock mock_output_stream_; + Awdl awdl_medium_; +}; + +TEST_F(AwdlEndpointChannelTest, CloseImpl_StopsDiscoveryIfOutgoing) { + EXPECT_CALL(*mock_socket_, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(mock_input_stream_, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(mock_output_stream_, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(*awdl_medium_mock, StartDiscovery(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*awdl_medium_mock, StopDiscovery(_)).WillOnce(Return(true)); + awdl_medium_.StartDiscovery(std::string(kServiceId), {}); + + AwdlEndpointChannel channel( + std::string(kServiceId), std::string(kChannelName), + AwdlSocket(std::move(mock_socket_)), &awdl_medium_, + /*is_outgoing=*/true); + + channel.Close(location::nearby::proto::connections::DisconnectionReason:: + UNKNOWN_DISCONNECTION_REASON); +} + +TEST_F(AwdlEndpointChannelTest, CloseImpl_DoesNotStopDiscoveryIfIncoming) { + EXPECT_CALL(*mock_socket_, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(mock_input_stream_, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + EXPECT_CALL(mock_output_stream_, Close()) + .WillOnce(Return(Exception{Exception::kSuccess})); + + AwdlEndpointChannel channel( + std::string(kServiceId), std::string(kChannelName), + AwdlSocket(std::move(mock_socket_)), &awdl_medium_, + /*is_outgoing=*/false); + + channel.Close(location::nearby::proto::connections::DisconnectionReason:: + UNKNOWN_DISCONNECTION_REASON); +} + +TEST_F(AwdlEndpointChannelTest, EnableMultiplexSocket_CallsSocket) { + AwdlEndpointChannel channel( + std::string(kServiceId), std::string(kChannelName), + AwdlSocket(std::move(mock_socket_)), &awdl_medium_, + /*is_outgoing=*/true); + + EXPECT_TRUE(channel.EnableMultiplexSocket()); +} + +} // namespace +} // namespace connections +namespace api { + +std::unique_ptr ImplementationPlatform::CreateAwdlMedium() { + auto medium = std::make_unique(); + awdl_medium_mock = medium.get(); + return medium; +} + +} // namespace api +} // namespace nearby diff --git a/connections/implementation/awdl_endpoint_channel.cc b/connections/implementation/mediums/awdl_endpoint_channel.cc similarity index 97% rename from connections/implementation/awdl_endpoint_channel.cc rename to connections/implementation/mediums/awdl_endpoint_channel.cc index 74ac3564..46cac068 100644 --- a/connections/implementation/awdl_endpoint_channel.cc +++ b/connections/implementation/mediums/awdl_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/awdl_endpoint_channel.h" +#include "connections/implementation/mediums/awdl_endpoint_channel.h" #include #include diff --git a/connections/implementation/awdl_endpoint_channel.h b/connections/implementation/mediums/awdl_endpoint_channel.h similarity index 88% rename from connections/implementation/awdl_endpoint_channel.h rename to connections/implementation/mediums/awdl_endpoint_channel.h index 1cd8da5b..ff22735a 100644 --- a/connections/implementation/awdl_endpoint_channel.h +++ b/connections/implementation/mediums/awdl_endpoint_channel.h @@ -12,13 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_AWDL_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_AWDL_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_AWDL_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_AWDL_ENDPOINT_CHANNEL_H_ #include #include "connections/implementation/base_endpoint_channel.h" #include "connections/implementation/mediums/awdl.h" +#include "internal/platform/awdl.h" namespace nearby { namespace connections { @@ -48,4 +49,4 @@ class AwdlEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_AWDL_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_AWDL_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/mediums/ble/BUILD b/connections/implementation/mediums/ble/BUILD index 619672c2..a4f1a0a4 100644 --- a/connections/implementation/mediums/ble/BUILD +++ b/connections/implementation/mediums/ble/BUILD @@ -70,7 +70,6 @@ cc_library( "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:string_view", - "@com_google_absl//absl/synchronization", ], ) diff --git a/connections/implementation/mediums/ble/ble_socket.cc b/connections/implementation/mediums/ble/ble_socket.cc index 97c29e32..dc068c9c 100644 --- a/connections/implementation/mediums/ble/ble_socket.cc +++ b/connections/implementation/mediums/ble/ble_socket.cc @@ -207,22 +207,28 @@ Medium BleSocket::GetMediumLocked() const { } ExceptionOr BleSocket::DispatchPacket() { - MutexLock lock(&mutex_); - if (!ble_input_stream_) { - return Exception::kFailed; + std::shared_ptr input_stream; + { + MutexLock lock(&mutex_); + if (!ble_input_stream_) { + return Exception::kFailed; + } + input_stream = ble_input_stream_; } ExceptionOr read_bytes = - ble_input_stream_->Read(BlePacket::kServiceIdHashLength); + input_stream->Read(BlePacket::kServiceIdHashLength); while (read_bytes.ok()) { ByteArray read_bytes_result = read_bytes.result(); if (BlePacket::IsControlPacketBytes(read_bytes_result)) { - ExceptionOr handle_result = ProcessBleControlPacketLocked(); + ExceptionOr handle_result = + ProcessBleControlPacket(input_stream); if (!handle_result.ok()) { return handle_result; } - read_bytes = ble_input_stream_->Read(BlePacket::kServiceIdHashLength); + read_bytes = input_stream->Read(BlePacket::kServiceIdHashLength); } else { + MutexLock lock(&mutex_); if (read_bytes_result != service_id_hash_) { LOG(WARNING) << "Received data packet with incorrect service ID hash. Expected: " @@ -239,20 +245,22 @@ ExceptionOr BleSocket::DispatchPacket() { ExceptionOr BleSocket::ReadPayloadLength() { int payload_length = 0; + std::shared_ptr input_stream; { MutexLock lock(&mutex_); if (!ble_input_stream_) { return {Exception::kIo}; } - - ExceptionOr read_bytes = - ble_input_stream_->Read(sizeof(std::int32_t)); - if (!read_bytes.ok()) { - return read_bytes.exception(); - } - - payload_length = byte_utils::BytesToInt(std::move(read_bytes.result())); + input_stream = ble_input_stream_; } + + ExceptionOr read_bytes = input_stream->Read(sizeof(std::int32_t)); + if (!read_bytes.ok()) { + return read_bytes.exception(); + } + + payload_length = byte_utils::BytesToInt(std::move(read_bytes.result())); + Exception send_ack_result = SendPacketAcknowledgement(payload_length); if (!send_ack_result.Ok()) { LOG(WARNING) << "Failed to send packet acknowledgement."; @@ -268,9 +276,10 @@ Exception BleSocket::WritePayloadLength(int payload_length) { return ble_output_stream_->WritePayloadLength(payload_length); } -ExceptionOr BleSocket::ProcessBleControlPacketLocked() { +ExceptionOr BleSocket::ProcessBleControlPacket( + std::shared_ptr input_stream) { // Read the first 4 bytes (packet block 1). - ExceptionOr read_bytes = ble_input_stream_->Read(4); + ExceptionOr read_bytes = input_stream->Read(4); if (!read_bytes.ok()) { return read_bytes; } @@ -282,7 +291,7 @@ ExceptionOr BleSocket::ProcessBleControlPacketLocked() { // Read the length from the 3rd byte of the packet block (0-indexed). int packet_block_2_size = packet_block_1.data()[3]; // Read the left bytes for the packet block 2). - read_bytes = ble_input_stream_->Read(packet_block_2_size); + read_bytes = input_stream->Read(packet_block_2_size); if (!read_bytes.ok()) { return read_bytes; } diff --git a/connections/implementation/mediums/ble/ble_socket.h b/connections/implementation/mediums/ble/ble_socket.h index 4aba0ca1..85aa9fb0 100644 --- a/connections/implementation/mediums/ble/ble_socket.h +++ b/connections/implementation/mediums/ble/ble_socket.h @@ -375,8 +375,8 @@ class BleSocket final { * payload, the `ByteArray` may be empty. Returns an `Exception` if a * protocol error occurs or the read operation fails. */ - ExceptionOr ProcessBleControlPacketLocked() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + ExceptionOr ProcessBleControlPacket( + std::shared_ptr input_stream); /** * Sends a raw L2CAP packet over the socket. @@ -407,9 +407,9 @@ class BleSocket final { SingleThreadExecutor serial_executor_; const ByteArray service_id_hash_; - std::unique_ptr ble_input_stream_ + std::shared_ptr ble_input_stream_ ABSL_GUARDED_BY(mutex_) = nullptr; - std::unique_ptr ble_output_stream_ + std::shared_ptr ble_output_stream_ ABSL_GUARDED_BY(mutex_) = nullptr; nearby::BleSocket ble_socket_ ABSL_GUARDED_BY(mutex_) = nearby::BleSocket(); nearby::BleL2capSocket l2cap_socket_ ABSL_GUARDED_BY(mutex_) = diff --git a/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc b/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc index 4eda44c6..6639dd4a 100644 --- a/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc +++ b/connections/implementation/mediums/ble/discovered_peripheral_tracker.cc @@ -247,20 +247,11 @@ bool DiscoveredPeripheralTracker::HandleOnLostAdvertisementLocked( BlePeripheral lost_peripheral = it.second.peripheral; lost_peripheral.SetId(ByteArray(gatt_advertisement)); if (gatt_advertisement.IsValid()) { - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableScanningForInstantOnLost)) { - AddInstantLostAdvertisement(it.second.advertisement_header); - discovery_cb_it->second.discovered_peripheral_callback - .instant_lost_cb(lost_peripheral, it.second.service_id, - gatt_advertisement.GetData(), - gatt_advertisement.IsFastAdvertisement()); - } else { - discovery_cb_it->second.discovered_peripheral_callback - .peripheral_lost_cb(lost_peripheral, it.second.service_id, - gatt_advertisement.GetData(), - gatt_advertisement.IsFastAdvertisement()); - } + AddInstantLostAdvertisement(it.second.advertisement_header); + discovery_cb_it->second.discovered_peripheral_callback + .instant_lost_cb(lost_peripheral, it.second.service_id, + gatt_advertisement.GetData(), + gatt_advertisement.IsFastAdvertisement()); LOG(INFO) << __func__ << ": OnLost triggered for service_id " << it.second.service_id; } diff --git a/connections/implementation/mediums/ble/discovered_peripheral_tracker_test.cc b/connections/implementation/mediums/ble/discovered_peripheral_tracker_test.cc index 79fd120f..c34120ae 100644 --- a/connections/implementation/mediums/ble/discovered_peripheral_tracker_test.cc +++ b/connections/implementation/mediums/ble/discovered_peripheral_tracker_test.cc @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -53,7 +52,6 @@ #include "internal/platform/mutex.h" #include "internal/platform/mutex_lock.h" #include "internal/platform/uuid.h" -#include "internal/test/fake_clock.h" namespace nearby { namespace connections { @@ -1628,9 +1626,6 @@ TEST_P(DiscoveredPeripheralTrackerTest, TEST_P(DiscoveredPeripheralTrackerTest, OnlyGattAdvertisementReceivedOnDeviceWithExtended) { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - std::vector service_ids = {std::string(kServiceIdA)}; ByteArray advertisement_hash = GenerateRandomAdvertisementHash(); ByteArray advertisement_header_bytes = @@ -1668,7 +1663,7 @@ TEST_P(DiscoveredPeripheralTrackerTest, // 2. Receive GATT advertisement data again after 4 seconds, it should access // GATT server. - (*fake_clock)->FastForward(absl::Seconds(4)); + MediumEnvironment::Instance().FastForward(absl::Seconds(4)); FindAdvertisement(advertisement_data, {advertisement_bytes}, fetch_latch); // We should receive a client callback of a peripheral discovery. @@ -1678,9 +1673,6 @@ TEST_P(DiscoveredPeripheralTrackerTest, } TEST_P(DiscoveredPeripheralTrackerTest, SkipExpiredGattAdvertisement) { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - std::vector service_ids = {std::string(kServiceIdA)}; ByteArray advertisement_hash = GenerateRandomAdvertisementHash(); ByteArray advertisement_header_bytes = @@ -1718,7 +1710,7 @@ TEST_P(DiscoveredPeripheralTrackerTest, SkipExpiredGattAdvertisement) { // 2. The GATT advertisement is already queued and will be skipped. FindAdvertisement(advertisement_data, {advertisement_bytes}, fetch_latch); - (*fake_clock)->FastForward(absl::Seconds(20)); + MediumEnvironment::Instance().FastForward(absl::Seconds(20)); discovered_peripheral_tracker_->StartFetchExecutorForTesting(); // We should not receive a client callback of a peripheral discovery. @@ -1729,9 +1721,6 @@ TEST_P(DiscoveredPeripheralTrackerTest, SkipExpiredGattAdvertisement) { TEST_P(DiscoveredPeripheralTrackerTest, DiscoveredOnceWhenGattAndExtendedAdvertisementReceived) { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - std::vector service_ids = {std::string(kServiceIdA)}; ByteArray advertisement_hash = GenerateRandomAdvertisementHash(); ByteArray advertisement_header_bytes = @@ -1756,7 +1745,7 @@ TEST_P(DiscoveredPeripheralTrackerTest, }, }, bleutils::kCopresenceServiceUuid); - (*fake_clock)->FastForward(absl::Seconds(4)); + MediumEnvironment::Instance().FastForward(absl::Seconds(4)); discovered_peripheral_tracker_->StartFetchExecutorForTesting(); // 1. Received extended advertisement. @@ -1784,8 +1773,6 @@ TEST_P(DiscoveredPeripheralTrackerTest, TEST_P(DiscoveredPeripheralTrackerTest, FindGattAdvertisementInHigherPriorityThanExtendedGattAdvertisement) { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); std::vector service_ids = {std::string(kServiceIdA)}; ByteArray advertisement_hash_a = GenerateRandomAdvertisementHash(); ByteArray advertisement_header_a = @@ -1823,7 +1810,7 @@ TEST_P(DiscoveredPeripheralTrackerTest, }, }, bleutils::kCopresenceServiceUuid); - (*fake_clock)->FastForward(absl::Seconds(4)); + MediumEnvironment::Instance().FastForward(absl::Seconds(4)); discovered_peripheral_tracker_->StartFetchExecutorForTesting(); // 1. Find peripheral A with GATT advertisement. diff --git a/connections/implementation/mediums/ble/instant_on_lost_manager.cc b/connections/implementation/mediums/ble/instant_on_lost_manager.cc index 6fd17c46..8a477d21 100644 --- a/connections/implementation/mediums/ble/instant_on_lost_manager.cc +++ b/connections/implementation/mediums/ble/instant_on_lost_manager.cc @@ -206,10 +206,7 @@ bool InstantOnLostManager::StartInstantOnLostAdvertisement() { StopOnLostAdvertising(); - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kDisableInstantOnLostOnBleWithoutExtended) && - !ble_medium_.IsExtendedAdvertisementsAvailable()) { + if (!ble_medium_.IsExtendedAdvertisementsAvailable()) { LOG(WARNING) << __func__ << ": Disabling instant on lost on BLE without extended advertising."; diff --git a/connections/implementation/ble_endpoint_channel.cc b/connections/implementation/mediums/ble_endpoint_channel.cc similarity index 98% rename from connections/implementation/ble_endpoint_channel.cc rename to connections/implementation/mediums/ble_endpoint_channel.cc index 4146b7ac..a261ab89 100644 --- a/connections/implementation/ble_endpoint_channel.cc +++ b/connections/implementation/mediums/ble_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/ble_endpoint_channel.h" +#include "connections/implementation/mediums/ble_endpoint_channel.h" #include #include diff --git a/connections/implementation/ble_endpoint_channel.h b/connections/implementation/mediums/ble_endpoint_channel.h similarity index 91% rename from connections/implementation/ble_endpoint_channel.h rename to connections/implementation/mediums/ble_endpoint_channel.h index 7ad7fc4e..82805a98 100644 --- a/connections/implementation/ble_endpoint_channel.h +++ b/connections/implementation/mediums/ble_endpoint_channel.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CONNECTIONS_IMPLEMENTATION_BLE_ENDPOINT_CHANNEL_H_ -#define CONNECTIONS_IMPLEMENTATION_BLE_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_ENDPOINT_CHANNEL_H_ #include #include @@ -57,4 +57,4 @@ class BleEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CONNECTIONS_IMPLEMENTATION_BLE_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/ble_l2cap_endpoint_channel.cc b/connections/implementation/mediums/ble_l2cap_endpoint_channel.cc similarity index 98% rename from connections/implementation/ble_l2cap_endpoint_channel.cc rename to connections/implementation/mediums/ble_l2cap_endpoint_channel.cc index 33056d69..6f92010e 100644 --- a/connections/implementation/ble_l2cap_endpoint_channel.cc +++ b/connections/implementation/mediums/ble_l2cap_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/ble_l2cap_endpoint_channel.h" +#include "connections/implementation/mediums/ble_l2cap_endpoint_channel.h" #include #include @@ -22,11 +22,11 @@ #include "connections/implementation/base_endpoint_channel.h" #include "connections/implementation/mediums/ble/ble_socket.h" #include "internal/platform/ble.h" +#include "internal/platform/byte_array.h" #include "internal/platform/exception.h" #include "internal/platform/input_stream.h" #include "internal/platform/logging.h" #include "internal/platform/output_stream.h" -#include "internal/platform/byte_array.h" namespace nearby { namespace connections { diff --git a/connections/implementation/ble_l2cap_endpoint_channel.h b/connections/implementation/mediums/ble_l2cap_endpoint_channel.h similarity index 91% rename from connections/implementation/ble_l2cap_endpoint_channel.h rename to connections/implementation/mediums/ble_l2cap_endpoint_channel.h index 292d67ea..00b84c8b 100644 --- a/connections/implementation/ble_l2cap_endpoint_channel.h +++ b/connections/implementation/mediums/ble_l2cap_endpoint_channel.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLE_L2CAP_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_BLE_L2CAP_ENDPOINT_CHANNEL_H_ #include #include @@ -60,4 +60,4 @@ class BleL2capEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_BLE_L2CAP_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLE_L2CAP_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/bluetooth_bwu_handler.cc b/connections/implementation/mediums/bluetooth_bwu_handler.cc similarity index 88% rename from connections/implementation/bluetooth_bwu_handler.cc rename to connections/implementation/mediums/bluetooth_bwu_handler.cc index f6734597..0edaae99 100644 --- a/connections/implementation/bluetooth_bwu_handler.cc +++ b/connections/implementation/mediums/bluetooth_bwu_handler.cc @@ -12,22 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/bluetooth_bwu_handler.h" +#include "connections/implementation/mediums/bluetooth_bwu_handler.h" #include #include #include +#include "absl/base/nullability.h" #include "absl/functional/bind_front.h" #include "connections/implementation/base_bwu_handler.h" -#include "connections/implementation/bluetooth_endpoint_channel.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" +#include "connections/implementation/mediums/bluetooth_classic.h" +#include "connections/implementation/mediums/bluetooth_endpoint_channel.h" +#include "connections/implementation/mediums/bluetooth_radio.h" #include "connections/implementation/offline_frames.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/bluetooth_classic.h" -#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" @@ -44,9 +46,12 @@ using ::location::nearby::proto::connections::OperationResultCode; } // namespace BluetoothBwuHandler::BluetoothBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + BluetoothRadio* absl_nonnull bluetooth_radio, + BluetoothClassic* absl_nonnull bluetooth_medium, + IncomingConnectionCallback incoming_connection_callback) : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} + bluetooth_radio_(*bluetooth_radio), + bluetooth_medium_(*bluetooth_medium) {} // Called by BWU target. Retrieves a new medium info from incoming message, // and establishes connection over BT using this info. @@ -85,8 +90,10 @@ BluetoothBwuHandler::CreateUpgradedEndpointChannel( OperationResultCode::CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE)}; } - ErrorOr socket_result = bluetooth_medium_.Connect( - device, service_id, client->GetCancellationFlag(endpoint_id)); + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint_id); + ErrorOr socket_result = + bluetooth_medium_.Connect(device, service_name, cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "BluetoothBwuHandler failed to connect to the Bluetooth device (" @@ -116,7 +123,7 @@ BluetoothBwuHandler::CreateUpgradedEndpointChannel( return {std::move(channel)}; } -ByteArray BluetoothBwuHandler::HandleInitializeUpgradedMediumForEndpoint( +std::string BluetoothBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) { MacAddress mac_address = bluetooth_medium_.GetAddress(); diff --git a/connections/implementation/bluetooth_bwu_handler.h b/connections/implementation/mediums/bluetooth_bwu_handler.h similarity index 84% rename from connections/implementation/bluetooth_bwu_handler.h rename to connections/implementation/mediums/bluetooth_bwu_handler.h index ae409310..b1902362 100644 --- a/connections/implementation/bluetooth_bwu_handler.h +++ b/connections/implementation/mediums/bluetooth_bwu_handler.h @@ -12,21 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_BLUETOOTH_BWU_HANDLER_H_ -#define CORE_INTERNAL_BLUETOOTH_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLUETOOTH_BWU_HANDLER_H_ +#define CORE_INTERNAL_MEDIUMS_BLUETOOTH_BWU_HANDLER_H_ #include #include +#include "absl/base/nullability.h" #include "connections/implementation/base_bwu_handler.h" +#include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/bluetooth_classic.h" #include "connections/implementation/mediums/bluetooth_radio.h" -#include "connections/implementation/mediums/mediums.h" #include "connections/medium_selector.h" #include "internal/platform/bluetooth_classic.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" namespace nearby { @@ -36,8 +36,9 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class BluetoothBwuHandler : public BaseBwuHandler { public: - explicit BluetoothBwuHandler( - Mediums& mediums, + BluetoothBwuHandler( + BluetoothRadio* absl_nonnull bluetooth_radio, + BluetoothClassic* absl_nonnull bluetooth_medium, IncomingConnectionCallback incoming_connection_callback); private: @@ -66,7 +67,7 @@ class BluetoothBwuHandler : public BaseBwuHandler { const std::string& endpoint_id) final {} // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final; void HandleRevertInitiatorStateForService( @@ -76,12 +77,11 @@ class BluetoothBwuHandler : public BaseBwuHandler { const std::string& upgrade_service_id, BluetoothSocket socket); - Mediums& mediums_; - BluetoothRadio& bluetooth_radio_{mediums_.GetBluetoothRadio()}; - BluetoothClassic& bluetooth_medium_{mediums_.GetBluetoothClassic()}; + BluetoothRadio& bluetooth_radio_; + BluetoothClassic& bluetooth_medium_; }; } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_BLUETOOTH_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLUETOOTH_BWU_HANDLER_H_ diff --git a/connections/implementation/bluetooth_bwu_test.cc b/connections/implementation/mediums/bluetooth_bwu_handler_test.cc similarity index 69% rename from connections/implementation/bluetooth_bwu_test.cc rename to connections/implementation/mediums/bluetooth_bwu_handler_test.cc index a60f8333..55c6c021 100644 --- a/connections/implementation/bluetooth_bwu_test.cc +++ b/connections/implementation/mediums/bluetooth_bwu_handler_test.cc @@ -12,18 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "connections/implementation/mediums/bluetooth_bwu_handler.h" + #include +#include #include #include "gtest/gtest.h" #include "absl/time/time.h" -#include "connections/implementation/bluetooth_bwu_handler.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/offline_frames.h" -#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" @@ -43,17 +44,27 @@ constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); class BluetoothBwuTest : public testing::Test { protected: - BluetoothBwuTest() { env_.Start(); } - ~BluetoothBwuTest() override { env_.Stop(); } + BluetoothBwuTest() { + original_flags_ = FeatureFlags::GetInstance().GetFlags(); + env_.Start(); + } + ~BluetoothBwuTest() override { + FeatureFlags::GetMutableInstanceForTesting().SetFlags(original_flags_); + env_.Stop(); + } + + void RunSTACreateEndpointChannelTest(bool enable_cancellation); MediumEnvironment& env_{MediumEnvironment::Instance()}; + FeatureFlags::Flags original_flags_; }; TEST_F(BluetoothBwuTest, CanCreateBwuHandler) { ClientProxy client; Mediums mediums; - auto handler = std::make_unique(mediums, nullptr); + auto handler = std::make_unique( + &mediums.GetBluetoothRadio(), &mediums.GetBluetoothClassic(), nullptr); handler->InitializeUpgradedMediumForEndpoint(&client, /*service_id=*/"B", /*endpoint_id=*/"2"); @@ -62,7 +73,12 @@ TEST_F(BluetoothBwuTest, CanCreateBwuHandler) { handler.reset(); } -TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { +void BluetoothBwuTest::RunSTACreateEndpointChannelTest( + bool enable_cancellation) { + FeatureFlags::Flags flags = original_flags_; + flags.enable_cancellation_flag = enable_cancellation; + FeatureFlags::GetMutableInstanceForTesting().SetFlags(flags); + CountDownLatch start_latch(1); CountDownLatch accept_latch(1); CountDownLatch end_latch(1); @@ -71,10 +87,14 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { Mediums mediums_1, mediums_2; ExceptionOr upgrade_frame; + EXPECT_TRUE(mediums_1.GetBluetoothRadio().Enable()); + EXPECT_TRUE(mediums_2.GetBluetoothRadio().Enable()); + auto handler_1 = std::make_unique( - mediums_1, [&](ClientProxy* client, - std::unique_ptr - mutable_connection) { + &mediums_1.GetBluetoothRadio(), &mediums_1.GetBluetoothClassic(), + [&](ClientProxy* client, + std::unique_ptr + mutable_connection) { LOG(WARNING) << "Server socket connection accept call back"; accept_latch.CountDown(); EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); @@ -83,11 +103,11 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { // client_1 works as Bluetooth Server Device SingleThreadExecutor server_executor; server_executor.Execute([&]() { - ByteArray upgrade_path_available_frame = + std::string upgrade_path_available_frame = handler_1->InitializeUpgradedMediumForEndpoint(&client_1, /*service_id=*/"A", /*endpoint_id=*/"1"); - EXPECT_FALSE(upgrade_path_available_frame.Empty()); + EXPECT_FALSE(upgrade_path_available_frame.empty()); upgrade_frame = parser::FromBytes(upgrade_path_available_frame); start_latch.CountDown(); @@ -98,7 +118,9 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { // Wait till client_1 started as Bluetooth and then connect to it EXPECT_TRUE(start_latch.Await(kWaitDuration).result()); std::unique_ptr handler_2 = - std::make_unique(mediums_2, nullptr); + std::make_unique( + &mediums_2.GetBluetoothRadio(), &mediums_2.GetBluetoothClassic(), + nullptr); client_executor.Execute([&]() { auto bwu_frame = @@ -108,7 +130,7 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { handler_2->CreateUpgradedEndpointChannel(&client_2, /*service_id=*/"A", /*endpoint_id=*/"1", bwu_frame.upgrade_path_info()); - if (!FeatureFlags::GetInstance().GetFlags().enable_cancellation_flag) { + if (!enable_cancellation) { ASSERT_TRUE(result.has_value()); std::unique_ptr new_channel = std::move(result.value()); EXPECT_TRUE(accept_latch.Await(kWaitDuration).result()); @@ -117,9 +139,9 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { } else { EXPECT_FALSE(result.has_value()); EXPECT_TRUE(result.has_error()); - EXPECT_EQ( - result.error().operation_result_code(), - OperationResultCode::CONNECTIVITY_BLUETOOTH_DEVICE_OBTAIN_FAILURE); + EXPECT_EQ(result.error().operation_result_code(), + OperationResultCode:: + CLIENT_CANCELLATION_CANCEL_BT_OUTGOING_CONNECTION); accept_latch.CountDown(); } EXPECT_TRUE(mediums_2.GetBluetoothClassic().GetAddress().IsSet()); @@ -131,5 +153,15 @@ TEST_F(BluetoothBwuTest, SoftAPBWUInit_STACreateEndpointChannel) { EXPECT_TRUE(end_latch.Await(kWaitDuration).result()); } +TEST_F(BluetoothBwuTest, + SoftAPBWUInit_STACreateEndpointChannel_WithCancellation) { + RunSTACreateEndpointChannelTest(true); +} + +TEST_F(BluetoothBwuTest, + SoftAPBWUInit_STACreateEndpointChannel_NoCancellation) { + RunSTACreateEndpointChannelTest(false); +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/bluetooth_classic.cc b/connections/implementation/mediums/bluetooth_classic.cc index 2ee55c30..d0dc386d 100644 --- a/connections/implementation/mediums/bluetooth_classic.cc +++ b/connections/implementation/mediums/bluetooth_classic.cc @@ -18,11 +18,9 @@ #include #include -#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "connections/implementation/bwu_handler.h" #include "connections/implementation/mediums/bluetooth_radio.h" -#include "connections/implementation/mediums/multiplex/multiplex_socket.h" -#include "connections/medium_selector.h" -#include "internal/flags/nearby_flags.h" +#include "connections/implementation/mediums/bluetooth_bwu_handler.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/bluetooth_classic.h" #include "internal/platform/cancellation_flag.h" @@ -30,8 +28,6 @@ #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" #include "internal/platform/mutex_lock.h" -#include "internal/platform/socket.h" -#include "internal/platform/types.h" #include "internal/platform/uuid.h" namespace nearby { @@ -54,8 +50,6 @@ std::string ScanModeToString(BluetoothAdapter::ScanMode mode) { } } // namespace -using MultiplexSocket = mediums::multiplex::MultiplexSocket; - BluetoothClassic::BluetoothClassic(BluetoothRadio& radio) : BluetoothClassic(radio, std::make_unique( radio.GetBluetoothAdapter())) {} @@ -64,15 +58,7 @@ BluetoothClassic::BluetoothClassic( BluetoothRadio& radio, std::unique_ptr medium) : radio_(radio), adapter_(radio_.GetBluetoothAdapter()), - medium_(std::move(medium)) { - is_multiplex_enabled_ = - NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplex) && - NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexBluetooth); -} + medium_(std::move(medium)) {} BluetoothClassic::~BluetoothClassic() { // Destructor is not taking locks, but methods it is calling are. @@ -82,20 +68,6 @@ BluetoothClassic::~BluetoothClassic() { } TurnOffDiscoverability(); - { - MutexLock lock(&mutex_); - LOG(INFO) << "Closing multiplex sockets for " << multiplex_sockets_.size() - << " devices"; - if (is_multiplex_enabled_) { - for (auto& [bt_mac, multiplex_socket] : multiplex_sockets_) { - LOG(INFO) << "Closing multiplex sockets for " - << GetRemoteDevice(bt_mac).GetName(); - multiplex_socket->Shutdown(); - } - } - multiplex_sockets_.clear(); - } - // All the AcceptLoopRunnable objects in here should already have gotten an // opportunity to shut themselves down cleanly in the calls to // StopAcceptingConnections() above. @@ -384,24 +356,13 @@ ErrorOr BluetoothClassic::StartAcceptingConnections( auto owned_socket = server_sockets_.emplace(service_id, std::move(socket)).first->second; - if (is_multiplex_enabled_) { - MultiplexSocket::ListenForIncomingConnection( - service_id, Medium::BLUETOOTH, - [&callback](const std::string& listening_service_id, - MediumSocket* virtual_socket) mutable { - if (callback) { - callback(listening_service_id, - *(down_cast(virtual_socket))); - } - }); - } // Start the accept loop on a dedicated thread - this stays alive and // listening for new incoming connections until StopAcceptingConnections() // is invoked. accept_loops_runner_.Execute("bt-accept", [callback = std::move(callback), server_socket = std::move(owned_socket), - service_id, this]() mutable { + service_id]() mutable { while (true) { BluetoothSocket client_socket = server_socket.Accept(); if (!client_socket.IsValid()) { @@ -411,34 +372,6 @@ ErrorOr BluetoothClassic::StartAcceptingConnections( } LOG(INFO) << "Accepted connection for " << service_id; bool callback_called = false; - { - MutexLock lock(&mutex_); - if (is_multiplex_enabled_) { - BluetoothSocket client_socket_bak = client_socket; - auto physical_socket_ptr = - std::make_shared(client_socket_bak); - MultiplexSocket* multiplex_socket = - MultiplexSocket::CreateIncomingSocket(physical_socket_ptr, - service_id, 0); - - if (multiplex_socket != nullptr && - multiplex_socket->GetVirtualSocket(service_id)) { - multiplex_sockets_.emplace( - client_socket.GetRemoteDevice().GetAddress(), - multiplex_socket); - MultiplexSocket::StopListeningForIncomingConnection( - service_id, Medium::BLUETOOTH); - LOG(INFO) << "Multiplex virtaul socket created for " - << client_socket.GetRemoteDevice().GetName(); - if (callback) { - callback(service_id, - *(down_cast( - multiplex_socket->GetVirtualSocket(service_id)))); - callback_called = true; - } - } - } - } if (callback && !callback_called) { LOG(INFO) << "Call back triggered for physical socket."; callback(service_id, std::move(client_socket)); @@ -475,10 +408,6 @@ bool BluetoothClassic::StopAcceptingConnections(const std::string& service_id) { << " because it was never started."; return false; } - if (is_multiplex_enabled_) { - MultiplexSocket::StopListeningForIncomingConnection(service_id, - Medium::BLUETOOTH); - } // Closing the BluetoothServerSocket will kick off the suicide of the thread // in accept_loops_thread_pool_ that blocks on @@ -507,29 +436,6 @@ bool BluetoothClassic::StopAcceptingConnections(const std::string& service_id) { ErrorOr BluetoothClassic::Connect( BluetoothDevice& bluetooth_device, const std::string& service_id, CancellationFlag* cancellation_flag) { - { - MutexLock lock(&mutex_); - if (is_multiplex_enabled_) { - LOG(INFO) << "multiplex_sockets_ size:" << multiplex_sockets_.size(); - auto it = multiplex_sockets_.find(bluetooth_device.GetAddress()); - if (it != multiplex_sockets_.end()) { - MultiplexSocket* multiplex_socket = it->second; - if (multiplex_socket->IsEnabled()) { - auto* virtual_socket = - multiplex_socket->EstablishVirtualSocket(service_id); - // Should not happen. - auto* bluetooth_socket = down_cast(virtual_socket); - if (bluetooth_socket == nullptr) { - LOG(INFO) << "Failed to cast to BluetoothSocket for " << service_id - << " with " << bluetooth_device.GetName(); - return {Error(OperationResultCode:: - NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE)}; - } - return *bluetooth_socket; - } - } - } - } service_id_to_connect_attempts_count_map_[service_id] = 1; while (service_id_to_connect_attempts_count_map_[service_id] <= kConnectAttemptsLimit) { @@ -605,29 +511,6 @@ ErrorOr BluetoothClassic::AttemptToConnect( return {Error( OperationResultCode::CONNECTIVITY_BT_CLIENT_SOCKET_CREATION_FAILURE)}; } - - if (is_multiplex_enabled_) { - // New MultiplexSocket but default disabled, should be enabled after - // negotiated - auto physical_socket_ptr = std::make_shared(socket); - MultiplexSocket* multiplex_socket = MultiplexSocket::CreateOutgoingSocket( - std::move(physical_socket_ptr), service_id); - - auto* virtual_socket = multiplex_socket->GetVirtualSocket(service_id); - // Should not happen. - auto* bluetooth_socket = down_cast(virtual_socket); - if (bluetooth_socket == nullptr) { - LOG(INFO) << "Failed to cast to BluetoothSocket for " << service_id - << " with " << bluetooth_device.GetName(); - return {Error( - OperationResultCode::NEARBY_BT_VIRTUAL_SOCKET_CREATION_FAILURE)}; - } - LOG(INFO) << "Multiplex socket created for " << bluetooth_device.GetName(); - multiplex_sockets_.emplace(bluetooth_device.GetAddress(), - multiplex_socket); - return *bluetooth_socket; - } - return socket; } @@ -684,5 +567,12 @@ std::string BluetoothClassic::GenerateUuidFromString(const std::string& data) { return std::string(Uuid(data)); } +std::unique_ptr BluetoothClassic::CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback) { + MutexLock lock(&mutex_); + return std::make_unique( + &radio_, this, std::move(incoming_connection_callback)); +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/bluetooth_classic.h b/connections/implementation/mediums/bluetooth_classic.h index d4221a1c..63ae1e68 100644 --- a/connections/implementation/mediums/bluetooth_classic.h +++ b/connections/implementation/mediums/bluetooth_classic.h @@ -22,10 +22,8 @@ #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" -#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "connections/implementation/bwu_handler.h" #include "connections/implementation/mediums/bluetooth_radio.h" -#include "connections/implementation/mediums/multiplex/multiplex_socket.h" -#include "internal/flags/nearby_flags.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/bluetooth_classic.h" #include "internal/platform/cancellation_flag.h" @@ -129,6 +127,9 @@ class BluetoothClassic { bool IsDiscovering(const std::string& serviceId) const ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback); + protected: // Use for unit tests only to inject a BluetoothClassicMedium. BluetoothClassic(BluetoothRadio& radio, @@ -234,14 +235,6 @@ class BluetoothClassic { mutable Mutex discovery_callbacks_mutex_; absl::flat_hash_map discovery_callbacks_ ABSL_GUARDED_BY(discovery_callbacks_mutex_); - - // Whether the multiplex feature is enabled. - bool is_multiplex_enabled_ = NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature::kEnableMultiplex); - - // A map of Bluetooth MacAddress -> MultiplexSocket. - absl::flat_hash_map - multiplex_sockets_ ABSL_GUARDED_BY(mutex_); }; } // namespace connections diff --git a/connections/implementation/bluetooth_endpoint_channel.cc b/connections/implementation/mediums/bluetooth_endpoint_channel.cc similarity index 97% rename from connections/implementation/bluetooth_endpoint_channel.cc rename to connections/implementation/mediums/bluetooth_endpoint_channel.cc index 73d09d9c..643a65c7 100644 --- a/connections/implementation/bluetooth_endpoint_channel.cc +++ b/connections/implementation/mediums/bluetooth_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/bluetooth_endpoint_channel.h" +#include "connections/implementation/mediums/bluetooth_endpoint_channel.h" #include #include diff --git a/connections/implementation/bluetooth_endpoint_channel.h b/connections/implementation/mediums/bluetooth_endpoint_channel.h similarity index 88% rename from connections/implementation/bluetooth_endpoint_channel.h rename to connections/implementation/mediums/bluetooth_endpoint_channel.h index b2176388..a28a7cdf 100644 --- a/connections/implementation/bluetooth_endpoint_channel.h +++ b/connections/implementation/mediums/bluetooth_endpoint_channel.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_BLUETOOTH_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_BLUETOOTH_ENDPOINT_CHANNEL_H_ #include @@ -46,4 +46,4 @@ class BluetoothEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_BLUETOOTH_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_BLUETOOTH_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/mediums/mediums.cc b/connections/implementation/mediums/mediums.cc index 8dd6dccd..4e0ff7bf 100644 --- a/connections/implementation/mediums/mediums.cc +++ b/connections/implementation/mediums/mediums.cc @@ -14,10 +14,15 @@ #include "connections/implementation/mediums/mediums.h" +#include + #include "connections/implementation/mediums/awdl.h" #include "connections/implementation/mediums/ble.h" #include "connections/implementation/mediums/bluetooth_classic.h" #include "connections/implementation/mediums/bluetooth_radio.h" +#ifndef NO_WEBRTC +#include "connections/implementation/mediums/webrtc/webrtc_impl.h" +#endif #include "connections/implementation/mediums/webrtc.h" #include "connections/implementation/mediums/wifi.h" #include "connections/implementation/mediums/wifi_direct.h" @@ -27,6 +32,14 @@ namespace nearby { namespace connections { +Mediums::Mediums() { +#ifndef NO_WEBRTC + webrtc_ = std::make_unique(); +#else + webrtc_ = std::make_unique(); +#endif +} + BluetoothRadio& Mediums::GetBluetoothRadio() { return bluetooth_radio_; } BluetoothClassic& Mediums::GetBluetoothClassic() { return bluetooth_classic_; } @@ -41,7 +54,7 @@ WifiHotspot& Mediums::GetWifiHotspot() { return wifi_hotspot_; } WifiDirect& Mediums::GetWifiDirect() { return wifi_direct_; } -mediums::WebRtc& Mediums::GetWebRtc() { return webrtc_; } +mediums::WebRtc& Mediums::GetWebRtc() { return *webrtc_; } Awdl& Mediums::GetAwdl() { return awdl_; } diff --git a/connections/implementation/mediums/mediums.h b/connections/implementation/mediums/mediums.h index 9cacfc31..bc125964 100644 --- a/connections/implementation/mediums/mediums.h +++ b/connections/implementation/mediums/mediums.h @@ -15,15 +15,13 @@ #ifndef CORE_INTERNAL_MEDIUMS_MEDIUMS_H_ #define CORE_INTERNAL_MEDIUMS_MEDIUMS_H_ +#include + #include "connections/implementation/mediums/awdl.h" #include "connections/implementation/mediums/ble.h" #include "connections/implementation/mediums/bluetooth_classic.h" #include "connections/implementation/mediums/bluetooth_radio.h" -#ifdef NO_WEBRTC -#include "connections/implementation/mediums/webrtc_stub.h" -#else #include "connections/implementation/mediums/webrtc.h" -#endif #include "connections/implementation/mediums/wifi.h" #include "connections/implementation/mediums/wifi_direct.h" #include "connections/implementation/mediums/wifi_hotspot.h" @@ -35,7 +33,7 @@ namespace connections { // Facilitates convenient and reliable usage of various wireless mediums. class Mediums { public: - Mediums() = default; + Mediums(); ~Mediums() = default; // Returns a handle to the Bluetooth radio. @@ -81,7 +79,7 @@ class Mediums { WifiLan wifi_lan_; WifiHotspot wifi_hotspot_; WifiDirect wifi_direct_; - mediums::WebRtc webrtc_; + std::unique_ptr webrtc_; Awdl awdl_; }; diff --git a/connections/implementation/mediums/multiplex/BUILD b/connections/implementation/mediums/multiplex/BUILD deleted file mode 100644 index fc1a59ff..00000000 --- a/connections/implementation/mediums/multiplex/BUILD +++ /dev/null @@ -1,72 +0,0 @@ -load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") - -# 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. -licenses(["notice"]) - -cc_library( - name = "multiplex", - srcs = [ - "multiplex_frames.cc", - "multiplex_output_stream.cc", - "multiplex_socket.cc", - ], - hdrs = [ - "multiplex_frames.h", - "multiplex_output_stream.h", - "multiplex_socket.h", - ], - visibility = [ - "//connections/implementation:__subpackages__", - ], - deps = [ - "//connections:core_types", - "//connections/implementation/mediums:utils", - "//internal/platform:base", - "//internal/platform:logging", - "//internal/platform:types", - "//proto:connections_enums_cc_proto", - "//proto/mediums:multiplex_frames_cc_proto", - "@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/strings", - "@com_google_absl//absl/time", - ], -) - -cc_test( - name = "multiplex_test", - srcs = [ - "multiplex_frames_test.cc", - "multiplex_output_stream_test.cc", - "multiplex_socket_test.cc", - ], - deps = [ - ":multiplex", - "//connections/implementation:internal", - "//internal/platform:base", - "//internal/platform:logging", - "//internal/platform:types", - "//internal/platform/implementation/g3", # buildcleaner: keep - "//proto:connections_enums_cc_proto", - "//proto/mediums:multiplex_frames_cc_proto", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/strings:string_view", - "@com_google_absl//absl/time", - "@com_google_googletest//:gtest_main", - ], -) diff --git a/connections/implementation/mediums/multiplex/multiplex_frames.cc b/connections/implementation/mediums/multiplex/multiplex_frames.cc deleted file mode 100644 index 3eea2aa1..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_frames.cc +++ /dev/null @@ -1,215 +0,0 @@ -// 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 "connections/implementation/mediums/multiplex/multiplex_frames.h" - -#include -#include - -#include "absl/strings/string_view.h" -#include "connections/implementation/mediums/utils.h" -#include "internal/platform/base64_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "internal/platform/logging.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -using ::location::nearby::mediums::ConnectionResponseFrame; -using ::location::nearby::mediums::MultiplexControlFrame; -using ::location::nearby::mediums::MultiplexFrame; - -ByteArray GenerateServiceIdHash(const std::string& service_id) { - return Utils::Sha256Hash(service_id, kServiceIdHashLength); -} - -ByteArray GenerateServiceIdHashWithSalt(const std::string& service_id, - std::string salt) { - if (salt.empty()) { - return GenerateServiceIdHash(service_id); - } - - return Utils::Sha256Hash(service_id + salt, kServiceIdHashLength); -} - -std::string GenerateServiceIdHashKey(const ByteArray& service_id_hash) { - return Base64Utils::Encode(service_id_hash); -} - -std::string GenerateServiceIdHashKey(const std::string& service_id) { - return GenerateServiceIdHashKey(GenerateServiceIdHash(service_id)); -} - -std::string GenerateServiceIdHashKeyWithSalt(const std::string& service_id, - std::string salt) { - return GenerateServiceIdHashKey( - GenerateServiceIdHashWithSalt(service_id, salt)); -} - -ByteArray ToBytes(MultiplexFrame&& frame) { - ByteArray bytes(frame.ByteSizeLong()); - frame.SerializeToArray(bytes.data(), bytes.size()); - return bytes; -} - -ByteArray ForConnectionRequest(const std::string& service_id, - const std::string& service_id_hash_salt) { - MultiplexFrame frame; - - frame.set_frame_type(MultiplexFrame::CONTROL_FRAME); - auto* header = frame.mutable_header(); - header->set_salted_service_id_hash(std::string( - GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt))); - header->set_service_id_hash_salt(service_id_hash_salt); - - auto* control_frame = frame.mutable_control_frame(); - control_frame->set_control_frame_type( - MultiplexControlFrame::CONNECTION_REQUEST); - - return ToBytes(std::move(frame)); -} - -ByteArray ForConnectionResponse( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - ConnectionResponseFrame::ConnectionResponseCode response_code) { - MultiplexFrame frame; - - frame.set_frame_type(MultiplexFrame::CONTROL_FRAME); - auto* header = frame.mutable_header(); - header->set_salted_service_id_hash(std::string(salted_service_id_hash)); - header->set_service_id_hash_salt(service_id_hash_salt); - - auto* control_frame = frame.mutable_control_frame(); - control_frame->set_control_frame_type( - MultiplexControlFrame::CONNECTION_RESPONSE); - - auto* response_frame = control_frame->mutable_connection_response_frame(); - response_frame->set_connection_response_code(response_code); - - return ToBytes(std::move(frame)); -} - -ByteArray ForDisconnection(const std::string& service_id, - const std::string& service_id_hash_salt) { - MultiplexFrame frame; - - frame.set_frame_type(MultiplexFrame::CONTROL_FRAME); - auto* header = frame.mutable_header(); - header->set_salted_service_id_hash(std::string( - GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt))); - header->set_service_id_hash_salt(service_id_hash_salt); - - auto* control_frame = frame.mutable_control_frame(); - control_frame->set_control_frame_type(MultiplexControlFrame::DISCONNECTION); - - return ToBytes(std::move(frame)); -} - -ByteArray ForData(const std::string& service_id, - const std::string& service_id_hash_salt, - bool should_pass_salt, absl::string_view data) { - MultiplexFrame frame; - - frame.set_frame_type(MultiplexFrame::DATA_FRAME); - auto* header = frame.mutable_header(); - header->set_salted_service_id_hash(std::string( - GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt))); - if (should_pass_salt) { - header->set_service_id_hash_salt(service_id_hash_salt); - } - - auto* data_frame = frame.mutable_data_frame(); - data_frame->set_data(data); - - return ToBytes(std::move(frame)); -} - -ExceptionOr FromBytes(const ByteArray& multiplex_frame_bytes) { - MultiplexFrame frame; - - if (frame.ParseFromString(std::string(multiplex_frame_bytes))) { - if (!IsValid(frame)) { - return ExceptionOr(Exception::kInvalidProtocolBuffer); - } - return ExceptionOr(std::move(frame)); - } else { - return ExceptionOr(Exception::kInvalidProtocolBuffer); - } -} - -bool IsControlFrame(MultiplexFrame::MultiplexFrameType frame_type) { - return frame_type == MultiplexFrame::CONTROL_FRAME; -} - -bool IsDataFrame(MultiplexFrame::MultiplexFrameType frame_type) { - return frame_type == MultiplexFrame::DATA_FRAME; -} - -bool IsValid(const MultiplexFrame& frame) { - switch (frame.frame_type()) { - case MultiplexFrame::CONTROL_FRAME: - return IsValidControlFrame(frame); - case MultiplexFrame::DATA_FRAME: - return IsValidDataFrame(frame); - default: - return false; - } -} - -bool IsValidControlFrame(const MultiplexFrame& frame) { - if (!frame.has_control_frame()) { - return false; - } - - switch (frame.control_frame().control_frame_type()) { - case MultiplexControlFrame::CONNECTION_REQUEST: - case MultiplexControlFrame::CONNECTION_RESPONSE: - case MultiplexControlFrame::DISCONNECTION: - if (frame.header().salted_service_id_hash().size() == - kServiceIdHashLength) { - return true; - } - break; - default: - break; - } - - return false; -} - -bool IsValidDataFrame(const MultiplexFrame& frame) { - return frame.has_data_frame() && - frame.header().salted_service_id_hash().size() == kServiceIdHashLength; -} - -bool IsMultiplexFrame(const ByteArray& data) { - ExceptionOr frame = FromBytes(data); - if (!frame.ok()) { - return false; - } else { - LOG(INFO) << "Checked data is a multiplex frame. Is Control ? " - << frame.result().has_control_frame() << ", is data ? " - << frame.result().has_data_frame(); - return true; - } -} - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/multiplex/multiplex_frames.h b/connections/implementation/mediums/multiplex/multiplex_frames.h deleted file mode 100644 index 283697a4..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_frames.h +++ /dev/null @@ -1,112 +0,0 @@ - -// 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 CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_FRAMES_H_ -#define CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_FRAMES_H_ - -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "proto/mediums/multiplex_frames.pb.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -constexpr int kServiceIdHashLength = 4; - -// Serialize/Deserialize MultiplexFrame messages. - -// Parses incoming MultiplexFrame message. -// Returns MultiplexFrame if parser was able to understand it, or -// Exception::kInvalidProtocolBuffer, if parser failed. - -// Generates a service ID hash bytes with {@link -// MultiplexFrames#SERVICE_ID_HASH_LENGTH}. -ByteArray GenerateServiceIdHash(const std::string& service_id); - -// Generates a service ID hash bytes with salt and {@link -// MultiplexFrames#SERVICE_ID_HASH_LENGTH}. -ByteArray GenerateServiceIdHashWithSalt(const std::string& service_id, - std::string salt); - -// Converts the service Id hash bytes to a Base64 encoded string to be used as a -// {@code Map} key. -std::string GenerateServiceIdHashKey(const ByteArray& service_id_hash); - -// Generates a service ID hash bytes with {@link -// MultiplexFrames#SERVICE_ID_HASH_LENGTH} and converts to a Base64 encoded -// string to be used as a {@code Map} key. -std::string GenerateServiceIdHashKey(const std::string& service_id); - -// Generates a service ID hash bytes with salt and {@link -// MultiplexFrames#SERVICE_ID_HASH_LENGTH} and converts to a Base64 encoded -// string to be used as a { @code Map } key. -std::string GenerateServiceIdHashKeyWithSalt(const std::string& service_id, - std::string salt); - -// Build a MultiplexFrame Connection Request frame Bytes stream. -// @param service_id The service ID of the connection. -// @param service_id_hash_salt The salt used to generate the service ID hash. -ByteArray ForConnectionRequest(const std::string& service_id, - const std::string& service_id_hash_salt); - -// Build a MultiplexFrame Connection Response frame Bytes stream. -// @param salted_service_id_hash The salted service ID hash. -// @param service_id_hash_salt The salt used to generate the service ID hash. -// @param response_code The response code of the connection. -ByteArray ForConnectionResponse( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - location::nearby::mediums::ConnectionResponseFrame::ConnectionResponseCode - response_code); - -// Build a MultiplexFrame Disconnection frame Bytes stream. -// @param service_id The service ID of the connection. -// @param service_id_hash_salt The salt used to generate the service ID hash. -ByteArray ForDisconnection(const std::string& service_id, - const std::string& service_id_hash_salt); - -// Build a MultiplexFrame Data frame Bytes stream. -// @param service_id The service ID of the connection. -// @param service_id_hash_salt The salt used to generate the service ID hash. -// @param should_pass_salt Whether to pass the salt in the data frame. -// @param data The data to send. -ByteArray ForData(const std::string& service_id, - const std::string& service_id_hash_salt, - bool should_pass_salt, absl::string_view data); - -ExceptionOr FromBytes( - const ByteArray& multiplex_frame_bytes); - -bool IsControlFrame( - location::nearby::mediums::MultiplexFrame::MultiplexFrameType frame_type); -bool IsDataFrame( - location::nearby::mediums::MultiplexFrame::MultiplexFrameType frame_type); -bool IsValid(const location::nearby::mediums::MultiplexFrame& frame); -bool IsValidControlFrame( - const location::nearby::mediums::MultiplexFrame& frame); -bool IsValidDataFrame(const location::nearby::mediums::MultiplexFrame& frame); -bool IsMultiplexFrame(const ByteArray& data); - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif // CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_FRAMES_H_ diff --git a/connections/implementation/mediums/multiplex/multiplex_frames_test.cc b/connections/implementation/mediums/multiplex/multiplex_frames_test.cc deleted file mode 100644 index 95a66803..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_frames_test.cc +++ /dev/null @@ -1,170 +0,0 @@ -// 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 "connections/implementation/mediums/multiplex/multiplex_frames.h" -#include -#include - -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -using ::location::nearby::mediums::MultiplexFrame; -using ::location::nearby::mediums::MultiplexControlFrame; -using ::location::nearby::mediums::ConnectionResponseFrame; - -constexpr absl::string_view kServiceId_1 = "serviceId_1"; -constexpr absl::string_view kServiceId_2 = "serviceId_2"; - -TEST(MultiplexFrameTest, FrameValidation) { - const ByteArray data("abcdefghijklmnopqrstuvwxyz"); - MultiplexFrame frame; - EXPECT_FALSE(IsValid(frame)); - frame.set_frame_type(MultiplexFrame::CONTROL_FRAME); - EXPECT_FALSE(IsValidControlFrame(frame)); - - auto* control_frame = frame.mutable_control_frame(); - control_frame->set_control_frame_type( - MultiplexControlFrame::UNKNOWN_CONTROL_FRAME_TYPE); - EXPECT_FALSE(IsValidControlFrame(frame)); - auto* header = frame.mutable_header(); - header->set_salted_service_id_hash(std::string( - GenerateServiceIdHashWithSalt(std::string(kServiceId_1), "1234"))); - control_frame->set_control_frame_type( - MultiplexControlFrame::CONNECTION_REQUEST); - EXPECT_TRUE(IsValidControlFrame(frame)); - EXPECT_TRUE(IsValid(frame)); - control_frame->set_control_frame_type( - MultiplexControlFrame::CONNECTION_RESPONSE); - EXPECT_TRUE(IsValidControlFrame(frame)); - EXPECT_TRUE(IsValid(frame)); - control_frame->set_control_frame_type( - MultiplexControlFrame::DISCONNECTION); - EXPECT_TRUE(IsValidControlFrame(frame)); - EXPECT_TRUE(IsValid(frame)); - - EXPECT_FALSE(IsValidDataFrame(frame)); - frame.set_frame_type(MultiplexFrame::DATA_FRAME); - auto* data_frame = frame.mutable_data_frame(); - data_frame->set_data(std::string(std::move(data))); - EXPECT_TRUE(IsValidDataFrame(frame)); - EXPECT_TRUE(IsValid(frame)); - - frame.set_frame_type(MultiplexFrame::UNKNOWN_FRAME_TYPE); - EXPECT_FALSE(IsValid(frame)); - - frame.set_frame_type(MultiplexFrame::DATA_FRAME); - auto serialized_bytes = ByteArray(frame.SerializeAsString()); - EXPECT_TRUE(IsMultiplexFrame(std::move(serialized_bytes))); - - EXPECT_TRUE(IsControlFrame(MultiplexFrame::CONTROL_FRAME)); - EXPECT_FALSE(IsControlFrame(MultiplexFrame::DATA_FRAME)); - EXPECT_TRUE(IsDataFrame(MultiplexFrame::DATA_FRAME)); - EXPECT_FALSE(IsDataFrame(MultiplexFrame::UNKNOWN_FRAME_TYPE)); -} - -TEST(MultiplexFrameTest, HashValidtion) { - auto service_id_hash_1 = GenerateServiceIdHash(std::string(kServiceId_1)); - EXPECT_EQ(service_id_hash_1.size(), kServiceIdHashLength); - auto service_id_hash_2 = GenerateServiceIdHash(std::string(kServiceId_2)); - EXPECT_NE(service_id_hash_1, service_id_hash_2); - - auto hash_key_1 = GenerateServiceIdHashKey(service_id_hash_1); - auto hash_key_2 = GenerateServiceIdHashKey(service_id_hash_2); - EXPECT_NE(hash_key_1, hash_key_2); - - auto service_id_hash_with_salt_1 = - GenerateServiceIdHashWithSalt(std::string(kServiceId_1), "1234"); - EXPECT_EQ(service_id_hash_with_salt_1.size(), kServiceIdHashLength); - auto service_id_hash_with_salt_2 = - GenerateServiceIdHashWithSalt(std::string(kServiceId_2), "1234"); - EXPECT_NE(service_id_hash_with_salt_1, service_id_hash_with_salt_2); - service_id_hash_with_salt_2 = - GenerateServiceIdHashWithSalt(std::string(kServiceId_1), "abcd"); - EXPECT_NE(service_id_hash_with_salt_1, service_id_hash_with_salt_2); - - auto hash_key_with_salt_1 = - GenerateServiceIdHashKeyWithSalt(std::string(kServiceId_1), "1234"); - auto hash_key_with_salt_2 = - GenerateServiceIdHashKeyWithSalt(std::string(kServiceId_2), "1234"); - EXPECT_NE(hash_key_with_salt_1, hash_key_with_salt_2); -} - -TEST(MultiplexFrameTest, CanGenerateConnectionRequest) { - ByteArray bytes = ForConnectionRequest(std::string(kServiceId_1), "1234"); - auto request = FromBytes(bytes); - ASSERT_TRUE(request.ok()); - auto frame = request.result(); - EXPECT_EQ(frame.control_frame().control_frame_type(), - MultiplexControlFrame::CONNECTION_REQUEST); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - "1234"))); -} - -TEST(MultiplexFrameTest, CanGenerateConnectionRespons) { - auto service_id_hash_with_salt_2 = - GenerateServiceIdHashWithSalt(std::string(kServiceId_2), "1234"); - ByteArray bytes = - ForConnectionResponse(service_id_hash_with_salt_2, "1234", - ConnectionResponseFrame::CONNECTION_ACCEPTED); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - auto frame = response.result(); - EXPECT_EQ(frame.control_frame().control_frame_type(), - MultiplexControlFrame::CONNECTION_RESPONSE); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(service_id_hash_with_salt_2)); - EXPECT_EQ(frame.control_frame() - .connection_response_frame() - .connection_response_code(), - ConnectionResponseFrame::CONNECTION_ACCEPTED); -} - -TEST(MultiplexFrameTest, CanGenerateDisconnection) { - ByteArray bytes = ForDisconnection(std::string(kServiceId_1), "1234"); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - auto frame = response.result(); - EXPECT_EQ(frame.control_frame().control_frame_type(), - MultiplexControlFrame::DISCONNECTION); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - "1234"))); -} - -TEST(MultiplexFrameTest, CanGenerateData) { - absl::string_view data = "abcdefghijklmnopqrstuvwxyz"; - ByteArray bytes = - ForData(std::string(kServiceId_1), "1234", true, data); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - auto frame = response.result(); - EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - "1234"))); - EXPECT_EQ(frame.data_frame().data(), - std::string("abcdefghijklmnopqrstuvwxyz")); -} - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/multiplex/multiplex_output_stream.cc b/connections/implementation/mediums/multiplex/multiplex_output_stream.cc deleted file mode 100644 index 0cdc2d52..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_output_stream.cc +++ /dev/null @@ -1,360 +0,0 @@ -// 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 "connections/implementation/mediums/multiplex/multiplex_output_stream.h" - -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/multiplex/multiplex_frames.h" -#include "internal/platform/array_blocking_queue.h" -#include "internal/platform/atomic_boolean.h" -#include "internal/platform/base64_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" -#include "internal/platform/output_stream.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { -namespace { -using ::location::nearby::mediums::ConnectionResponseFrame; - -constexpr absl::string_view kFakeSalt = "RECEIVER_CONDIMENT"; -} // namespace - -// Implementation for class MultiplexOutputStream -MultiplexOutputStream::MultiplexOutputStream(OutputStream* physical_writer, - AtomicBoolean& is_enabled) - : is_enabled_(is_enabled), - physical_writer_(physical_writer), - multiplex_writer_{physical_writer} {} - -Exception MultiplexOutputStream::WaitForResult(const std::string& method_name, - Future* future) { - if (!future) { - LOG(INFO) << "No future to wait for; return with error."; - return {Exception::kFailed}; - } - LOG(INFO) << "Waiting for future to complete: " << method_name; - ExceptionOr result = - future->Get(FeatureFlags::GetInstance() - .GetFlags() - .mediums_frame_write_timeout_millis); - if (!result.ok()) { - LOG(INFO) << "Future:[" << method_name - << "] completed with exception:" << result.exception(); - return {Exception::kFailed}; - } - if (result.result()) { - LOG(INFO) << "Future:[" << method_name << "] completed with success."; - return {Exception::kSuccess}; - } - LOG(INFO) << "Future:[" << method_name << "] completed with failure."; - return {Exception::kFailed}; -} - -bool MultiplexOutputStream::WriteConnectionRequestFrame( - const std::string& service_id, const std::string& service_id_hash_salt) { - if (!is_enabled_.Get()) { - return false; - } - Future future; - multiplex_writer_.EnqueueToSend( - &future, ForConnectionRequest(service_id, service_id_hash_salt), - "MultiplexFrame::CONNECTION_REQUEST"); - if (WaitForResult("MultiplexFrame::CONNECTION_REQUEST", &future).Ok()) - return true; - return false; -} - -bool MultiplexOutputStream::WriteConnectionResponseFrame( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - ConnectionResponseFrame::ConnectionResponseCode response_code) { - if (!is_enabled_.Get()) { - return false; - } - Future future; - multiplex_writer_.EnqueueToSend( - &future, - ForConnectionResponse(salted_service_id_hash, service_id_hash_salt, - response_code), - "MultiplexFrame::CONNECTION_RESPONSE"); - if (WaitForResult("MultiplexFrame::CONNECTION_RESPONSE", &future).Ok()) - return true; - return false; -} - -bool MultiplexOutputStream::Close(const std::string& service_id) { - auto item = virtual_output_streams_.find(service_id); - if (item == virtual_output_streams_.end()) { - LOG(INFO) << "Don't need to close VirtualOutputStream(" << service_id - << ") because it's already gone."; - return false; - } - - item->second->Close(); - if (is_enabled_.Get()) { - Future future; - multiplex_writer_.EnqueueToSend( - &future, - ForDisconnection(service_id, item->second->GetServiceIdHashSalt()), - "MultiplexFrame::DISCONNECTION"); - WaitForResult("MultiplexFrame::DISCONNECTION", &future); - } - virtual_output_streams_.erase(service_id); - if (virtual_output_streams_.empty()) { - physical_writer_->Close(); - multiplex_writer_.Close(); - } - return true; -} - -void MultiplexOutputStream::CloseAll() { - for (auto& [service_id, virtual_output_stream] : virtual_output_streams_) { - if (is_enabled_.Get()) { - Future future; - multiplex_writer_.EnqueueToSend( - &future, - ForDisconnection(service_id, - virtual_output_stream->GetServiceIdHashSalt()), - "MultiplexFrame::DISCONNECTION"); - WaitForResult("MultiplexFrame::DISCONNECTION", &future); - } - virtual_output_stream->Close(); - } - virtual_output_streams_.clear(); - physical_writer_->Close(); - multiplex_writer_.Close(); -} - -OutputStream* -MultiplexOutputStream::CreateVirtualOutputStreamForFirstVirtualSocket( - const std::string& service_id, const std::string& service_id_hash_salt) { - return virtual_output_streams_ - .emplace(service_id, - std::make_unique( - service_id, service_id_hash_salt, physical_writer_, - multiplex_writer_, - VirtualOutputStreamType::kFirstVirtualSocket, *this)) - .first->second.get(); -} - -OutputStream* MultiplexOutputStream::CreateVirtualOutputStream( - const std::string& service_id, const std::string& service_id_hash_salt) { - return virtual_output_streams_ - .emplace(service_id, - std::make_unique( - service_id, service_id_hash_salt, physical_writer_, - multiplex_writer_, - VirtualOutputStreamType::kNormalVirtualSocket, *this)) - .first->second.get(); -} - -std::string MultiplexOutputStream::GetServiceIdHashSalt( - const std::string& service_id) { - auto item = virtual_output_streams_.find(service_id); - if (item != virtual_output_streams_.end()) { - return item->second->GetServiceIdHashSalt(); - } - return {}; -} - -void MultiplexOutputStream::Shutdown() { - physical_writer_->Close(); - multiplex_writer_.Close(); -} - -// Implementation for class MultiplexOutputStream::MultiplexWriter -MultiplexOutputStream::MultiplexWriter::MultiplexWriter( - OutputStream* physical_writer) - : physical_writer_(physical_writer) {} - -MultiplexOutputStream::MultiplexWriter::~MultiplexWriter() { - Close(); - physical_writer_ = nullptr; -} - -void MultiplexOutputStream::MultiplexWriter::EnqueueToSend( - Future* future, const ByteArray& data, - const std::string& frame_name) { - MutexLock lock(&writing_mutex_); - data_queue_.Put(EnqueuedFrame(future, data)); - - if (is_writing_) { - return; - } - is_writing_ = true; - is_writing_cond_.Notify(); - if (!is_write_loop_running_) { - is_write_loop_running_ = true; - writer_thread_.Execute("Start writing", [this] { StartWriting(); }); - } -} - -void MultiplexOutputStream::MultiplexWriter::StartWriting() { - LOG(INFO) << "Writing loop started."; - while (true) { - auto enqueued_frame = data_queue_.TryTake(); - if (enqueued_frame != std::nullopt) { - Write(enqueued_frame.value()); - continue; - } - { - MutexLock lock(&writing_mutex_); - if (data_queue_.Empty() && is_writing_ && !is_closed_) { - is_writing_ = false; - LOG(INFO) << "Waiting for data_queue_ has data."; - Exception wait_succeeded = is_writing_cond_.Wait(); - if (!wait_succeeded.Ok()) { - LOG(WARNING) << "Failure waiting to wait: " << wait_succeeded.value; - return; - } - } - if (is_closed_) { - LOG(INFO) << "Notify to close_writing_thread"; - MutexLock lock(&close_writing_thread_mutex_); - close_writing_thread_cond_.Notify(); - break; - } - } - } - LOG(INFO) << "Writing loop stopped."; -} - -void MultiplexOutputStream::MultiplexWriter::Write( - EnqueuedFrame& enqueued_frame) { - MutexLock lock(&writer_mutex_); - if (!Base64Utils::WriteInt(physical_writer_, enqueued_frame.data_.size()) - .Ok()) { - enqueued_frame.future_->SetException({Exception::kIo}); - return; - }; - if (!physical_writer_->Write(enqueued_frame.data_.AsStringView()).Ok()) { - enqueued_frame.future_->SetException({Exception::kIo}); - return; - }; - if (!physical_writer_->Flush().Ok()) { - enqueued_frame.future_->SetException({Exception::kIo}); - return; - }; - enqueued_frame.future_->Set(true); -} - -void MultiplexOutputStream::MultiplexWriter::Close() { - if (is_closed_) { - LOG(INFO) << "MultiplexWriter is already closed."; - return; - } - LOG(INFO) << "Stop writing loop and Shutdown writer thread."; - { - MutexLock lock(&writing_mutex_); - is_closed_ = true; - if (!is_write_loop_running_) { - writer_thread_.Shutdown(); - return; - } - is_write_loop_running_ = false; - is_writing_cond_.Notify(); - } - LOG(INFO) << "Wait to close_writing_thread"; - { - MutexLock lock(&close_writing_thread_mutex_); - close_writing_thread_cond_.Wait(absl::Milliseconds(20)); - LOG(INFO) << "Shutdown writer thread."; - writer_thread_.Shutdown(); - } -} - -MultiplexOutputStream::VirtualOutputStream::VirtualOutputStream( - std::string service_id, std::string service_id_hash_salt, - OutputStream* physical_writer, MultiplexWriter& multiplex_writer, - VirtualOutputStreamType virtual_output_stream_type, - MultiplexOutputStream& multiplex_output_stream) - : service_id_(service_id), - service_id_hash_salt_(service_id_hash_salt), - physical_writer_(physical_writer), - multiplex_writer_(multiplex_writer), - virtual_output_stream_type_(virtual_output_stream_type), - multiplex_output_stream_(multiplex_output_stream) {} - -Exception MultiplexOutputStream::VirtualOutputStream::Write( - absl::string_view data) { - if (is_closed_.Get()) { - LOG(WARNING) << "Failed to write data because the VirtualOutputStream for " - << service_id_ << " closed"; - return {Exception::kIo}; - } - if (multiplex_output_stream_.is_enabled_.Get()) { - bool should_pass_salt = false; - if (IsFirstVirtualOutputStream()) { - if (!first_frame_sent_for_first_virtual_output_stream_) { - first_frame_sent_for_first_virtual_output_stream_ = true; - should_pass_salt = true; - } - // Fixes b/290724590, b/290983930 which can't get the correct socket - // from the virtualSockets map. NS receiver side will pass 2 - // DATA_FRAMEs continuously to the remote sender side but originally - // impl will only consider the 1st one. Add below fix to handle 2nd - // frame which the salt is still fake one and change shouldPassSalt to - // true to let the remote handle correctly. - if ((service_id_hash_salt_ == kFakeSalt) && !should_pass_salt) { - should_pass_salt = true; - LOG(INFO) << "service_idHashSalt is still a fake one and " - "not changed yet; continue to pass salt."; - } - } - ByteArray data_frame = - ForData(service_id_, service_id_hash_salt_, should_pass_salt, data); - Future future; - multiplex_writer_.EnqueueToSend(&future, data_frame, - "MultiplexFrame::DATA_FRAME"); - return multiplex_output_stream_.WaitForResult("MultiplexFrame::DATA_FRAME", - &future); - } else { - if (!physical_writer_->Write(data).Ok()) { - return {Exception::kIo}; - }; - if (!physical_writer_->Flush().Ok()) { - return {Exception::kIo}; - }; - } - - return {Exception::kSuccess}; -} - -Exception MultiplexOutputStream::VirtualOutputStream::Flush() { - return {Exception::kSuccess}; -} - -Exception MultiplexOutputStream::VirtualOutputStream::Close() { - LOG(INFO) << "MultiplexOutputStream::VirtualOutputStream::Close"; - is_closed_.Set(true); - return {Exception::kSuccess}; -} - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/multiplex/multiplex_output_stream.h b/connections/implementation/mediums/multiplex/multiplex_output_stream.h deleted file mode 100644 index 22067d71..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_output_stream.h +++ /dev/null @@ -1,209 +0,0 @@ -// 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 CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_OUTPUT_STREAM_H_ -#define CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_OUTPUT_STREAM_H_ - -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/strings/string_view.h" -#include "internal/platform/array_blocking_queue.h" -#include "internal/platform/atomic_boolean.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/mutex.h" -#include "internal/platform/output_stream.h" -#include "internal/platform/single_thread_executor.h" -#include "proto/mediums/multiplex_frames.pb.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { -/** - * A helper class to send out the {@code MultiplexControlFrame} and the outgoing - * data from clients. It schedules control and data frames with priority below - * - *

{@link MultiplexControlFrameType#CONNECTION_REQUEST} and {@link - * MultiplexControlFrameType#CONNECTION_RESPONSE} have the highest priority - * - *

All {@link MultiplexDataFrame} has the medium priority. If there's - * multiple clients send data at the same time, should poll every client's - * outgoing data in sequence. For example, client A and B send data at the same - * time, the outgoing data sequence should like A-Frame-1, B-Frame-1, A-Frame-2, - * B-Frame-2,... - * - *

{@link MultiplexControlFrameType#DISCONNECTION} has the same priority with - * {@link MultiplexDataFrame} because the disconnect should not make the already - * enqueued data failed to send out, so put it in the same priority queue with - * the MultiplexDataFrame. - */ -class MultiplexOutputStream { - public: - enum class VirtualOutputStreamType { - // The type of virtual socket established for the physical socket is - // created. - kFirstVirtualSocket = 0, - // The others except FIRST_VIRTUAL_SCOKET type. - kNormalVirtualSocket = 1, - }; - - MultiplexOutputStream(OutputStream* physical_writer, - AtomicBoolean& is_enabled); - ~MultiplexOutputStream() = default; - - // Writes the connection request frame to the physical output stream. - bool WriteConnectionRequestFrame(const std::string& service_id, - const std::string& service_id_hash_salt); - - // Writes the connection response frame to the physical output stream. - bool WriteConnectionResponseFrame( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - ::location::nearby::mediums::ConnectionResponseFrame:: - ConnectionResponseCode response_code); - - // Closes the virtual output stream. - bool Close(const std::string& service_id); - - // Closes all virtual output streams. - void CloseAll(); - - // Waits for the result of the future. - Exception WaitForResult(const std::string& method_name, Future* future); - - // Creates the virtual output stream for the first virtual socket. - OutputStream* CreateVirtualOutputStreamForFirstVirtualSocket( - const std::string& service_id, const std::string& service_id_hash_salt); - - // Creates the virtual output stream. - OutputStream* CreateVirtualOutputStream( - const std::string& service_id, const std::string& service_id_hash_salt); - - // Gets the service id hash salt. - std::string GetServiceIdHashSalt(const std::string& service_id); - - // Shuts down the multiplex output stream. - void Shutdown(); - - class EnqueuedFrame { - public: - EnqueuedFrame(Future* future, ByteArray data) - : future_(future), data_(data) {} - ~EnqueuedFrame() = default; - - Future* future_; - ByteArray data_; - }; - - class MultiplexWriter { - public: - explicit MultiplexWriter(OutputStream* physical_writer); - ~MultiplexWriter(); - - // Enqueues the frame to be sent out. - void EnqueueToSend(Future* future, const ByteArray& data, - const std::string& frame_name); - // Closes the writer. - void Close(); - - private: - // Starts the writer thread. - void StartWriting(); - - // Writes the enqueued frame. - void Write(EnqueuedFrame& enqueued_frame); - - Mutex writer_mutex_; - OutputStream* physical_writer_ ABSL_PT_GUARDED_BY(writer_mutex_); - - ArrayBlockingQueue data_queue_{ - FeatureFlags::GetInstance() - .GetFlags() - .multiplex_socket_middle_priority_queue_capacity}; - mutable Mutex writing_mutex_; - ConditionVariable is_writing_cond_{&writing_mutex_}; - bool is_writing_ ABSL_GUARDED_BY(writing_mutex_) = false; - bool is_closed_ = false; - mutable Mutex close_writing_thread_mutex_; - ConditionVariable close_writing_thread_cond_{&close_writing_thread_mutex_}; - - // The single thread to write all enqueued frames. - SingleThreadExecutor writer_thread_; - bool is_write_loop_running_ = false; - }; - - class VirtualOutputStream : public OutputStream { - public: - VirtualOutputStream(std::string service_id, - std::string service_id_hash_salt, - OutputStream* physical_writer, - MultiplexWriter& multiplex_writer, - VirtualOutputStreamType virtual_output_stream_type, - MultiplexOutputStream& multiplex_output_stream); - ~VirtualOutputStream() override = default; - - // Returns true if the virtual output stream is the first virtual output - // stream. - bool IsFirstVirtualOutputStream() { - return virtual_output_stream_type_ == - VirtualOutputStreamType::kFirstVirtualSocket; - } - - // Returns the service id hash salt. - std::string GetServiceIdHashSalt() { return service_id_hash_salt_; } - - // Sets the service id hash salt. - void SetserviceIdHashSalt(std::string service_id_hash_salt) { - service_id_hash_salt_ = service_id_hash_salt; - } - - // Writes the data to the physical output stream. - Exception Write(absl::string_view data) override; - // Flushes the physical output stream. - Exception Flush() override; - // Closes the virtual output stream. - Exception Close() override; - - private: - AtomicBoolean is_closed_{false}; - - std::string service_id_; - std::string service_id_hash_salt_; - OutputStream* physical_writer_; - MultiplexWriter& multiplex_writer_; - VirtualOutputStreamType virtual_output_stream_type_; - bool first_frame_sent_for_first_virtual_output_stream_ = false; - MultiplexOutputStream& multiplex_output_stream_; - }; - - private: - AtomicBoolean& is_enabled_; - OutputStream* physical_writer_; - absl::flat_hash_map> - virtual_output_streams_; - MultiplexWriter multiplex_writer_; -}; - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif // CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_OUTPUT_STREAM_H_ diff --git a/connections/implementation/mediums/multiplex/multiplex_output_stream_test.cc b/connections/implementation/mediums/multiplex/multiplex_output_stream_test.cc deleted file mode 100644 index 4a5ae130..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_output_stream_test.cc +++ /dev/null @@ -1,253 +0,0 @@ -// 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 "connections/implementation/mediums/multiplex/multiplex_output_stream.h" - -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/multiplex/multiplex_frames.h" -#include "internal/platform/atomic_boolean.h" -#include "internal/platform/base64_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/exception.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/logging.h" -#include "internal/platform/multi_thread_executor.h" -#include "internal/platform/output_stream.h" -#include "internal/platform/pipe.h" -#include "proto/mediums/multiplex_frames.pb.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -constexpr absl::string_view kServiceId_1 = "serviceId_1"; -constexpr absl::string_view kServiceId_2 = "serviceId_2"; -constexpr absl::string_view kNoSalt = ""; -constexpr absl::string_view kSalt_1 = "DNFG"; -constexpr absl::string_view kSalt_2 = "YFRT"; - -using ::location::nearby::mediums::ConnectionResponseFrame; -using ::location::nearby::mediums::MultiplexControlFrame; -using ::location::nearby::mediums::MultiplexFrame; - -class MultiplexOutputStreamTest : public ::testing::Test { - protected: - ExceptionOr ReadFrame() { - ExceptionOr read_int = Base64Utils::ReadInt(reader_.get()); - if (!read_int.ok()) return read_int.GetException(); - if (read_int.result() <= 0) return {Exception::kFailed}; - - ExceptionOr received_data = - reader_->ReadExactly(read_int.result()); - if (!received_data.ok()) return received_data.GetException(); - auto bytes = std::move(received_data.result()); - return FromBytes(bytes); - } - - AtomicBoolean enabled_{true}; - std::pair, std::unique_ptr> pipe_ = - CreatePipe(); - - std::unique_ptr reader_ = std::move(pipe_.first); - std::unique_ptr writer_ = std::move(pipe_.second); - std::unique_ptr multiplex_output_stream_; -}; - -TEST_F(MultiplexOutputStreamTest, SendConnectionRequestFrame) { - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - EXPECT_TRUE(multiplex_output_stream_->WriteConnectionRequestFrame( - std::string(kServiceId_1), std::string(kNoSalt))); - - auto request = ReadFrame(); - ASSERT_TRUE(request.ok()); - auto frame = request.result(); - EXPECT_EQ(frame.control_frame().control_frame_type(), - MultiplexControlFrame::CONNECTION_REQUEST); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - std::string(kNoSalt)))); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, SendConnectionRequestFrameDisabled) { - enabled_.Set(false); - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - EXPECT_FALSE(multiplex_output_stream_->WriteConnectionRequestFrame( - std::string(kServiceId_1), std::string(kNoSalt))); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, SendConnectionResponseFrame) { - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - EXPECT_TRUE(multiplex_output_stream_->WriteConnectionResponseFrame( - GenerateServiceIdHash(std::string(kServiceId_1)), std::string(kNoSalt), - ConnectionResponseFrame::CONNECTION_ACCEPTED)); - - auto response = ReadFrame(); - ASSERT_TRUE(response.ok()); - auto frame = response.result(); - EXPECT_EQ(frame.control_frame().control_frame_type(), - MultiplexControlFrame::CONNECTION_RESPONSE); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - std::string(kNoSalt)))); - EXPECT_EQ(frame.control_frame() - .connection_response_frame() - .connection_response_code(), - ConnectionResponseFrame::CONNECTION_ACCEPTED); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, SendConnectionResponseFrameDisabled) { - enabled_.Set(false); - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - EXPECT_FALSE(multiplex_output_stream_->WriteConnectionResponseFrame( - GenerateServiceIdHash(std::string(kServiceId_1)), std::string(kNoSalt), - ConnectionResponseFrame::CONNECTION_ACCEPTED)); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, CloseVirtualStreamFailed) { - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - EXPECT_FALSE(multiplex_output_stream_->Close(std::string(kServiceId_1))); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, CloseVirtualStreamSuccess) { - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - EXPECT_FALSE(multiplex_output_stream_->Close(std::string(kServiceId_1))); - - multiplex_output_stream_->CreateVirtualOutputStream(std::string(kServiceId_1), - std::string(kNoSalt)); - EXPECT_TRUE(multiplex_output_stream_->Close(std::string(kServiceId_1))); - - auto request = ReadFrame(); - ASSERT_TRUE(request.ok()); - auto frame = request.result(); - EXPECT_EQ(frame.control_frame().control_frame_type(), - MultiplexControlFrame::DISCONNECTION); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - std::string(kNoSalt)))); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, CreateVirtualStream_SendData) { - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - - auto virtual_output_stream = - multiplex_output_stream_->CreateVirtualOutputStream( - std::string(kServiceId_1), std::string(kSalt_1)); - - absl::string_view data = "abcdefghijklmnopqrstuvwxyz"; - virtual_output_stream->Write(data); - virtual_output_stream->Flush(); - auto frame_data = ReadFrame(); - ASSERT_TRUE(frame_data.ok()); - auto frame = frame_data.result(); - EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME); - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - std::string(kSalt_1)))); - EXPECT_EQ(frame.data_frame().data(), std::string(data)); - - multiplex_output_stream_->Shutdown(); -} - -TEST_F(MultiplexOutputStreamTest, CreateTwoVirtualStreams_SendData) { - multiplex_output_stream_ = - std::make_unique(writer_.get(), enabled_); - - auto virtual_output_stream_1 = - multiplex_output_stream_->CreateVirtualOutputStreamForFirstVirtualSocket( - std::string(kServiceId_1), std::string(kSalt_1)); - auto virtual_output_stream_2 = - multiplex_output_stream_->CreateVirtualOutputStreamForFirstVirtualSocket( - std::string(kServiceId_2), std::string(kSalt_2)); - - absl::string_view data_1("abcdefg"); - absl::string_view data_2("hijklmn"); - MultiThreadExecutor executor(2); - CountDownLatch latch(2); - executor.Execute([&virtual_output_stream_1, &latch, &data_1]() { - absl::SleepFor(absl::Milliseconds(100)); - virtual_output_stream_1->Write(data_1); - virtual_output_stream_1->Flush(); - latch.CountDown(); - }); - executor.Execute([&virtual_output_stream_2, &latch, &data_2]() { - virtual_output_stream_2->Write(data_2); - virtual_output_stream_2->Flush(); - latch.CountDown(); - }); - EXPECT_TRUE(latch.Await(absl::Milliseconds(5000)).result()); - - auto frame_data = ReadFrame(); - ASSERT_TRUE(frame_data.ok()); - auto frame = frame_data.result(); - EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME); - bool first_frame_is_data_1 = true; - if (frame.header().salted_service_id_hash() == - std::string(GenerateServiceIdHashWithSalt(std::string(kServiceId_1), - std::string(kSalt_1)))) { - EXPECT_EQ(frame.data_frame().data(), std::string(data_1)); - LOG(INFO) << "Read first virtual stream frame first."; - } else { - EXPECT_EQ(frame.header().salted_service_id_hash(), - std::string(GenerateServiceIdHashWithSalt( - std::string(kServiceId_2), std::string(kSalt_2)))); - EXPECT_EQ(frame.data_frame().data(), std::string(data_2)); - first_frame_is_data_1 = false; - LOG(INFO) << "Read second virtual stream frame first."; - } - - frame_data = ReadFrame(); - ASSERT_TRUE(frame_data.ok()); - frame = frame_data.result(); - EXPECT_EQ(frame.frame_type(), MultiplexFrame::DATA_FRAME); - if (first_frame_is_data_1) { - EXPECT_EQ(frame.data_frame().data(), std::string(data_2)); - } else { - EXPECT_EQ(frame.data_frame().data(), std::string(data_1)); - } - multiplex_output_stream_->Shutdown(); -} - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/multiplex/multiplex_socket.cc b/connections/implementation/mediums/multiplex/multiplex_socket.cc deleted file mode 100644 index befe36e9..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_socket.cc +++ /dev/null @@ -1,807 +0,0 @@ -// 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 "connections/implementation/mediums/multiplex/multiplex_socket.h" - -#include -#include -#include -#include -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/functional/any_invocable.h" -#include "absl/strings/string_view.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/multiplex/multiplex_frames.h" -#include "connections/implementation/mediums/multiplex/multiplex_output_stream.h" -#include "connections/implementation/mediums/utils.h" -#include "internal/platform/atomic_boolean.h" -#include "internal/platform/base64_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/exception.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex.h" -#include "internal/platform/mutex_lock.h" -#include "internal/platform/socket.h" -#include "internal/platform/types.h" -#include "proto/connections_enums.pb.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -namespace { -// It is defined for the receiver which send the first packet to the sender -// without getting salt from it yet. The fake salt reminds sender to get the -// correct socket from `virtualSockets` without remapping it. -constexpr absl::string_view kFakeSalt = "RECEIVER_CONDIMENT"; - -// The max duration to wait for the reader thread to stop. -constexpr absl::Duration kTimeoutForReaderThreadStop = absl::Milliseconds(100); - -} // namespace - -using ::location::nearby::mediums::ConnectionResponseFrame; -using ::location::nearby::mediums::MultiplexControlFrame; -using ::location::nearby::mediums::MultiplexDataFrame; -using ::location::nearby::mediums::MultiplexFrame; -using ::location::nearby::proto::connections::Medium; -using ::location::nearby::proto::connections::Medium_Name; -using ConnectionResponseCode = ConnectionResponseFrame::ConnectionResponseCode; - -// AtomicBoolean is trivial destructible, so it is safe to use it as a static -// variable. -AtomicBoolean MultiplexSocket::is_shutting_down_{false}; // NOLINT - -void MultiplexSocket::ListenForIncomingConnection( - const std::string& service_id, Medium type, - MultiplexIncomingConnectionCb incoming_connection_cb) { - GetIncomingConnectionCallbacks().emplace( - std::pair(service_id, type), - std::move(incoming_connection_cb)); -} - -void MultiplexSocket::StopListeningForIncomingConnection( - const std::string& service_id, Medium type) { - GetIncomingConnectionCallbacks().erase( - std::pair(service_id, type)); -} - -MultiplexSocket::MultiplexSocket(std::shared_ptr physical_socket) - : physical_socket_ptr_(physical_socket), - multiplex_output_stream_{&physical_socket_ptr_->GetOutputStream(), - enabled_}, - physical_reader_(&physical_socket_ptr_->GetInputStream()), - medium_(physical_socket_ptr_->GetMedium()) {} - -absl::flat_hash_map, - MultiplexIncomingConnectionCb>& -MultiplexSocket::GetIncomingConnectionCallbacks() { - using MapType = absl::flat_hash_map, - MultiplexIncomingConnectionCb>; - alignas(MapType) static char storage[sizeof(MapType)]; - static MapType* incoming_connection_callbacks = new (&storage) MapType(); - - return *incoming_connection_callbacks; -} - -MultiplexSocket* MultiplexSocket::CreateIncomingSocket( - std::shared_ptr physical_socket, - const std::string& service_id, std::int32_t first_frame_len) { - while (is_shutting_down_.Get()) { - LOG(WARNING) - << "Shutting down is going on, wait for 2ms to create incoming socket"; - absl::SleepFor(absl::Milliseconds(2)); - } - - MultiplexSocket* multiplex_incoming_socket = nullptr; - static MultiplexSocket* multiplex_incoming_socket_bt = nullptr; - static MultiplexSocket* multiplex_incoming_socket_wlan = nullptr; - - switch (physical_socket->GetMedium()) { - case Medium::BLUETOOTH: - if (multiplex_incoming_socket_bt != nullptr) { - LOG(INFO) << "Multiplex incoming socket already exists for BT"; - return multiplex_incoming_socket_bt; - } - alignas(MultiplexSocket) static char storage_bt[sizeof(MultiplexSocket)]; - multiplex_incoming_socket_bt = - new (&storage_bt) MultiplexSocket(physical_socket); - multiplex_incoming_socket = multiplex_incoming_socket_bt; - break; - case Medium::WIFI_LAN: - case Medium::AWDL: - if (multiplex_incoming_socket_wlan != nullptr) { - LOG(INFO) << "Multiplex incoming socket already exists for WLAN"; - return multiplex_incoming_socket_wlan; - } - alignas( - MultiplexSocket) static char storage_wlan[sizeof(MultiplexSocket)]; - multiplex_incoming_socket_wlan = - new (&storage_wlan) MultiplexSocket(physical_socket); - multiplex_incoming_socket = multiplex_incoming_socket_wlan; - break; - default: - LOG(ERROR) << __func__ - << "Unsupported medium: " << physical_socket->GetMedium(); - multiplex_incoming_socket = nullptr; - return multiplex_incoming_socket; - } - LOG(INFO) << "CreateIncomingSocket with serviceId=" << service_id - << ", serviceIdHashSalt=" << kFakeSalt - << " for medium=" << Medium_Name(physical_socket->GetMedium()); - - multiplex_incoming_socket->CreateFirstVirtualSocket(service_id, - (std::string)kFakeSalt); - multiplex_incoming_socket->StartReaderThread(first_frame_len); - - return multiplex_incoming_socket; -} - -MultiplexSocket* MultiplexSocket::CreateOutgoingSocket( - std::shared_ptr physical_socket, - const std::string& service_id, const std::string& service_id_hash_salt) { - while (is_shutting_down_.Get()) { - LOG(WARNING) - << "Shutting down is going on, wait for 2ms to create outgoing socket"; - absl::SleepFor(absl::Milliseconds(2)); - } - - MultiplexSocket* multiplex_outgoing_socket = nullptr; - static MultiplexSocket* multiplex_outgoing_socket_bt = nullptr; - static MultiplexSocket* multiplex_outgoing_socket_wlan = nullptr; - - switch (physical_socket->GetMedium()) { - case Medium::BLUETOOTH: - if (multiplex_outgoing_socket_bt != nullptr) { - LOG(INFO) << "Multiplex outgoing socket already exists for BT"; - return multiplex_outgoing_socket_bt; - } - alignas(MultiplexSocket) static char storage_bt[sizeof(MultiplexSocket)]; - multiplex_outgoing_socket_bt = - new (&storage_bt) MultiplexSocket(physical_socket); - multiplex_outgoing_socket = multiplex_outgoing_socket_bt; - break; - case Medium::WIFI_LAN: - case Medium::AWDL: - if (multiplex_outgoing_socket_wlan != nullptr) { - LOG(INFO) << "Multiplex outgoing socket already exists for WLAN"; - return multiplex_outgoing_socket_wlan; - } - alignas( - MultiplexSocket) static char storage_wlan[sizeof(MultiplexSocket)]; - multiplex_outgoing_socket_wlan = - new (&storage_wlan) MultiplexSocket(physical_socket); - multiplex_outgoing_socket = multiplex_outgoing_socket_wlan; - break; - default: - LOG(ERROR) << __func__ - << "Unsupported medium: " << physical_socket->GetMedium(); - multiplex_outgoing_socket = nullptr; - return multiplex_outgoing_socket; - } - LOG(INFO) << "CreateOutgoingSocket with serviceId=" << service_id - << ", serviceIdHashSalt=" << service_id_hash_salt - << " for medium=" << Medium_Name(physical_socket->GetMedium()); - - multiplex_outgoing_socket->CreateFirstVirtualSocket(service_id, - service_id_hash_salt); - multiplex_outgoing_socket->StartReaderThread(0); - return multiplex_outgoing_socket; -} - -MultiplexSocket* MultiplexSocket::CreateOutgoingSocket( - std::shared_ptr physical_socket, - const std::string& service_id) { - return CreateOutgoingSocket(physical_socket, service_id, - Utils::GenerateSalt()); -} - -MediumSocket* MultiplexSocket::CreateFirstVirtualSocket( - const std::string& service_id, const std::string& service_id_hash_salt) { - auto output_stream = - multiplex_output_stream_.CreateVirtualOutputStreamForFirstVirtualSocket( - service_id, service_id_hash_salt); - - MutexLock lock(&virtual_socket_mutex_); - std::string salted_service_id_hash_key = - GenerateServiceIdHashKeyWithSalt(service_id, service_id_hash_salt); - LOG(INFO) << __func__ << " for service_id=" << service_id - << ", salt=" << service_id_hash_salt - << ", salted_service_id_hash_key=" << salted_service_id_hash_key; - MediumSocket* virtual_socket = physical_socket_ptr_->CreateVirtualSocket( - salted_service_id_hash_key, output_stream, medium_, &virtual_sockets_); - - virtual_socket->AddOnSocketClosedListener( - std::make_unique>( - [this, service_id]() { OnVirtualSocketClosed(service_id); })); - - if (!IsEnabled()) { - LOG(INFO) << __func__ << ": Register multiplex enabled callback"; - virtual_socket->RegisterMultiplexEnabledCallback(enable_cb_); - } - - return virtual_socket; -} - -MediumSocket* MultiplexSocket::CreateVirtualSocket( - const std::string& service_id, const std::string& service_id_hash_salt) { - auto output_stream = multiplex_output_stream_.CreateVirtualOutputStream( - service_id, service_id_hash_salt); - MutexLock lock(&virtual_socket_mutex_); - std::string salted_service_id_hash_key = - GenerateServiceIdHashKeyWithSalt(service_id, service_id_hash_salt); - - LOG(INFO) << __func__ << "service_id=" << service_id - << ", salt=" << service_id_hash_salt - << ", salted_service_id_hash_key=" << salted_service_id_hash_key; - - MediumSocket* virtual_socket = physical_socket_ptr_->CreateVirtualSocket( - salted_service_id_hash_key, output_stream, medium_, &virtual_sockets_); - - virtual_socket->AddOnSocketClosedListener( - std::make_unique>( - [this, service_id]() { OnVirtualSocketClosed(service_id); })); - - return virtual_socket; -} - -MediumSocket* MultiplexSocket::GetVirtualSocket(const std::string& service_id) { - MutexLock lock(&virtual_socket_mutex_); - LOG(INFO) << __func__ << " service_id=" << service_id << ", Salt=" - << multiplex_output_stream_.GetServiceIdHashSalt(service_id) - << ", virtual_sockets_.size()=" << virtual_sockets_.size(); - auto item = virtual_sockets_.find(GenerateServiceIdHashKeyWithSalt( - service_id, multiplex_output_stream_.GetServiceIdHashSalt(service_id))); - if (item == virtual_sockets_.end()) { - LOG(INFO) << "Not found!"; - return nullptr; - } - return item->second.get(); -} - -int MultiplexSocket::GetVirtualSocketCount() { - MutexLock lock(&virtual_socket_mutex_); - return virtual_sockets_.size(); -} - -void MultiplexSocket::ListVirtualSocket() { - LOG(INFO) << __func__ - << " virtual_sockets_.size()=" << virtual_sockets_.size(); - for (auto& [service_id_hash_key, virtual_socket] : virtual_sockets_) { - LOG(INFO) << __func__ << " service_id_hash_key=" << service_id_hash_key - << ", virtual_socket=" << virtual_socket; - } -} - -std::shared_ptr> -MultiplexSocket::RegisterConnectionResponse(const std::string& service_id) { - auto future = std::make_shared>(); - connection_response_futures_.emplace(service_id, future); - - return future; -} - -void MultiplexSocket::UnRegisterConnectionResponse( - const std::string& service_id) { - connection_response_futures_.erase(service_id); -} - -MediumSocket* MultiplexSocket::EstablishVirtualSocket( - const std::string& service_id) { - if (!IsEnabled()) { - LOG(ERROR) - << "MultiplexSocket is disabled, cannot establish virtual socket."; - return nullptr; - } - - std::string service_id_hash_salt = Utils::GenerateSalt(); - auto future = RegisterConnectionResponse(service_id); - - multiplex_output_stream_.WriteConnectionRequestFrame(service_id, - service_id_hash_salt); - auto result = - future->Get(FeatureFlags::GetInstance() - .GetFlags() - .multiplex_socket_connection_response_timeout_millis); - if (!result.ok()) { - LOG(ERROR) << __func__ - << "EstablishVirtualSocket failed with response code=" - << result.exception(); - return nullptr; - } - - ConnectionResponseCode response_code = result.GetResult(); - switch (response_code) { - case ConnectionResponseFrame::CONNECTION_ACCEPTED: - LOG(INFO) << "EstablishVirtualSocket after remote response to" - " accept the connection with service_id=" - << service_id - << ", service_id_hash_salt=" << service_id_hash_salt; - return CreateVirtualSocket(service_id, service_id_hash_salt); - case ConnectionResponseFrame::NOT_LISTENING: - LOG(ERROR) << "EstablishVirtualSocket failed for service_id=" - << service_id - << ", service_id_hash_salt=" << service_id_hash_salt - << " with response code=NOT_LISTENING"; - break; - default: - LOG(ERROR) << "EstablishVirtualSocket failed for service_id=" - << service_id - << ", service_id_hash_salt=" << service_id_hash_salt - << " with response code=UNKNOWN_RESPONSE_CODE"; - break; - } - return nullptr; -} - -void MultiplexSocket::StartReaderThread(std::int32_t first_frame_len) { - if (is_shutdown_) { - LOG(WARNING) << "Stop to start reader thread since socket is " - "shutdown."; - return; - } - reader_thread_shutdown_barrier_ = std::make_unique(1); - physical_reader_thread_.Execute([this, first_frame_len]() { - LOG(INFO) << __func__ << " Reader thread starts."; - auto first_frame_len_copy = first_frame_len; - while (!is_shutdown_) { - bool fail = false; - ExceptionOr bytes; - ExceptionOr read_int; - if (first_frame_len_copy > 0) { - read_int = ExceptionOr(first_frame_len); - first_frame_len_copy = 0; - } else { - read_int = Base64Utils::ReadInt(physical_reader_); - } - if (!read_int.ok()) { - LOG(WARNING) << __func__ - << "Failed to read. Exception:" << read_int.exception(); - fail = true; - } else { - auto length = read_int.result(); - VLOG(1) << __func__ << " length:" << length; - - if (length < 0 || length > FeatureFlags::GetInstance() - .GetFlags() - .connection_max_frame_length) { - // Ignore the failure because not only one client use this - // connection. - LOG(WARNING) << __func__ - << "Failed to read because received a invalid length " - << length << ", but continue to read."; - continue; - } - - bytes = physical_reader_->ReadExactly(length); - if (!bytes.ok()) { - LOG(WARNING) << __func__ - << "Read data exception:" << bytes.exception(); - fail = true; - } - } - if (fail) { - reader_thread_shutdown_barrier_->CountDown(); - return; - } - - ExceptionOr frame_exc = - multiplex::FromBytes(bytes.result()); - if (!frame_exc.ok()) { - HandleOfflineFrame(bytes.result()); - continue; - } - - if (!IsEnabled()) { - // The reader thread will only be enabled when local device - // supports multiplex if we received a multiplex frame from - // the remote, it means that the remote and the local both - // support multiplex as well. So it is safe to just turn on - // the feature at this point. - LOG(INFO) << __func__ - << " Received a multiplex frame while not enabled, enable " - "multiplex."; - Enable(); - } - const auto& frame = frame_exc.result(); - auto salted_service_id_hash = - ByteArray{std::move(frame.header().salted_service_id_hash())}; - auto service_id_hash_salt = frame.header().has_service_id_hash_salt() - ? frame.header().service_id_hash_salt() - : ""; - switch (frame.frame_type()) { - case MultiplexFrame::CONTROL_FRAME: - HandleControlFrame(salted_service_id_hash, service_id_hash_salt, - frame.control_frame()); - break; - case MultiplexFrame::DATA_FRAME: - VLOG(1) << "service_id_hash_salt: " << service_id_hash_salt; - HandleDataFrame(salted_service_id_hash, service_id_hash_salt, - frame.data_frame()); - break; - default: - LOG(WARNING) << __func__ - << " Received MultiplexFrame with unknown frame type " - << frame.frame_type(); - } - } - }); -} - -void MultiplexSocket::HandleOfflineFrame(const ByteArray& bytes) { - MutexLock lock(&virtual_socket_mutex_); - LOG(INFO) << __func__ << " Virtual_socket num:" << virtual_sockets_.size(); - if (virtual_sockets_.size() == 1) { - auto item = virtual_sockets_.begin(); - if (item->second == nullptr) { - LOG(WARNING) << "Expected one live socket, but found null."; - return; - } - LOG(INFO) << __func__ << "FeedIncomingData:" << std::string(bytes); - item->second->FeedIncomingData(Base64Utils::IntToBytes(bytes.size())); - item->second->FeedIncomingData(bytes); - } -} - -void MultiplexSocket::HandleControlFrame( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - const MultiplexControlFrame& frame) { - switch (frame.control_frame_type()) { - case MultiplexControlFrame::CONNECTION_REQUEST: - RunOffloadThread("CONNECTION_REQUEST", [this, salted_service_id_hash, - service_id_hash_salt] { - HandleConnectionRequest(salted_service_id_hash, service_id_hash_salt); - }); - break; - case MultiplexControlFrame::CONNECTION_RESPONSE: - LOG(INFO) << __func__ << "Received an CONNECTION_RESPONSE frame." - << " salted_service_id_hash: " - << std::string(salted_service_id_hash) - << ", service_id_hash_salt: " << service_id_hash_salt - << ", ConnectionResponseCode: " - << frame.connection_response_frame().connection_response_code(); - - RunOffloadThread("CONNECTION_RESPONSE", [this, salted_service_id_hash, - service_id_hash_salt, - frame = frame] { - HandleConnectionResponse(salted_service_id_hash, service_id_hash_salt, - frame.connection_response_frame()); - }); - break; - case MultiplexControlFrame::DISCONNECTION: - // The virtual socket will be closed in the offload thread, so don't run - // the thread here. - HandleDisconnection(salted_service_id_hash); - break; - default: - LOG(WARNING) << __func__ << "Received an unknown frame type " - << frame.control_frame_type(); - break; - } -} - -void MultiplexSocket::HandleConnectionRequest( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt) { - if (!IsEnabled()) { - LOG(WARNING) << "Received a CONNECTION_REQUEST frame on medium " - << Medium_Name(medium_) - << " but status is disabled, ignore it."; - return; - } - - std::string salted_service_id_hash_key = - GenerateServiceIdHashKey(salted_service_id_hash); - MultiplexIncomingConnectionCb* incoming_connection_callback = nullptr; - std::string listening_service_id = ""; - for (auto& [service_id_medium_pair, callback] : - GetIncomingConnectionCallbacks()) { - if (GenerateServiceIdHashWithSalt(service_id_medium_pair.first, - service_id_hash_salt) == - salted_service_id_hash) { - incoming_connection_callback = &callback; - listening_service_id = service_id_medium_pair.first; - } - } - - if (incoming_connection_callback == nullptr || listening_service_id.empty()) { - LOG(INFO) << "There's no client listening for hash salt : " - << service_id_hash_salt - << ", hash key : " << salted_service_id_hash_key << " on medium " - << Medium_Name(medium_); - - LOG(INFO) << "The size of incomingConnectionCallbacks : " - << GetIncomingConnectionCallbacks().size(); - if (!multiplex_output_stream_.WriteConnectionResponseFrame( - salted_service_id_hash, service_id_hash_salt, - ConnectionResponseFrame::NOT_LISTENING)) { - LOG(INFO) << __func__ << "Failed to write NOT_LISTENING frame."; - } - return; - } - LOG(INFO) << "Accept new virtual socket request service ID : " - << listening_service_id << ", hash salt : " << service_id_hash_salt - << ", hash key : " << salted_service_id_hash_key << " on medium " - << Medium_Name(medium_); - - if (!multiplex_output_stream_.WriteConnectionResponseFrame( - salted_service_id_hash, service_id_hash_salt, - ConnectionResponseFrame::CONNECTION_ACCEPTED)) { - LOG(INFO) << "Failed to write CONNECTION_ACCEPTED frame."; - return; - } - - LOG(INFO) - << "EstablishVirtualSocket after local device accept the connection " - "with serviceId=" - << listening_service_id; - MediumSocket* virtual_socket = - CreateVirtualSocket(listening_service_id, service_id_hash_salt); - (*incoming_connection_callback)(std::move(listening_service_id), - virtual_socket); -} - -void MultiplexSocket::HandleConnectionResponse( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - const ConnectionResponseFrame& frame) { - LOG(INFO) << __func__ - << "connection_response_code: " << frame.connection_response_code(); - for (auto& [service_id, future] : connection_response_futures_) { - if (GenerateServiceIdHashWithSalt(service_id, service_id_hash_salt) == - salted_service_id_hash) { - if (future != nullptr) { - future->Set(frame.connection_response_code()); - LOG(INFO) << __func__ << "Set the future for serviceId=" << service_id - << ", serviceIdHashSalt=" << service_id_hash_salt - << " with response code=" << frame.connection_response_code(); - return; - } - } - } - - LOG(WARNING) - << __func__ - << "Received a CONNECTION_RESPONSE frame but no client waiting for " - "service ID Hash Key" - << GenerateServiceIdHashKey(salted_service_id_hash); -} - -void MultiplexSocket::HandleDisconnection( - const ByteArray& salted_service_id_hash) { - std::string salted_service_id_hash_key = - GenerateServiceIdHashKey(salted_service_id_hash); - MediumSocket* virtual_socket_to_close = nullptr; - { - MutexLock lock(&virtual_socket_mutex_); - auto item = virtual_sockets_.find(salted_service_id_hash_key); - if (item != virtual_sockets_.end()) { - LOG(INFO) - << "Received a DISCONNECTION frame to disconnect virtual socket for " - "salted service ID Hash Key " - << salted_service_id_hash_key; - virtual_socket_to_close = item->second.get(); - } else { - LOG(WARNING) - << "Received a DISCONNECTION frame but there's no alive socket to " - "disconnect for service ID Hash Key " - << salted_service_id_hash_key; - } - } - // Close the virtual socket outside of the mutex lock because - // OnVirtualSocketClosed will lock the mutex. - if (virtual_socket_to_close != nullptr) { - virtual_socket_to_close->Close(); - } -} - -void MultiplexSocket::HandleDataFrame(const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - const MultiplexDataFrame& frame) { - std::string salted_service_id_hash_key = - GenerateServiceIdHashKey(salted_service_id_hash); - MediumSocket* virtual_socket = nullptr; - if (service_id_hash_salt.empty()) { - { - MutexLock lock(&virtual_socket_mutex_); - auto item = virtual_sockets_.find(salted_service_id_hash_key); - if (item != virtual_sockets_.end()) { - virtual_socket = item->second.get(); - } - } - } else { - virtual_socket = - ReMapAndGetVirtualSocket(salted_service_id_hash, service_id_hash_salt); - } - - if (virtual_socket != nullptr) { - VLOG(1) - << "Received a DATA frame to feed virtual socket for salted service ID " - "Hash Key " - << salted_service_id_hash_key; - virtual_socket->FeedIncomingData(ByteArray(frame.data())); - } else { - LOG(WARNING) - << "Received a DATA frame but there's no alive socket to feed for " - "salted service ID Hash Key " - << salted_service_id_hash_key; - } -} - -void MultiplexSocket::OnPhysicalSocketClosed() { - RunOffloadThread("Shutdown", [this]() { Shutdown(); }); -} - -void MultiplexSocket::OnVirtualSocketClosed(const std::string& service_id) { - LOG(INFO) << __func__ << " for service_id:" << service_id; - CountDownLatch latch(1); - bool shutdown = false; - RunOffloadThread( - "VirtualSocketClosed", [this, service_id, &latch, &shutdown]() { - LOG(INFO) << "Try to close Virtual socket: " << service_id; - MediumSocket* virtual_socket = GetVirtualSocket(service_id); - { - MutexLock lock(&virtual_socket_mutex_); - LOG(INFO) << "virtual_socket:" << virtual_socket; - if (virtual_socket != nullptr) { - auto salted_service_id_hash_key = GenerateServiceIdHashKeyWithSalt( - service_id, - multiplex_output_stream_.GetServiceIdHashSalt(service_id)); - multiplex_output_stream_.Close(service_id); - virtual_sockets_.erase(salted_service_id_hash_key); - LOG(INFO) << "Erase Virtual socket with service_id: " << service_id - << ", hash_key: " << salted_service_id_hash_key; - ListVirtualSocket(); - - if (virtual_sockets_.empty()) { - LOG(INFO) << "Close the physical socket because all virtual " - "sockets disconnected."; - is_shutting_down_.Set(true); - Shutdown(); - shutdown = true; - } - } else { - LOG(INFO) << "Virtual socket(" << service_id << ") not found"; - } - } - latch.CountDown(); - }); - - if (!latch.Await(absl::Milliseconds(1000)).result()) { - LOG(ERROR) << "Timeout to close virtual socket"; - } - - if (shutdown) { - LOG(INFO) - << "Shutdown single_thread_offloader_ and physical_reader_thread_"; - single_thread_offloader_.Shutdown(); - physical_reader_thread_.Shutdown(); - is_shutting_down_.Set(false); - } -} - -MediumSocket* MultiplexSocket::ReMapAndGetVirtualSocket( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt) { - std::string salted_service_id_hash_key = - GenerateServiceIdHashKey(salted_service_id_hash); - VLOG(1) << "ReMapAndGetVirtualSocket with serviceIdHashSalt=" - << service_id_hash_salt - << ", saltedServiceIdHashKey=" << salted_service_id_hash_key; - { - MutexLock lock(&virtual_socket_mutex_); - for (auto& [hash_key, virtual_socket] : virtual_sockets_) { - auto output_stream = - down_cast( - &(virtual_socket->GetOutputStream())); - if (output_stream == nullptr) { - continue; - } - if (!output_stream->IsFirstVirtualOutputStream()) { - continue; - } - if ((service_id_hash_salt == kFakeSalt) || - (hash_key == salted_service_id_hash_key)) { - return virtual_socket.get(); - } else { - LOG(INFO) << "Remap the virtualSockets."; - output_stream->SetserviceIdHashSalt(service_id_hash_salt); - auto virtual_socket_tmp = virtual_socket; - LOG(INFO) << "virtual_socket before:" << virtual_socket; - virtual_sockets_.erase(hash_key); - virtual_sockets_[salted_service_id_hash_key] = virtual_socket_tmp; - ListVirtualSocket(); - return virtual_socket_tmp.get(); - } - } - } - - LOG(INFO) << "Failed to remap the virtualSockets."; - return nullptr; -} - -void MultiplexSocket::RunOffloadThread(const std::string& name, - absl::AnyInvocable runnable) { - single_thread_offloader_.Execute(name, std::move(runnable)); -} - -void MultiplexSocket::Shutdown() { - LOG(INFO) << __func__ << " start"; - if (is_shutdown_) { - LOG(INFO) << __func__ << " Already shutdown"; - return; - } - - multiplex_output_stream_.Shutdown(); - physical_socket_ptr_->Close(); - - if (reader_thread_shutdown_barrier_) { - reader_thread_shutdown_barrier_->Await(kTimeoutForReaderThreadStop); - } - - GetIncomingConnectionCallbacks().clear(); - connection_response_futures_.clear(); - - is_shutdown_ = true; - enabled_.Set(false); - LOG(INFO) << __func__ << " end"; -} - -void MultiplexSocket::ShutdownAll() { - LOG(INFO) << __func__ << " start"; - if (is_shutdown_) { - LOG(WARNING) << __func__ << " Already shutdown"; - return; - } - - CountDownLatch latch(1); - RunOffloadThread("VirtualSocketClosed", [this, &latch]() { - { - MutexLock lock(&virtual_socket_mutex_); - multiplex_output_stream_.CloseAll(); - virtual_sockets_.clear(); - - Shutdown(); - } - latch.CountDown(); - }); - - if (!latch - .Await(FeatureFlags::GetInstance() - .GetFlags() - .mediums_frame_write_timeout_millis + - absl::Milliseconds(100)) - .result()) { - LOG(ERROR) << "Timeout to close virtual socket"; - } - - LOG(INFO) << "Shutdown single_thread_offloader_ and physical_reader_thread_"; - single_thread_offloader_.Shutdown(); - physical_reader_thread_.Shutdown(); - LOG(INFO) << __func__ << " end"; -} - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/multiplex/multiplex_socket.h b/connections/implementation/mediums/multiplex/multiplex_socket.h deleted file mode 100644 index 5e65c5d4..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_socket.h +++ /dev/null @@ -1,222 +0,0 @@ -// 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 CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_SOCKET_H_ -#define CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_SOCKET_H_ - -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/functional/any_invocable.h" -#include "connections/implementation/mediums/multiplex/multiplex_output_stream.h" -#include "connections/medium_selector.h" -#include "internal/platform/atomic_boolean.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/future.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/platform/socket.h" -#include "proto/connections_enums.pb.h" -#include "proto/mediums/multiplex_frames.pb.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -using MultiplexEnbaleCb = absl::AnyInvocable; -using MultiplexIncomingConnectionCb = absl::AnyInvocable; - -class MultiplexSocket { - public: - MultiplexSocket(const MultiplexSocket&) = delete; - MultiplexSocket& operator=(const MultiplexSocket&) = delete; - ~MultiplexSocket() { ShutdownAll(); }; - - // Creates a new incoming MultiplexSocket. - static MultiplexSocket* CreateIncomingSocket( - std::shared_ptr physical_socket, - const std::string& service_id, std::int32_t first_frame_len); - // Creates a new outgoing MultiplexSocket. - static MultiplexSocket* CreateOutgoingSocket( - std::shared_ptr physical_socket, - const std::string& service_id, const std::string& service_id_hash_salt); - - // Creates a new outgoing MultiplexSocket with default service_id_hash_salt. - static MultiplexSocket* CreateOutgoingSocket( - std::shared_ptr physical_socket, - const std::string& service_id); - - // A Table of service Id as row key, medium type as column key, and - // MultiplexIncomingConnectionCb as value. Non-empty while the client starts - // listening for incoming virtual socket. The MultiplexIncomingConnectionCb - // will be called when the incoming virtual socket is established. - static absl::flat_hash_map< - std::pair, - MultiplexIncomingConnectionCb>& - GetIncomingConnectionCallbacks(); - - // Listens for incoming connection through multiplex for specified {@code - // service_id} on medium - // {@code type}. Should register the callback before new the MultiplexSocket. - static void ListenForIncomingConnection( - const std::string& service_id, - ::location::nearby::proto::connections::Medium type, - absl::AnyInvocable - incoming_connection_cb); - - // Stops listening for incoming multiplex connection for {@code service_id} on - // medium {@code type}. - static void StopListeningForIncomingConnection( - const std::string& service_id, - ::location::nearby::proto::connections::Medium type); - - bool IsEnabled() { return enabled_.Get(); } - void Enable() { - LOG(INFO) << "Enable the Multiplex MediumSocket."; - enabled_.Set(true); - } - - // Gets the virtual socket by service id. - MediumSocket* GetVirtualSocket(const std::string& service_id); - // Gets the virtual socket count. - int GetVirtualSocketCount(); - - void ListVirtualSocket() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(virtual_socket_mutex_); - - // Establishes the virtual socket by service id. - MediumSocket* EstablishVirtualSocket(const std::string& service_id); - // Shuts down the multiplex socket. - void Shutdown(); - bool IsShutdown() { return is_shutdown_; } - void SetShutdown(bool is_shutdown) { is_shutdown_ = is_shutdown; } - void ShutdownAll(); - - private: - explicit MultiplexSocket(std::shared_ptr physical_socket); - - // Creates the first virtual socket for the service id. The first virtual - // socket is created by the sender. - MediumSocket* CreateFirstVirtualSocket( - const std::string& service_id, const std::string& service_id_hash_salt); - // Creates the virtual socket for the service id. - MediumSocket* CreateVirtualSocket(const std::string& service_id, - const std::string& service_id_hash_salt); - // Registers the connection response future for the service id. - std::shared_ptr> - RegisterConnectionResponse(const std::string& service_id); - // Unregisters the connection response future for the service id. - void UnRegisterConnectionResponse(const std::string& service_id); - // Starts the reader thread to read the incoming MultiplexFrame from the - // physical socket. - void StartReaderThread(std::int32_t first_frame_len); - // Handles the offline frame from the physical socket. - void HandleOfflineFrame(const ByteArray& bytes); - // Handles the control frame from the physical socket. - void HandleControlFrame( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - const ::location::nearby::mediums::MultiplexControlFrame& frame); - // Handles the connection request frame from the physical socket. - void HandleConnectionRequest(const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt); - // Handles the connection response frame from the physical socket. - void HandleConnectionResponse( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - const ::location::nearby::mediums::ConnectionResponseFrame& frame); - // Handles the disconnection frame from the physical socket. - void HandleDisconnection(const ByteArray& salted_service_id_hash); - // Handles the data frame from the physical socket. - void HandleDataFrame( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt, - const ::location::nearby::mediums::MultiplexDataFrame& frame); - // Handles the physical socket closed. - void OnPhysicalSocketClosed(); - // Remaps and gets the virtual socket by service id hash. - MediumSocket* ReMapAndGetVirtualSocket( - const ByteArray& salted_service_id_hash, - const std::string& service_id_hash_salt); - // Handles the virtual socket closed. - void OnVirtualSocketClosed(const std::string& service_id); - // Runs the offload thread. - void RunOffloadThread(const std::string& name, - absl::AnyInvocable runnable); - - // The physical socket connect to the remote device. - std::shared_ptr physical_socket_ptr_; - - // The output stream to manage all outgoing frames from all clients. - MultiplexOutputStream multiplex_output_stream_; - // The {@link InputStream} of the physical socket. It is used to read the - // incoming MultiplexFrame from the physical socket. - InputStream* physical_reader_; - // The medium type of the physical socket. - Medium medium_; - - // The callback to enable the MultiplexSocket. - std::shared_ptr> enable_cb_ = - std::make_shared>([this]() { Enable(); }); - - // A map of service Id -> {@link SettableFuture} for waiting the - // ConnectionResponse. Non-empty while requesting the virtual socket. - absl::flat_hash_map>> - connection_response_futures_; - - // A map of service Id hash key -> virtual socket. Non-empty while at least - // one virtual socket alive. Class derived from "MediumSocket" should define a - // pointer to the virtual sockets map. When here's any virtual socket - // operation, it will be reflected in both derived MediumSocket class and - // MultiplexSocket object - mutable Mutex virtual_socket_mutex_; - absl::flat_hash_map> - virtual_sockets_ ABSL_GUARDED_BY(virtual_socket_mutex_); - - // The thread to receive incoming MultiplexFrame from the physical socket. - SingleThreadExecutor physical_reader_thread_; - // The single thread we throw the potentially blocking work on to. - SingleThreadExecutor single_thread_offloader_; - - // The status of the MultiplexSocket enabled or disabled, it depends on both - // Sender and Receiver supports MultiplexSocket or not. Default disabled and - // enable it once two devices negotiated finished. - AtomicBoolean enabled_{false}; - - // If the socket is already shutdown and no longer in use. - bool is_shutdown_ = false; - static AtomicBoolean is_shutting_down_; - std::unique_ptr reader_thread_shutdown_barrier_; -}; - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif // CORE_INTERNAL_MEDIUMS_MULTIPLEX_MULTIPLEX_SOCKET_H_ diff --git a/connections/implementation/mediums/multiplex/multiplex_socket_test.cc b/connections/implementation/mediums/multiplex/multiplex_socket_test.cc deleted file mode 100644 index 3b523d20..00000000 --- a/connections/implementation/mediums/multiplex/multiplex_socket_test.cc +++ /dev/null @@ -1,451 +0,0 @@ -// 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 "connections/implementation/mediums/multiplex/multiplex_socket.h" - -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "absl/container/flat_hash_map.h" -#include "absl/strings/string_view.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/multiplex/multiplex_frames.h" -#include "connections/implementation/offline_frames.h" -#include "internal/platform/base64_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/exception.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/logging.h" -#include "internal/platform/output_stream.h" -#include "internal/platform/pipe.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/platform/socket.h" -#include "proto/connections_enums.proto.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace multiplex { - -constexpr absl::string_view SERVICE_ID_1 = "serviceId_1"; -constexpr absl::string_view SERVICE_ID_2 = "serviceId_2"; - -using location::nearby::mediums::ConnectionResponseFrame; -using location::nearby::mediums::MultiplexControlFrame; -using location::nearby::mediums::MultiplexFrame; -using location::nearby::proto::connections::Medium; -using location::nearby::proto::connections::Medium_Name; - -// A fake socket for testing. -class FakeSocket : public MediumSocket { - public: - explicit FakeSocket(Medium medium) : MediumSocket(medium) { - pipe_1_ = CreatePipe(); - reader_1_ = std::move(pipe_1_.first); - writer_1_ = std::move(pipe_1_.second); - pipe_2_ = CreatePipe(); - reader_2_ = std::move(pipe_2_.first); - writer_2_ = std::move(pipe_2_.second); - LOG(WARNING) << "Physical Socket Medium:" << Medium_Name(GetMedium()); - }; - ~FakeSocket() override = default; - - FakeSocket(const FakeSocket&) = default; - FakeSocket& operator=(const FakeSocket&) = default; - - /** - * The constructor for a virtual socket which own the virtual {@link - * OutputStream} and {@link InputStream}. - */ - explicit FakeSocket(Medium medium, OutputStream* virtualOutputStream) - : MediumSocket(medium), - is_virtual_socket_(true), - virtual_output_stream_(virtualOutputStream) { - pipe_1_ = CreatePipe(); - reader_1_ = std::move(pipe_1_.first); - writer_1_ = std::move(pipe_1_.second); - pipe_2_ = CreatePipe(); - reader_2_ = std::move(pipe_2_.first); - writer_2_ = std::move(pipe_2_.second); - } - - InputStream& GetInputStream() override { return *reader_1_; } - OutputStream& GetOutputStream() override { - return IsVirtualSocket() ? *virtual_output_stream_ - : *writer_2_; - } Exception Close() override { - if (IsVirtualSocket()) { - LOG(INFO) << "Multiplex: Closing virtual socket: " << this; - CloseLocal(); - return {Exception::kSuccess}; - } - LOG(INFO) << "Multiplex: Closing physical socket: " << this; - reader_1_->Close(); - reader_2_->Close(); - writer_1_->Close(); - writer_2_->Close(); - return {Exception::kSuccess}; - } - - MediumSocket* CreateVirtualSocket( - const std::string& salted_service_id_hash_key, OutputStream* outputstream, - Medium medium, - absl::flat_hash_map>* - virtual_sockets_ptr) override { - if (IsVirtualSocket()) { - LOG(WARNING) - << "Creating the virtual socket on a virtual socket is not allowed."; - return nullptr; - } - - auto virtual_socket = std::make_shared(medium, outputstream); - LOG(WARNING) << "Created the virtual socket for Medium: " - << Medium_Name(virtual_socket->GetMedium()); - - if (virtual_sockets_ptr_ == nullptr) { - virtual_sockets_ptr_ = virtual_sockets_ptr; - } - - (*virtual_sockets_ptr_)[salted_service_id_hash_key] = virtual_socket; - LOG(INFO) << "virtual_sockets_ size: " << virtual_sockets_ptr_->size(); - return virtual_socket.get(); - } - - void FeedIncomingData(ByteArray data) override { - bytes_read_future_.Set(data); - LOG(INFO) << "FeedIncomingData. Size of receive data: " << data.size() - << ", bytes content:" << std::string(data); - } - - bool IsVirtualSocket() override { return is_virtual_socket_; } - Future& GetByteReadFuture() { return bytes_read_future_; } - - std::pair, std::unique_ptr> - pipe_1_; - std::unique_ptr reader_1_; - std::unique_ptr writer_1_; - std::pair, std::unique_ptr> - pipe_2_; - std::unique_ptr reader_2_; - std::unique_ptr writer_2_; - - private: - bool is_virtual_socket_ = false; - Future bytes_read_future_; - absl::flat_hash_map>* - virtual_sockets_ptr_ = nullptr; - OutputStream* virtual_output_stream_ = nullptr; -}; - -TEST(MultiplexSocketTest, CreateIncomingSocketSuccess) { - auto fake_socket_ptr = std::make_shared(Medium::BLUETOOTH); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1), - Medium::BLUETOOTH); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2), - Medium::BLUETOOTH); - MultiplexSocket::ListenForIncomingConnection( - std::string(SERVICE_ID_1), Medium::BLUETOOTH, - [](const std::string& service_id, MediumSocket* socket) { - LOG(INFO) << "Incoming connection for service_id: " << service_id; - }); - MultiplexSocket::ListenForIncomingConnection( - std::string(SERVICE_ID_2), Medium::BLUETOOTH, - [](const std::string& service_id, MediumSocket* socket) { - LOG(INFO) << "Incoming connection for service_id: " << service_id; - }); - - MultiplexSocket* multiplex_socket_incoming = - MultiplexSocket::CreateIncomingSocket( - fake_socket_ptr, std::string(SERVICE_ID_1), /*first_frame_len*/ 0); - ASSERT_NE(multiplex_socket_incoming, nullptr); - MultiplexSocket* multiplex_socket_incoming_2 = - MultiplexSocket::CreateIncomingSocket( - fake_socket_ptr, std::string(SERVICE_ID_2), /*first_frame_len*/ 0); - ASSERT_EQ(multiplex_socket_incoming_2, multiplex_socket_incoming); - - FakeSocket* virtual_socket = - (FakeSocket*)multiplex_socket_incoming->GetVirtualSocket( - std::string(SERVICE_ID_1)); - if (virtual_socket == nullptr) { - LOG(INFO) << "Virtual socket not found for " << SERVICE_ID_1; - return; - } - - SingleThreadExecutor executor; - FakeSocket* socket = fake_socket_ptr.get(); - executor.Execute([socket]() { - ByteArray connection_req_frame = parser::ForConnectionRequestConnections( - {}, { - .local_endpoint_id = "endpoint1", - .local_endpoint_info = ByteArray("endpoint1 info"), - }); - auto& writer = socket->writer_1_; - LOG(INFO) << "writer_1_ Write start"; - Base64Utils::WriteInt(writer.get(), connection_req_frame.size()); - writer->Write(connection_req_frame.AsStringView()); - writer->Flush(); - LOG(INFO) << "writer_1_ Write end"; - }); - - ExceptionOr result = virtual_socket->GetByteReadFuture().Get(); - if (!result.ok()) { - ADD_FAILURE() << "Read error: " << result.GetException().value; - } - ByteArray data = result.result(); - LOG(INFO) << "Received " << data.size() << " bytes of data."; - EXPECT_NE(data.size(), 0); - absl::SleepFor(absl::Milliseconds(100)); - - EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 1); - virtual_socket->Close(); - EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 0); - multiplex_socket_incoming->ShutdownAll(); -} - -TEST(MultiplexSocketTest, CreateFail_MediumNotSupport) { - auto fake_socket_ptr = std::make_shared(Medium::WEB_RTC); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1), - Medium::WEB_RTC); - MultiplexSocket* multiplex_socket_incoming = - MultiplexSocket::CreateIncomingSocket( - fake_socket_ptr, std::string(SERVICE_ID_1), /*first_frame_len*/ 0); - - ASSERT_EQ(multiplex_socket_incoming, nullptr); -} - -TEST(MultiplexSocketTest, CreateIncomingVirtualSocketSuccess) { - auto fake_socket_ptr = std::make_shared(Medium::WIFI_LAN); - - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1), - Medium::WIFI_LAN); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2), - Medium::WIFI_LAN); - MultiplexSocket::ListenForIncomingConnection( - std::string(SERVICE_ID_1), Medium::WIFI_LAN, - [](const std::string& service_id, MediumSocket* socket) { - LOG(INFO) << "Incoming connection for service_id: " << service_id; - }); - MultiplexSocket::ListenForIncomingConnection( - std::string(SERVICE_ID_2), Medium::WIFI_LAN, - [](const std::string& service_id, MediumSocket* socket) { - LOG(INFO) << "Incoming connection for service_id: " << service_id; - }); - - MultiplexSocket* multiplex_socket_incoming = - MultiplexSocket::CreateIncomingSocket( - fake_socket_ptr, std::string(SERVICE_ID_1), /*first_frame_len*/ 0); - ASSERT_NE(multiplex_socket_incoming, nullptr); - - FakeSocket* virtual_socket = - (FakeSocket*)multiplex_socket_incoming->GetVirtualSocket( - std::string(SERVICE_ID_1)); - if (virtual_socket == nullptr) { - LOG(INFO) << "Virtual socket not found for " << SERVICE_ID_1; - return; - } - - SingleThreadExecutor executor; - FakeSocket* socket = fake_socket_ptr.get(); - executor.Execute([socket]() { - ByteArray connection_req_frame = ForConnectionRequest( - std::string(SERVICE_ID_2), "J7frzSmHK-VBTHjCKpf4ew"); - auto& writer = socket->writer_1_; - LOG(INFO) << "writer_1_ Write start"; - Base64Utils::WriteInt(writer.get(), connection_req_frame.size()); - writer->Write(connection_req_frame.AsStringView()); - writer->Flush(); - LOG(INFO) << "writer_1_ Write end"; - }); - absl::SleepFor(absl::Milliseconds(100)); - - EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 2); - virtual_socket->Close(); - EXPECT_EQ(multiplex_socket_incoming->GetVirtualSocketCount(), 1); - multiplex_socket_incoming->ShutdownAll(); -} - -TEST(MultiplexSocketTest, - EstablishVirtualSocket_Timeout_BecauseNoConnectionResponse) { - auto fake_socket_ptr = std::make_shared(Medium::WIFI_LAN); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1), - Medium::WIFI_LAN); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2), - Medium::WIFI_LAN); - MultiplexSocket* multiplex_socket = MultiplexSocket::CreateOutgoingSocket( - fake_socket_ptr, std::string(SERVICE_ID_1)); - ASSERT_NE(multiplex_socket, nullptr); - MultiplexSocket* multiplex_socket_2 = MultiplexSocket::CreateOutgoingSocket( - fake_socket_ptr, std::string(SERVICE_ID_2)); - ASSERT_EQ(multiplex_socket_2, multiplex_socket); - multiplex_socket->Enable(); - FakeSocket* virtual_socket = (FakeSocket*)multiplex_socket->GetVirtualSocket( - std::string(SERVICE_ID_1)); - if (virtual_socket == nullptr) { - LOG(INFO) << "Virtual socket not found for " << SERVICE_ID_1; - return; - } - - SingleThreadExecutor establish_socket_executor; - establish_socket_executor.Execute([&multiplex_socket]() { - LOG(INFO) << "EstablishVirtualSocket"; - MediumSocket* socket = - multiplex_socket->EstablishVirtualSocket(std::string(SERVICE_ID_2)); - LOG(INFO) << "EstablishVirtualSocket finished"; - EXPECT_EQ(socket, nullptr); - }); - - SingleThreadExecutor read_executor; - read_executor.Execute([&multiplex_socket, &fake_socket_ptr]() { - auto reader = fake_socket_ptr->reader_2_.get(); - LOG(INFO) << "reader_2_ Read start"; - ExceptionOr read_int = Base64Utils::ReadInt(reader); - if (!read_int.ok()) { - ADD_FAILURE() << "Failed to read. Exception:" << read_int.exception(); - } - auto length = read_int.result(); - LOG(INFO) << " length:" << length; - EXPECT_GT(length, 0); - EXPECT_EQ(multiplex_socket->GetVirtualSocket(std::string(SERVICE_ID_2)), - nullptr); - }); - - absl::SleepFor(absl::Milliseconds(300)); - EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 1); - virtual_socket->Close(); - EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 0); - multiplex_socket->ShutdownAll(); -} - -TEST(MultiplexSocketTest, EstablishVirtualSocket_RemoteAccepted) { - auto fake_socket_ptr = std::make_shared(Medium::BLUETOOTH); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_1), - Medium::BLUETOOTH); - MultiplexSocket::StopListeningForIncomingConnection(std::string(SERVICE_ID_2), - Medium::BLUETOOTH); - - MultiplexSocket* multiplex_socket = MultiplexSocket::CreateOutgoingSocket( - fake_socket_ptr, std::string(SERVICE_ID_1)); - ASSERT_NE(multiplex_socket, nullptr); - MultiplexSocket* multiplex_socket_2 = MultiplexSocket::CreateOutgoingSocket( - fake_socket_ptr, std::string(SERVICE_ID_2)); - ASSERT_EQ(multiplex_socket_2, multiplex_socket); - - SingleThreadExecutor executor; - CountDownLatch latch(1); - executor.Execute([&multiplex_socket, &latch]() { - LOG(INFO) << "EstablishVirtualSocket"; - MediumSocket* socket = - multiplex_socket->EstablishVirtualSocket(std::string(SERVICE_ID_2)); - EXPECT_EQ(socket, nullptr); - latch.CountDown(); - }); - latch.Await(); - - multiplex_socket->Enable(); - executor.Execute([&multiplex_socket]() { - LOG(INFO) << "EstablishVirtualSocket"; - MediumSocket* socket = - multiplex_socket->EstablishVirtualSocket(std::string(SERVICE_ID_2)); - EXPECT_NE(socket, nullptr); - }); - - auto reader = fake_socket_ptr->reader_2_.get(); - LOG(INFO) << "reader_2_ Waiting for CONNECTION_REQUEST frame."; - ExceptionOr read_int = Base64Utils::ReadInt(reader); - if (!read_int.ok()) { - ADD_FAILURE() << "Failed to read length.Exception:" << read_int.exception(); - } - auto length = read_int.result(); - if (length < 0 || - length > - FeatureFlags::GetInstance().GetFlags().connection_max_frame_length) { - ADD_FAILURE() << "Invalid length:" << length; - } - - auto bytes = reader->ReadExactly(length); - if (!bytes.ok()) { - ADD_FAILURE() << "Failed to read frame. Exception:" << bytes.exception(); - } - length = read_int.result(); - if (length < 0 || - length > - FeatureFlags::GetInstance().GetFlags().connection_max_frame_length) { - ADD_FAILURE() << "Invalid frame length:" << length; - } - - ExceptionOr frame_exc = multiplex::FromBytes(bytes.result()); - if (!frame_exc.ok()) { - ADD_FAILURE() << "Failed to parse MultiplexFrame. Exception:" - << frame_exc.exception(); - } - auto frame = frame_exc.result(); - auto salted_service_id_hash = - ByteArray{std::move(frame.header().salted_service_id_hash())}; - auto service_id_hash_salt = frame.header().has_service_id_hash_salt() - ? frame.header().service_id_hash_salt() - : ""; - ASSERT_EQ(frame.frame_type(), MultiplexFrame::CONTROL_FRAME); - auto control_frame = frame.control_frame(); - ASSERT_EQ(control_frame.control_frame_type(), - MultiplexControlFrame::CONNECTION_REQUEST); - LOG(INFO) << "Recieved MultiplexControlFrame::CONNECTION_REQUEST " - "frame, now send CONNECTION_RESPONSE frame."; - - ByteArray connection_response_frame = - ForConnectionResponse(salted_service_id_hash, service_id_hash_salt, - ConnectionResponseFrame::CONNECTION_ACCEPTED); - auto& writer = fake_socket_ptr->writer_1_; - LOG(INFO) << "writer_1_ Write start"; - Base64Utils::WriteInt(writer.get(), connection_response_frame.size()); - writer->Write(connection_response_frame.AsStringView()); - writer->Flush(); - LOG(INFO) << "writer_1_ Write end"; - absl::SleepFor(absl::Milliseconds(100)); - EXPECT_NE(multiplex_socket->GetVirtualSocket(std::string(SERVICE_ID_2)), - nullptr); - - EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 2); - - LOG(INFO) << "Send Data frame on virtual socket for SERVICE_ID_2."; - ByteArray data_frame = - ForData(std::string(SERVICE_ID_2), service_id_hash_salt, - /*should_pass_salt=*/true, absl::string_view("data")); - Base64Utils::WriteInt(writer.get(), data_frame.size()); - writer->Write(data_frame.AsStringView()); - writer->Flush(); - absl::SleepFor(absl::Milliseconds(100)); - - LOG(INFO) << "Send disconnection frame on virtual socket for SERVICE_ID_2."; - ByteArray disconnect_frame = - ForDisconnection(std::string(SERVICE_ID_2), service_id_hash_salt); - Base64Utils::WriteInt(writer.get(), disconnect_frame.size()); - writer->Write(disconnect_frame.AsStringView()); - writer->Flush(); - absl::SleepFor(absl::Milliseconds(100)); - EXPECT_EQ(multiplex_socket->GetVirtualSocketCount(), 1); - - multiplex_socket->ShutdownAll(); -} - -} // namespace multiplex -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/webrtc.cc b/connections/implementation/mediums/webrtc.cc deleted file mode 100644 index c0fc4a56..00000000 --- a/connections/implementation/mediums/webrtc.cc +++ /dev/null @@ -1,788 +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 NO_WEBRTC - -#include "connections/implementation/mediums/webrtc.h" - -#include -#include -#include -#include -#include - -#include "absl/container/flat_hash_set.h" -#include "absl/functional/bind_front.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/webrtc/connection_flow.h" -#include "connections/implementation/mediums/webrtc/session_description_wrapper.h" -#include "connections/implementation/mediums/webrtc/signaling_frames.h" -#include "connections/implementation/mediums/webrtc_peer_id.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/cancelable_alarm.h" -#include "internal/platform/cancellation_flag.h" -#include "internal/platform/cancellation_flag_listener.h" -#include "internal/platform/exception.h" -#include "internal/platform/expected.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" -#include "internal/platform/runnable.h" -#include "internal/platform/webrtc.h" -#include "webrtc/api/jsep.h" - -namespace nearby { -namespace connections { -namespace mediums { - -namespace { -using ::location::nearby::connections::LocationHint; -using ::location::nearby::proto::connections::OperationResultCode; - -// The maximum amount of time to wait to connect to a data channel via WebRTC. -constexpr absl::Duration kDataChannelTimeout = absl::Seconds(10); - -// Delay between restarting signaling messenger to receive messages. -constexpr absl::Duration kRestartReceiveMessagesDuration = absl::Seconds(60); - -} // namespace - -WebRtc::WebRtc() : WebRtc(std::make_unique()) {} - -WebRtc::WebRtc(std::unique_ptr medium) - : medium_(std::move(medium)) {} - -WebRtc::~WebRtc() { - // This ensures that all pending callbacks are run before we reset the medium - // and we are not accepting new runnables. - single_thread_executor_.Shutdown(); - - // Stop accepting all connections - absl::flat_hash_set service_ids; - for (auto& item : accepting_connections_info_) { - service_ids.emplace(item.first); - } - for (const auto& service_id : service_ids) { - StopAcceptingConnections(service_id); - } -} - -std::string WebRtc::GetDefaultCountryCode() { - return medium_->GetDefaultCountryCode(); -} - -bool WebRtc::IsAvailable() { return medium_->IsValid(); } - -bool WebRtc::IsAcceptingConnections(const std::string& service_id) { - MutexLock lock(&mutex_); - return IsAcceptingConnectionsLocked(service_id); -} - -bool WebRtc::IsAcceptingConnectionsLocked(const std::string& service_id) { - return accepting_connections_info_.contains(service_id); -} - -bool WebRtc::StartAcceptingConnections(const std::string& service_id, - const WebrtcPeerId& self_peer_id, - const LocationHint& location_hint, - AcceptedConnectionCallback callback, - bool non_cellular) { - MutexLock lock(&mutex_); - if (!IsAvailable()) { - LOG(WARNING) << "Cannot start accepting WebRTC connections because " - "WebRTC is not available."; - return false; - } - - if (IsAcceptingConnectionsLocked(service_id)) { - LOG(WARNING) << "Cannot start accepting WebRTC connections because service " - << service_id << "is already accepting WebRTC connections."; - return false; - } - - // We'll track our state here, so that we're separated from the other services - // who may be also using WebRTC. - AcceptingConnectionsInfo info = AcceptingConnectionsInfo(); - info.self_peer_id = self_peer_id; - info.accepted_connection_callback = std::move(callback); - - medium_->SetNonCellular(non_cellular); - - // Create a new SignalingMessenger so that we can communicate w/ Tachyon. - info.signaling_messenger = - medium_->GetSignalingMessenger(self_peer_id.GetId(), location_hint); - if (!info.signaling_messenger->IsValid()) { - return false; - } - - // This registers ourselves w/ Tachyon, creating a room from the PeerId. - // This allows a remote device to message us over Tachyon. - if (!info.signaling_messenger->StartReceivingMessages( - absl::bind_front(&WebRtc::OnSignalingMessage, this, service_id), - absl::bind_front(&WebRtc::OnSignalingComplete, this, service_id))) { - info.signaling_messenger.reset(); - return false; - } - - // We'll automatically disconnect from Tachyon after 60sec. When this alarm - // fires, we'll recreate our room so we continue to receive messages. - info.restart_tachyon_receive_messages_alarm = - std::make_unique( - "restart_receiving_messages_webrtc", - std::bind(&WebRtc::ProcessRestartTachyonReceiveMessages, this, - service_id), - kRestartReceiveMessagesDuration, &single_thread_executor_); - - // Now that we're set up to receive messages, we'll save our state and return - // a successful result. - accepting_connections_info_.emplace(service_id, std::move(info)); - LOG(INFO) << "Started listening for WebRTC connections as " - << self_peer_id.GetId() << " on service " << service_id; - return true; -} - -void WebRtc::StopAcceptingConnections(const std::string& service_id) { - MutexLock lock(&mutex_); - if (!IsAcceptingConnectionsLocked(service_id)) { - LOG(WARNING) << "Cannot stop accepting WebRTC connections because service " - << service_id << "is not accepting WebRTC connections."; - return; - } - - // Grab our info from the map. - auto& info = accepting_connections_info_.find(service_id)->second; - - // Stop receiving messages from Tachyon. - info.signaling_messenger->StopReceivingMessages(); - info.signaling_messenger.reset(); - - // Cancel the scheduled alarm. - if (info.restart_tachyon_receive_messages_alarm && - info.restart_tachyon_receive_messages_alarm->IsValid()) { - info.restart_tachyon_receive_messages_alarm->Cancel(); - info.restart_tachyon_receive_messages_alarm.reset(); - } - - // If we had any in-progress connections that haven't materialized into full - // DataChannels yet, it's time to shut them down since they can't reach us - // anymore. - absl::flat_hash_set peer_ids; - for (auto& item : connection_flows_) { - peer_ids.emplace(item.first); - } - for (const auto& peer_id : peer_ids) { - const auto& entry = connection_flows_.find(peer_id); - // Skip outgoing connections in this step. Start/StopAcceptingConnections - // only deals with incoming connections. - if (requesting_connections_info_.contains(peer_id)) { - continue; - } - - // Skip fully connected connections in this step. If the connection was - // formed while we were accepting connections, then it will stay alive until - // it's explicitly closed. - if (!entry->second->CloseIfNotConnected()) { - continue; - } - - connection_flows_.erase(peer_id); - } - - // Clean up our state. We're now no longer listening for connections. - accepting_connections_info_.erase(service_id); - LOG(INFO) << "Stopped listening for WebRTC connections for service " - << service_id; -} - -ErrorOr WebRtc::Connect( - const std::string& service_id, const WebrtcPeerId& remote_peer_id, - const LocationHint& location_hint, CancellationFlag* cancellation_flag, - bool non_cellular) { - service_id_to_connect_attempts_count_map_[service_id] = 1; - medium_->SetNonCellular(non_cellular); - ErrorOr wrapper_result = { - Error(OperationResultCode::DETAIL_UNKNOWN)}; - while (service_id_to_connect_attempts_count_map_[service_id] <= - kConnectAttemptsLimit) { - if (cancellation_flag->Cancelled()) { - LOG(WARNING) << "Attempt #" - << service_id_to_connect_attempts_count_map_[service_id] - << ": Cannot Connect with WebRtc due to cancel."; - return { - Error(OperationResultCode:: - CLIENT_CANCELLATION_CANCEL_WEB_RTC_OUTGOING_CONNECTION)}; - } - - LOG(INFO) << "Attempt #" - << service_id_to_connect_attempts_count_map_[service_id] - << ": Beginning connection."; - wrapper_result = AttemptToConnect(service_id, remote_peer_id, location_hint, - cancellation_flag); - if (wrapper_result.has_value()) { - return std::move(wrapper_result.value()); - } - - service_id_to_connect_attempts_count_map_[service_id]++; - } - - LOG(WARNING) << "Giving up after " << kConnectAttemptsLimit << " attempts"; - return {Error(wrapper_result.error().operation_result_code().value())}; -} - -ErrorOr WebRtc::AttemptToConnect( - const std::string& service_id, const WebrtcPeerId& remote_peer_id, - const LocationHint& location_hint, CancellationFlag* cancellation_flag) { - ConnectionRequestInfo info = ConnectionRequestInfo(); - info.self_peer_id = WebrtcPeerId::FromRandom(); - Future socket_future = info.socket_future; - - // `listener` will go out of scope at the end of `AttemptToConnect`, and this - // is expected. This `listener` is tied to `socket_future` which we block on - // within this stack call, and will not go out of scope until the attempt - // is complete. - CancellationFlagListener listener( - cancellation_flag, [this, &service_id, &socket_future]() { - LOG(WARNING) << "Attempt # " - << service_id_to_connect_attempts_count_map_[service_id] - << " to connect with WebRtc stopped due to cancel."; - socket_future.SetException({Exception::kFailed}); - }); - - { - MutexLock lock(&mutex_); - if (!IsAvailable()) { - LOG(WARNING) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId() - << " because WebRTC is not available."; - return { - Error(OperationResultCode::MEDIUM_UNAVAILABLE_WEB_RTC_NOT_AVAILABLE)}; - } - - // Create a new ConnectionFlow for this connection attempt. - std::unique_ptr connection_flow = - CreateConnectionFlow(service_id, remote_peer_id); - if (!connection_flow) { - LOG(INFO) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId() - << " because we failed to create a ConnectionFlow."; - return {Error(OperationResultCode::NEARBY_WEB_RTC_CONNECTION_FLOW_NULL)}; - } - - // Create a new SignalingMessenger so that we can communicate over Tachyon. - info.signaling_messenger = medium_->GetSignalingMessenger( - info.self_peer_id.GetId(), location_hint); - if (!info.signaling_messenger->IsValid()) { - LOG(INFO) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId() - << " because we failed to create a SignalingMessenger."; - return { - Error(OperationResultCode:: - MISCELLEANEOUS_WEB_RTC_TACHYON_SIGNALING_MESSENGER_NULL)}; - } - - // This registers ourselves w/ Tachyon, creating a room from the PeerId. - // This allows a remote device to message us over Tachyon. - auto signaling_complete_callback = [socket_future](bool success) mutable { - if (!success) { - socket_future.SetException({Exception::kFailed}); - } - }; - if (!info.signaling_messenger->StartReceivingMessages( - absl::bind_front(&WebRtc::OnSignalingMessage, this, service_id), - signaling_complete_callback)) { - LOG(INFO) - << "Cannot connect to WebRTC peer " << remote_peer_id.GetId() - << " because we failed to start receiving messages over Tachyon."; - info.signaling_messenger.reset(); - return {Error(OperationResultCode:: - MISCELLEANEOUS_WEB_RTC_FAILED_TO_RECEIVE_MESSAGE)}; - } - - // Poke the remote device. This will cause them to send us an Offer. - if (!info.signaling_messenger->SendMessage( - remote_peer_id.GetId(), - webrtc_frames::EncodeReadyForSignalingPoke(info.self_peer_id))) { - LOG(INFO) << "Cannot connect to WebRTC peer " << remote_peer_id.GetId() - << " because we failed to poke the peer over Tachyon."; - info.signaling_messenger.reset(); - return {Error(OperationResultCode:: - CONNECTIVITY_WEB_RTC_CONNECT_TO_TACHYON_FAILURE)}; - } - - // Create a new ConnectionRequest entry. This map will be used later to look - // up state as we negotiate the connection over Tachyon. - requesting_connections_info_.emplace(remote_peer_id.GetId(), - std::move(info)); - connection_flows_.emplace(remote_peer_id.GetId(), - std::move(connection_flow)); - } - - // Wait for the connection to go through. Don't hold the mutex here so that - // we're not blocking necessary operations. - ExceptionOr socket_result = - socket_future.Get(kDataChannelTimeout); - - { - MutexLock lock(&mutex_); - - // Reclaim our info, since we had released ownership while talking to - // Tachyon. - auto& info = - requesting_connections_info_.find(remote_peer_id.GetId())->second; - - // Verify that the connection went through. - if (!socket_result.ok()) { - LOG(INFO) << "Failed to connect to WebRTC peer " - << remote_peer_id.GetId(); - RemoveConnectionFlow(remote_peer_id); - info.signaling_messenger.reset(); - requesting_connections_info_.erase(remote_peer_id.GetId()); - return {Error(OperationResultCode:: - CONNECTIVITY_WEB_RTC_CLIENT_SOCKET_CREATION_FAILURE)}; - } - - // Clean up our ConnectionRequest. - info.signaling_messenger.reset(); - requesting_connections_info_.erase(remote_peer_id.GetId()); - - // Return the result. - return socket_result.GetResult(); - } -} - -void WebRtc::ProcessLocalIceCandidate( - const std::string& service_id, const WebrtcPeerId& remote_peer_id, - const location::nearby::mediums::IceCandidate ice_candidate) { - MutexLock lock(&mutex_); - - // Check first if we have an outgoing request w/ this peer. As this request is - // tied to a specific peer, it takes precedence. - const auto& connection_request_entry = - requesting_connections_info_.find(remote_peer_id.GetId()); - if (connection_request_entry != requesting_connections_info_.end()) { - // Pass the ice candidate to the remote side. - if (!connection_request_entry->second.signaling_messenger->SendMessage( - remote_peer_id.GetId(), - webrtc_frames::EncodeIceCandidates( - connection_request_entry->second.self_peer_id, - {ice_candidate}))) { - LOG(INFO) << "Failed to send ice candidate to " << remote_peer_id.GetId(); - } - - LOG(INFO) << "Sent ice candidate to " << remote_peer_id.GetId(); - return; - } - - // Check next if we're expecting incoming connection requests. - const auto& accepting_connection_entry = - accepting_connections_info_.find(service_id); - if (accepting_connection_entry != accepting_connections_info_.end()) { - // Pass the ice candidate to the remote side. - // TODO(xlythe) Consider not blocking here, since this can eat into the - // connection time - if (!accepting_connection_entry->second.signaling_messenger->SendMessage( - remote_peer_id.GetId(), - webrtc_frames::EncodeIceCandidates( - accepting_connection_entry->second.self_peer_id, - {ice_candidate}))) { - LOG(INFO) << "Failed to send ice candidate to " << remote_peer_id.GetId(); - } - - LOG(INFO) << "Sent ice candidate to " << remote_peer_id.GetId(); - return; - } - - LOG(INFO) << "Skipping restart listening for tachyon inbox messages " - "since we are not accepting connections for service " - << service_id; -} - -void WebRtc::OnSignalingMessage(const std::string& service_id, - const ByteArray& message) { - OffloadFromThread("rtc-on-signaling-message", [this, service_id, message]() { - ProcessTachyonInboxMessage(service_id, message); - }); -} - -void WebRtc::OnSignalingComplete(const std::string& service_id, bool success) { - LOG(INFO) << "Signaling completed with status: " << success; - if (success) { - return; - } - - OffloadFromThread("rtc-on-signaling-complete", [this, service_id]() { - MutexLock lock(&mutex_); - const auto& info_entry = accepting_connections_info_.find(service_id); - if (info_entry == accepting_connections_info_.end()) { - return; - } - - if (info_entry->second.restart_accept_connections_count < - kRestartAcceptConnectionsLimit) { - ++info_entry->second.restart_accept_connections_count; - } else { - return; - } - - RestartTachyonReceiveMessages(service_id); - }); -} - -void WebRtc::ProcessTachyonInboxMessage(const std::string& service_id, - const ByteArray& message) { - MutexLock lock(&mutex_); - - // Attempt to parse the incoming message as a WebRtcSignalingFrame. - location::nearby::mediums::WebRtcSignalingFrame frame; - if (!frame.ParseFromString(std::string(message))) { - LOG(WARNING) << "Failed to parse signaling message."; - return; - } - - // Ensure that the frame is valid (no missing fields). - if (!frame.has_sender_id()) { - LOG(WARNING) << "Invalid WebRTC frame: Sender ID is missing."; - return; - } - WebrtcPeerId remote_peer_id = WebrtcPeerId(frame.sender_id().id()); - - // Depending on the message type, we'll respond as appropriate. - if (requesting_connections_info_.contains(remote_peer_id.GetId())) { - // This is from a peer we have an outgoing connection request with, so we'll - // only process the Answer path. - if (frame.has_offer()) { - ReceiveOffer(remote_peer_id, - SessionDescriptionWrapper( - webrtc_frames::DecodeOffer(frame).release())); - SendAnswer(remote_peer_id); - } else if (frame.has_ice_candidates()) { - ReceiveIceCandidates(remote_peer_id, - webrtc_frames::DecodeIceCandidates(frame)); - } else { - LOG(INFO) << "Received unknown WebRTC frame: ignoring."; - } - } else if (IsAcceptingConnectionsLocked(service_id)) { - // We don't have an outgoing connection request with this peer, but we are - // accepting incoming requests so we'll only process the Offer path. - if (frame.has_ready_for_signaling_poke()) { - SendOffer(service_id, remote_peer_id); - } else if (frame.has_answer()) { - ReceiveAnswer(remote_peer_id, - SessionDescriptionWrapper( - webrtc_frames::DecodeAnswer(frame).release())); - } else if (frame.has_ice_candidates()) { - ReceiveIceCandidates(remote_peer_id, - webrtc_frames::DecodeIceCandidates(frame)); - } else { - LOG(INFO) << "Received unknown WebRTC frame: ignoring."; - } - } else { - LOG(INFO) - << "Ignoring Tachyon message since we are not accepting connections."; - } -} - -void WebRtc::SendOffer(const std::string& service_id, - const WebrtcPeerId& remote_peer_id) { - std::unique_ptr connection_flow = - CreateConnectionFlow(service_id, remote_peer_id); - if (!connection_flow) { - LOG(INFO) << "Unable to send offer. Failed to create a ConnectionFlow."; - return; - } - - SessionDescriptionWrapper offer = connection_flow->CreateOffer(); - if (!offer.IsValid()) { - LOG(INFO) << "Unable to send offer. Failed to create our offer locally."; - RemoveConnectionFlow(remote_peer_id); - return; - } - - const webrtc::SessionDescriptionInterface& sdp = offer.GetSdp(); - if (!connection_flow->SetLocalSessionDescription(offer)) { - LOG(INFO) << "Unable to send offer. Failed to register our offer locally."; - RemoveConnectionFlow(remote_peer_id); - return; - } - - // Grab our info from the map. - auto& info = accepting_connections_info_.find(service_id)->second; - - // Pass the offer to the remote side. - if (!info.signaling_messenger->SendMessage( - remote_peer_id.GetId(), - webrtc_frames::EncodeOffer(info.self_peer_id, sdp))) { - LOG(INFO) - << "Unable to send offer. Failed to write the offer to the remote peer " - << remote_peer_id.GetId(); - RemoveConnectionFlow(remote_peer_id); - return; - } - - // Store the ConnectionFlow so that other methods can use it later. - connection_flows_.emplace(remote_peer_id.GetId(), std::move(connection_flow)); - LOG(INFO) << "Sent offer to " << remote_peer_id.GetId(); -} - -void WebRtc::ReceiveOffer(const WebrtcPeerId& remote_peer_id, - SessionDescriptionWrapper offer) { - const auto& entry = connection_flows_.find(remote_peer_id.GetId()); - if (entry == connection_flows_.end()) { - LOG(INFO) << "Unable to receive offer. Failed to create a ConnectionFlow."; - return; - } - - if (!entry->second->OnOfferReceived(offer)) { - LOG(INFO) << "Unable to receive offer. Failed to process the offer."; - RemoveConnectionFlow(remote_peer_id); - } -} - -void WebRtc::SendAnswer(const WebrtcPeerId& remote_peer_id) { - const auto& entry = connection_flows_.find(remote_peer_id.GetId()); - if (entry == connection_flows_.end()) { - LOG(INFO) << "Unable to send answer. Failed to create a ConnectionFlow."; - return; - } - - SessionDescriptionWrapper answer = entry->second->CreateAnswer(); - if (!answer.IsValid()) { - LOG(INFO) << "Unable to send answer. Failed to create our answer locally."; - RemoveConnectionFlow(remote_peer_id); - return; - } - - const webrtc::SessionDescriptionInterface& sdp = answer.GetSdp(); - if (!entry->second->SetLocalSessionDescription(answer)) { - LOG(INFO) - << "Unable to send answer. Failed to register our answer locally."; - RemoveConnectionFlow(remote_peer_id); - return; - } - - // Grab our info from the map. - const auto& connection_request_entry = - requesting_connections_info_.find(remote_peer_id.GetId()); - if (connection_request_entry == requesting_connections_info_.end()) { - LOG(INFO) << "Unable to send answer. Failed to find an outgoing " - "connection request."; - RemoveConnectionFlow(remote_peer_id); - return; - } - - // Pass the answer to the remote side. - if (!connection_request_entry->second.signaling_messenger->SendMessage( - remote_peer_id.GetId(), - webrtc_frames::EncodeAnswer( - connection_request_entry->second.self_peer_id, sdp))) { - LOG(INFO) - << "Unable to send answer. Failed to write the answer to the remote " - "peer " - << remote_peer_id.GetId(); - RemoveConnectionFlow(remote_peer_id); - return; - } - - LOG(INFO) << "Sent answer to " << remote_peer_id.GetId(); -} - -void WebRtc::ReceiveAnswer(const WebrtcPeerId& remote_peer_id, - SessionDescriptionWrapper answer) { - const auto& entry = connection_flows_.find(remote_peer_id.GetId()); - if (entry == connection_flows_.end()) { - LOG(INFO) << "Unable to receive answer. Failed to create a ConnectionFlow."; - return; - } - - if (!entry->second->OnAnswerReceived(answer)) { - LOG(INFO) << "Unable to receive answer. Failed to process the answer."; - RemoveConnectionFlow(remote_peer_id); - } -} - -void WebRtc::ReceiveIceCandidates( - const WebrtcPeerId& remote_peer_id, - std::vector> ice_candidates) { - const auto& entry = connection_flows_.find(remote_peer_id.GetId()); - if (entry == connection_flows_.end()) { - LOG(INFO) << "Unable to receive ice candidates. Failed to create a " - "ConnectionFlow."; - return; - } - - entry->second->OnRemoteIceCandidatesReceived(std::move(ice_candidates)); -} - -void WebRtc::ProcessRestartTachyonReceiveMessages( - const std::string& service_id) { - MutexLock lock(&mutex_); - RestartTachyonReceiveMessages(service_id); -} - -void WebRtc::RestartTachyonReceiveMessages(const std::string& service_id) { - if (!IsAcceptingConnectionsLocked(service_id)) { - LOG(INFO) - << "Skipping restart listening for tachyon inbox messages since we are " - "not accepting connections for service " - << service_id; - return; - } - - // Grab our info from the map. - auto& info = accepting_connections_info_.find(service_id)->second; - - // Ensure we've disconnected from Tachyon. - info.signaling_messenger->StopReceivingMessages(); - - // Attempt to re-register. - if (!info.signaling_messenger->StartReceivingMessages( - absl::bind_front(&WebRtc::OnSignalingMessage, this, service_id), - absl::bind_front(&WebRtc::OnSignalingComplete, this, service_id))) { - LOG(WARNING) - << "Failed to restart listening for tachyon inbox messages for " - "service " - << service_id << " since we failed to reach Tachyon."; - return; - } - - LOG(INFO) << "Successfully restarted listening for tachyon inbox " - "messages on service " - << service_id; -} - -void WebRtc::ProcessDataChannelOpen(const std::string& service_id, - const WebrtcPeerId& remote_peer_id, - WebRtcSocketWrapper socket_wrapper) { - MutexLock lock(&mutex_); - - // Notify the client of the newly formed socket. - const auto& connection_request_entry = - requesting_connections_info_.find(remote_peer_id.GetId()); - if (connection_request_entry != requesting_connections_info_.end()) { - connection_request_entry->second.socket_future.Set(socket_wrapper); - return; - } - - const auto& accepting_connection_entry = - accepting_connections_info_.find(service_id); - if (accepting_connection_entry != accepting_connections_info_.end() && - accepting_connection_entry->second.accepted_connection_callback) { - accepting_connection_entry->second.accepted_connection_callback( - service_id, socket_wrapper); - return; - } - - // No one to handle the newly created DataChannel, so we'll just close it. - socket_wrapper.Close(); - LOG(INFO) << "Ignoring new DataChannel because we are not accepting " - "connections for service " - << service_id; -} - -void WebRtc::ProcessDataChannelClosed(const WebrtcPeerId& remote_peer_id) { - MutexLock lock(&mutex_); - LOG(INFO) << "Data channel has closed, removing connection flow for peer " - << remote_peer_id.GetId(); - - RemoveConnectionFlow(remote_peer_id); -} - -std::unique_ptr WebRtc::CreateConnectionFlow( - const std::string& service_id, const WebrtcPeerId& remote_peer_id) { - RemoveConnectionFlow(remote_peer_id); - - return ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - {[this, service_id, - remote_peer_id](const webrtc::IceCandidate* ice_candidate) { - // Note: We need to encode the ice candidate here, before we jump - // off the thread. Otherwise, it gets destroyed and we can't read - // it later. - location::nearby::mediums::IceCandidate encoded_ice_candidate = - webrtc_frames::EncodeIceCandidate(*ice_candidate); - OffloadFromThread( - "rtc-ice-candidates", - [this, service_id, remote_peer_id, encoded_ice_candidate]() { - ProcessLocalIceCandidate(service_id, remote_peer_id, - encoded_ice_candidate); - }); - }}}, - { - .data_channel_open_cb = {[this, service_id, remote_peer_id]( - WebRtcSocketWrapper socket_wrapper) { - OffloadFromThread( - "rtc-channel-created", - [this, service_id, remote_peer_id, socket_wrapper]() { - ProcessDataChannelOpen(service_id, remote_peer_id, - socket_wrapper); - }); - }}, - .data_channel_closed_cb = {[this, remote_peer_id]() { - OffloadFromThread("rtc-channel-closed", [this, remote_peer_id]() { - ProcessDataChannelClosed(remote_peer_id); - }); - }}, - }, - { - .adapter_type_changed_cb = {[this](webrtc::AdapterType adapter_type) { - OffloadFromThread("rtc-adapter-type-changed", - [this, adapter_type]() { - if (FeatureFlags::GetInstance() - .GetFlags() - .support_web_rtc_non_cellular_medium) { - AdapterTypeChangedHandler(adapter_type); - } - }); - }}, - }, - *medium_); -} - -void WebRtc::AdapterTypeChangedHandler(webrtc::AdapterType adapter_type) { - MutexLock lock(&mutex_); - is_using_cellular_ = adapter_type == webrtc::ADAPTER_TYPE_CELLULAR || - adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_2G || - adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_3G || - adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_4G || - adapter_type == webrtc::ADAPTER_TYPE_CELLULAR_5G; -} - -void WebRtc::RemoveConnectionFlow(const WebrtcPeerId& remote_peer_id) { - if (!connection_flows_.erase(remote_peer_id.GetId())) { - return; - } - - // If we had an outgoing connection request w/ this peer, report the failure - // to the future that's being waited on. - const auto& connection_request_entry = - requesting_connections_info_.find(remote_peer_id.GetId()); - if (connection_request_entry != requesting_connections_info_.end()) { - connection_request_entry->second.socket_future.SetException( - {Exception::kFailed}); - } -} - -void WebRtc::OffloadFromThread(const std::string& name, Runnable runnable) { - single_thread_executor_.Execute(name, std::move(runnable)); -} - -bool WebRtc::IsUsingCellular() { - MutexLock lock(&mutex_); - return is_using_cellular_; -} - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc.h b/connections/implementation/mediums/webrtc.h index 66b84b45..93203d98 100644 --- a/connections/implementation/mediums/webrtc.h +++ b/connections/implementation/mediums/webrtc.h @@ -15,262 +15,76 @@ #ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_H_ #define CORE_INTERNAL_MEDIUMS_WEBRTC_H_ -#ifndef NO_WEBRTC - -#include #include #include -#include -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" -#include "connections/implementation/mediums/webrtc/connection_flow.h" -#include "connections/implementation/mediums/webrtc/session_description_wrapper.h" +#include "connections/implementation/bwu_handler.h" #include "connections/implementation/mediums/webrtc_peer_id.h" #include "connections/implementation/mediums/webrtc_socket.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/cancelable_alarm.h" +#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" -#include "internal/platform/future.h" -#include "internal/platform/mutex.h" -#include "internal/platform/runnable.h" -#include "internal/platform/scheduled_executor.h" -#include "internal/platform/webrtc.h" -#include "proto/mediums/web_rtc_signaling_frames.pb.h" -#include "webrtc/api/jsep.h" namespace nearby { namespace connections { namespace mediums { -// Entry point for connecting a data channel between two devices via WebRtc. +// A non-working base implementation for connecting a data channel between two +// devices via WebRtc. class WebRtc { public: // Callback that is invoked when a new connection is accepted. using AcceptedConnectionCallback = absl::AnyInvocable; + const std::string& service_id, std::shared_ptr socket)>; - WebRtc(); - ~WebRtc(); - - // Gets the default two-letter country code associated with current locale. - // For example, en_US locale resolves to "US". - std::string GetDefaultCountryCode(); + virtual ~WebRtc() = default; // Returns if WebRtc is available as a medium for nearby to transport data. // Runs on @MainThread. - bool IsAvailable(); + virtual bool IsAvailable() { return false; } // Returns if the device is accepting connection with specific service id. // Runs on @MainThread. - bool IsAcceptingConnections(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); + virtual bool IsAcceptingConnections(const std::string& service_id) { + return false; + } // Prepares the device to accept incoming WebRtc connections. Returns a // boolean value indicating if the device has started accepting connections. // Runs on @MainThread. - bool StartAcceptingConnections( + virtual bool StartAcceptingConnections( const std::string& service_id, const WebrtcPeerId& self_peer_id, const location::nearby::connections::LocationHint& location_hint, - AcceptedConnectionCallback callback, bool non_cellular) - ABSL_LOCKS_EXCLUDED(mutex_); + AcceptedConnectionCallback callback, bool non_cellular) { + return false; + } // Try to stop (accepting) the specific connection with provided service id. // Runs on @MainThread - void StopAcceptingConnections(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); + virtual void StopAcceptingConnections(const std::string& service_id) {} // Initiates a WebRtc connection with peer device identified by |peer_id| // with internal retry for maximum attempts of kConnectAttemptsLimit. // Runs on @MainThread. - ErrorOr Connect( + virtual ErrorOr> Connect( const std::string& service_id, const WebrtcPeerId& peer_id, const location::nearby::connections::LocationHint& location_hint, - CancellationFlag* cancellation_flag, bool non_cellular) - ABSL_LOCKS_EXCLUDED(mutex_); + CancellationFlag* cancellation_flag, bool non_cellular) { + return {Error(location::nearby::proto::connections::OperationResultCode:: + DETAIL_UNKNOWN)}; + } - bool IsUsingCellular() ABSL_LOCKS_EXCLUDED(mutex_); + virtual bool IsUsingCellular() { return false; } - protected: - // Use for unit tests only to inject a WebRtcMedium. - explicit WebRtc(std::unique_ptr medium); - - // Used in unit tests to determine how many calls to `AttemptToConnect` - // occured during a call to `Connect`, per service id. - std::map service_id_to_connect_attempts_count_map_; - - private: - static constexpr int kConnectAttemptsLimit = 3; - static constexpr int kRestartAcceptConnectionsLimit = 3; - - enum class Role { - kNone = 0, - kOfferer = 1, - kAnswerer = 2, - }; - - struct AcceptingConnectionsInfo { - // The self_peer_id is generated from the BT/WiFi advertisements and allows - // the scanner to message us over Tachyon. - WebrtcPeerId self_peer_id; - - // The registered callback. When there's an incoming connection, this - // callback is notified. - AcceptedConnectionCallback accepted_connection_callback; - - // Allows us to communicate with the Tachyon web server. - std::unique_ptr signaling_messenger; - - // Restarts the tachyon inbox receives messages streaming rpc if the - // streaming rpc times out. The streaming rpc times out after 60s while - // advertising. Non-null when listening for WebRTC connections as an - // offerer. - std::unique_ptr restart_tachyon_receive_messages_alarm; - - // Tracks the number of times we've restarted receiving messages after a - // failure. We limit the number to prevent endless restarts if we are - // repeatedly unable to communicate with Tachyon. - int restart_accept_connections_count = 0; - }; - - struct ConnectionRequestInfo { - // The self_peer_id is randomly generated and allows the advertiser to - // message us over Tachyon. - WebrtcPeerId self_peer_id; - - // Allows us to communicate with the Tachyon web server. - std::unique_ptr signaling_messenger; - - // The pending DataChannel future. Our client will be blocked on this while - // they wait for us to set up the channel over Tachyon. - Future socket_future; - }; - - // Attempt to initiates a WebRtc connection with peer device identified by - // |peer_id|. - // Runs on @MainThread. - ErrorOr AttemptToConnect( - const std::string& service_id, const WebrtcPeerId& peer_id, - const location::nearby::connections::LocationHint& location_hint, - CancellationFlag* cancellation_flag) ABSL_LOCKS_EXCLUDED(mutex_); - - // Returns if the device is accepting connection with specific service id. - // Runs on @MainThread. - bool IsAcceptingConnectionsLocked(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Receives a message from the signaling messenger. - void OnSignalingMessage(const std::string& service_id, - const ByteArray& message); - - // Decides whether to restart receiving messages. - void OnSignalingComplete(const std::string& service_id, bool success); - - // Runs on |single_thread_executor_|. - void ProcessTachyonInboxMessage(const std::string& service_id, - const ByteArray& message) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Runs on |single_thread_executor_|. - void SendOffer(const std::string& service_id, - const WebrtcPeerId& remote_peer_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void ReceiveOffer(const WebrtcPeerId& remote_peer_id, - SessionDescriptionWrapper offer) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void SendAnswer(const WebrtcPeerId& remote_peer_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void ReceiveAnswer(const WebrtcPeerId& remote_peer_id, - SessionDescriptionWrapper answer) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void ReceiveIceCandidates( - const WebrtcPeerId& remote_peer_id, - std::vector> ice_candidates) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - std::unique_ptr CreateConnectionFlow( - const std::string& service_id, const WebrtcPeerId& remote_peer_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - std::unique_ptr GetConnectionFlow( - const WebrtcPeerId& remote_peer_id) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void RemoveConnectionFlow(const WebrtcPeerId& remote_peer_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void ProcessDataChannelOpen(const std::string& service_id, - const WebrtcPeerId& remote_peer_id, - WebRtcSocketWrapper socket_wrapper) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Runs on |single_thread_executor_|. - void ProcessDataChannelClosed(const WebrtcPeerId& remote_peer_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Runs on |single_thread_executor_|. - void ProcessLocalIceCandidate( - const std::string& service_id, const WebrtcPeerId& remote_peer_id, - const location::nearby::mediums::IceCandidate ice_candidate) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Runs on |single_thread_executor_|. - void ProcessRestartTachyonReceiveMessages(const std::string& service_id) - ABSL_LOCKS_EXCLUDED(mutex_); - - // Runs on |single_thread_executor_|. - void RestartTachyonReceiveMessages(const std::string& service_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - - // Runs on |single_thread_executor_|. - void AdapterTypeChangedHandler(webrtc::AdapterType adapter_type) - ABSL_LOCKS_EXCLUDED(mutex_); - - void OffloadFromThread(const std::string& name, Runnable runnable); - - Mutex mutex_; - - std::unique_ptr medium_; - - // The single thread we throw the potentially blocking work on to. - ScheduledExecutor single_thread_executor_; - - // A map of ServiceID -> State for all services that are listening for - // incoming connections. - absl::flat_hash_map - accepting_connections_info_ ABSL_GUARDED_BY(mutex_); - - // A map of a remote PeerId -> State for pending connection requests. As - // messages from Tachyon come in, this lets us look up the connection request - // info to handle the interaction. - absl::flat_hash_map - requesting_connections_info_ ABSL_GUARDED_BY(mutex_); - - // A map of a remote PeerId -> ConnectionFlow. For each connection, we create - // a unique ConnectionFlow. - absl::flat_hash_map> - connection_flows_ ABSL_GUARDED_BY(mutex_); - - bool is_using_cellular_ ABSL_GUARDED_BY(mutex_) = true; + virtual std::unique_ptr CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback) { + return nullptr; + } }; } // namespace mediums } // namespace connections } // namespace nearby -#endif - #endif // CORE_INTERNAL_MEDIUMS_WEBRTC_H_ diff --git a/connections/implementation/mediums/webrtc/BUILD b/connections/implementation/mediums/webrtc/BUILD deleted file mode 100644 index 71662a36..00000000 --- a/connections/implementation/mediums/webrtc/BUILD +++ /dev/null @@ -1,108 +0,0 @@ -load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") - -# 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. -licenses(["notice"]) - -cc_library( - name = "webrtc", - srcs = [ - "connection_flow.cc", - "signaling_frames.cc", - ], - hdrs = [ - "connection_flow.h", - "data_channel_listener.h", - "local_ice_candidate_listener.h", - "session_description_wrapper.h", - "signaling_frames.h", - ], - copts = [ - "-DCORE_ADAPTER_DLL", - "-DNO_WEBRTC", - ], - visibility = [ - "//connections/implementation:__subpackages__", - ], - deps = [ - ":data_types", - "//connections:core_types", - "//connections/implementation/mediums:webrtc_utils", - "//internal/platform:base", - "//internal/platform:comm", - "//internal/platform:logging", - "//internal/platform:types", - "//proto/mediums:web_rtc_signaling_frames_cc_proto", - # TODO: Support WebRTC - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/time", - ], -) - -cc_library( - name = "data_types", - srcs = [ - "webrtc_socket_impl.cc", - ], - hdrs = [ - "webrtc_socket_impl.h", - ], - copts = [ - "-DCORE_ADAPTER_DLL", - "-DNO_WEBRTC", - ], - visibility = [ - "//connections/implementation:__subpackages__", - ], - deps = [ - "//internal/platform:base", - "//internal/platform:logging", - "//internal/platform:types", - "@com_google_absl//absl/strings:string_view", - ], -) - -cc_test( - name = "webrtc_test", - timeout = "short", - srcs = [ - "connection_flow_test.cc", - "signaling_frames_test.cc", - "webrtc_socket_impl_test.cc", - ], - tags = [ - "notsan", # NOTE(b/139734036): known data race in usrsctplib. - "requires-net:external", - ], - deps = [ - ":data_types", - ":webrtc", - "//connections/implementation/mediums:webrtc_utils", - "//internal/platform:base", - "//internal/platform:comm", - "//internal/platform:test_util", - "//internal/platform:types", - "//internal/platform/implementation/g3", # buildcleaner: keep - "//third_party/webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", - "//third_party/webrtc/files/stable/webrtc/api:scoped_refptr", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/strings:string_view", - "@com_google_absl//absl/time", - "@com_google_googletest//:gtest_main", - "@com_google_protobuf//:protobuf", - ], -) diff --git a/connections/implementation/mediums/webrtc/connection_flow.cc b/connections/implementation/mediums/webrtc/connection_flow.cc deleted file mode 100644 index 1d32ae17..00000000 --- a/connections/implementation/mediums/webrtc/connection_flow.cc +++ /dev/null @@ -1,583 +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 NO_WEBRTC - -#include "connections/implementation/mediums/webrtc/connection_flow.h" - -#include -#include -#include -#include - -#include "absl/memory/memory.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/webrtc/data_channel_listener.h" -#include "connections/implementation/mediums/webrtc/local_ice_candidate_listener.h" -#include "connections/implementation/mediums/webrtc/session_description_wrapper.h" -#include "connections/implementation/mediums/webrtc/webrtc_socket_impl.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "internal/platform/exception.h" -#include "internal/platform/future.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" -#include "internal/platform/runnable.h" -#include "internal/platform/webrtc.h" -#include "webrtc/api/data_channel_interface.h" -#include "webrtc/api/jsep.h" - -namespace nearby { -namespace connections { -namespace mediums { - -constexpr absl::Duration ConnectionFlow::kTimeout; -constexpr absl::Duration ConnectionFlow::kPeerConnectionTimeout; - -// This is the same as the nearby data channel name. -constexpr char kDataChannelName[] = "dataChannel"; - -class CreateSessionDescriptionObserverImpl - : public webrtc::CreateSessionDescriptionObserver { - public: - CreateSessionDescriptionObserverImpl( - ConnectionFlow* connection_flow, - Future settable_future, - ConnectionFlow::State expected_entry_state, - ConnectionFlow::State exit_state) - : connection_flow_{connection_flow}, - settable_future_{settable_future}, - expected_entry_state_{expected_entry_state}, - exit_state_{exit_state} {} - - // webrtc::CreateSessionDescriptionObserver - void OnSuccess(webrtc::SessionDescriptionInterface* desc) override { - if (connection_flow_->TransitionState(expected_entry_state_, exit_state_)) { - settable_future_.Set(SessionDescriptionWrapper{desc}); - } else { - settable_future_.SetException({Exception::kFailed}); - } - } - - void OnFailure(webrtc::RTCError error) override { - LOG(ERROR) << "Error when creating session description: " - << error.message(); - settable_future_.SetException({Exception::kFailed}); - } - - private: - ConnectionFlow* connection_flow_; - Future settable_future_; - ConnectionFlow::State expected_entry_state_; - ConnectionFlow::State exit_state_; -}; - -class SetDescriptionObserverBase { - public: - ExceptionOr GetResult(absl::Duration timeout) { - return settable_future_.Get(timeout); - } - - protected: - void OnSetDescriptionComplete(webrtc::RTCError error) { - // On success, |error.ok()| is true. - if (error.ok()) { - settable_future_.Set(true); - return; - } - settable_future_.SetException({Exception::kFailed}); - } - - private: - Future settable_future_; -}; - -class SetLocalDescriptionObserver - : public webrtc::SetLocalDescriptionObserverInterface, - public SetDescriptionObserverBase { - public: - void OnSetLocalDescriptionComplete(webrtc::RTCError error) override { - OnSetDescriptionComplete(error); - } -}; - -class SetRemoteDescriptionObserver - : public webrtc::SetRemoteDescriptionObserverInterface, - public SetDescriptionObserverBase { - public: - void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override { - OnSetDescriptionComplete(error); - } -}; - -using PeerConnectionState = - webrtc::PeerConnectionInterface::PeerConnectionState; - -std::unique_ptr ConnectionFlow::Create( - LocalIceCandidateListener local_ice_candidate_listener, - DataChannelListener data_channel_listener, - AdapterTypeListener adapter_type_listener, WebRtcMedium& webrtc_medium) { - auto connection_flow = absl::WrapUnique(new ConnectionFlow( - std::move(local_ice_candidate_listener), std::move(data_channel_listener), - std::move(adapter_type_listener))); - if (connection_flow->InitPeerConnection(webrtc_medium)) { - return connection_flow; - } - - return nullptr; -} - -ConnectionFlow::ConnectionFlow( - LocalIceCandidateListener local_ice_candidate_listener, - DataChannelListener data_channel_listener, - AdapterTypeListener adapter_type_listener) - : data_channel_listener_(std::move(data_channel_listener)), - local_ice_candidate_listener_(std::move(local_ice_candidate_listener)), - adapter_type_listener_(std::move(adapter_type_listener)) {} - -ConnectionFlow::~ConnectionFlow() { - LOG(INFO) << "~ConnectionFlow"; - RunOnSignalingThread([this] { CloseOnSignalingThread(); }); - shutdown_latch_.Await(); - LOG(INFO) << "~ConnectionFlow done"; -} - -SessionDescriptionWrapper ConnectionFlow::CreateOffer() { - CHECK(!IsRunningOnSignalingThread()); - Future success_future; - if (!RunOnSignalingThread([this, success_future] { - CreateOfferOnSignalingThread(success_future); - })) { - LOG(ERROR) << "Failed to create offer"; - return SessionDescriptionWrapper(); - } - ExceptionOr result = success_future.Get(kTimeout); - if (result.ok()) { - return std::move(result.result()); - } - LOG(ERROR) << "Failed to create offer: " << result.exception(); - return SessionDescriptionWrapper(); -} - -void ConnectionFlow::CreateOfferOnSignalingThread( - Future success_future) { - if (!TransitionState(State::kInitialized, State::kCreatingOffer)) { - success_future.SetException({Exception::kFailed}); - return; - } - webrtc::DataChannelInit data_channel_init; - data_channel_init.reliable = true; - auto pc = GetPeerConnection(); - auto result = - pc->CreateDataChannelOrError(kDataChannelName, &data_channel_init); - if (!result.ok()) { - success_future.SetException({Exception::kFailed}); - return; - } - CreateSocketFromDataChannel(result.MoveValue()); - - webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options; - webrtc::scoped_refptr observer( - new webrtc::RefCountedObject( - this, success_future, State::kCreatingOffer, - State::kWaitingForAnswer)); - pc->CreateOffer(observer.get(), options); -} - -SessionDescriptionWrapper ConnectionFlow::CreateAnswer() { - CHECK(!IsRunningOnSignalingThread()); - Future success_future; - if (!RunOnSignalingThread([this, success_future] { - CreateAnswerOnSignalingThread(success_future); - })) { - LOG(ERROR) << "Failed to create answer"; - return SessionDescriptionWrapper(); - } - ExceptionOr result = success_future.Get(kTimeout); - if (result.ok()) { - return std::move(result.result()); - } - LOG(ERROR) << "Failed to create answer: " << result.exception(); - return SessionDescriptionWrapper(); -} - -void ConnectionFlow::CreateAnswerOnSignalingThread( - Future success_future) { - if (!TransitionState(State::kReceivedOffer, State::kCreatingAnswer)) { - success_future.SetException({Exception::kFailed}); - return; - } - webrtc::PeerConnectionInterface::RTCOfferAnswerOptions options; - webrtc::scoped_refptr observer( - new webrtc::RefCountedObject( - this, success_future, State::kCreatingAnswer, - State::kWaitingToConnect)); - auto pc = GetPeerConnection(); - pc->CreateAnswer(observer.get(), options); -} - -bool ConnectionFlow::SetLocalSessionDescription(SessionDescriptionWrapper sdp) { - CHECK(!IsRunningOnSignalingThread()); - if (!sdp.IsValid()) return false; - - webrtc::scoped_refptr observer( - new webrtc::RefCountedObject()); - - if (!RunOnSignalingThread([this, observer, sdp = std::move(sdp)]() mutable { - if (state_ == State::kEnded) { - observer->OnSetLocalDescriptionComplete( - webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE)); - return; - } - auto pc = GetPeerConnection(); - - pc->SetLocalDescription( - std::unique_ptr(sdp.Release()), - observer); - })) { - return false; - } - - ExceptionOr result = observer->GetResult(kTimeout); - bool success = result.ok() && result.result(); - if (!success) { - LOG(ERROR) << "Failed to set local session description: " - << result.exception(); - } - return success; -} - -bool ConnectionFlow::SetRemoteSessionDescription(SessionDescriptionWrapper sdp, - State expected_entry_state, - State exit_state) { - if (!sdp.IsValid()) return false; - - webrtc::scoped_refptr observer( - new webrtc::RefCountedObject()); - - if (!RunOnSignalingThread([this, observer, sdp = std::move(sdp), - expected_entry_state, exit_state]() mutable { - if (!TransitionState(expected_entry_state, exit_state)) { - observer->OnSetRemoteDescriptionComplete( - webrtc::RTCError(webrtc::RTCErrorType::INVALID_STATE)); - return; - } - auto pc = GetPeerConnection(); - - pc->SetRemoteDescription( - std::unique_ptr(sdp.Release()), - observer); - })) { - return false; - } - - ExceptionOr result = observer->GetResult(kTimeout); - bool success = result.ok() && result.result(); - if (!success) { - LOG(ERROR) << "Failed to set remote description: " << result.exception(); - } - return success; -} - -bool ConnectionFlow::OnOfferReceived(SessionDescriptionWrapper offer) { - CHECK(!IsRunningOnSignalingThread()); - return SetRemoteSessionDescription(std::move(offer), State::kInitialized, - State::kReceivedOffer); -} - -bool ConnectionFlow::OnAnswerReceived(SessionDescriptionWrapper answer) { - CHECK(!IsRunningOnSignalingThread()); - return SetRemoteSessionDescription( - std::move(answer), State::kWaitingForAnswer, State::kWaitingToConnect); -} - -bool ConnectionFlow::OnRemoteIceCandidatesReceived( - std::vector> ice_candidates) { - CHECK(!IsRunningOnSignalingThread()); - // We can't call RunOnSignalingThread because C++ wants to copy ice_candidates - // if we try. unique_ptr is not CopyConstructible and compilation fails. - auto pc = GetPeerConnection(); - - if (!pc) { - return false; - } - pc->signaling_thread()->PostTask( - [this, can_run_tasks = std::weak_ptr(can_run_tasks_), - candidates = std::move(ice_candidates)]() mutable { - // Don't run the task if the weak_ptr is no longer valid. - if (!can_run_tasks.lock()) { - return; - } - AddIceCandidatesOnSignalingThread(std::move(candidates)); - }); - return true; -} - -void ConnectionFlow::AddIceCandidatesOnSignalingThread( - std::vector> ice_candidates) { - CHECK(IsRunningOnSignalingThread()); - if (state_ == State::kEnded) { - LOG(WARNING) << "You cannot add ice candidates to a disconnected session."; - return; - } - if (state_ != State::kWaitingToConnect && state_ != State::kConnected) { - cached_remote_ice_candidates_.insert( - cached_remote_ice_candidates_.end(), - std::make_move_iterator(ice_candidates.begin()), - std::make_move_iterator(ice_candidates.end())); - return; - } - auto pc = GetPeerConnection(); - for (auto&& ice_candidate : ice_candidates) { - if (!pc->AddIceCandidate(ice_candidate.get())) { - LOG(WARNING) << "Unable to add remote ice candidate."; - } - } -} - -bool ConnectionFlow::CloseIfNotConnected() { - CHECK(!IsRunningOnSignalingThread()); - Future closed; - if (RunOnSignalingThread([this, closed]() mutable { - if (state_ == State::kConnected) { - closed.Set(false); - } else { - CloseOnSignalingThread(); - closed.Set(true); - } - })) { - auto result = closed.Get(); - return result.ok() && result.result(); - } - return true; -} - -bool ConnectionFlow::InitPeerConnection(WebRtcMedium& webrtc_medium) { - Future success_future; - // CreatePeerConnection callback may be invoked after ConnectionFlow lifetime - // has ended, in case of a timeout. Future is captured by value, and is safe - // to access, but it is not safe to access ConnectionFlow member variables - // unless the Future::Set() returns true. - webrtc_medium.CreatePeerConnection( - this, [this, success_future]( - webrtc::scoped_refptr - peer_connection) mutable { - if (!peer_connection) { - success_future.Set(false); - return; - } - - // If this fails, means we have already assigned something to - // success_future; it is either: - // 1) this is the 2nd call of this callback (and this is a bug), or - // 2) Get(timeout) has set the future value as exception already. - if (success_future.IsSet()) return; - MutexLock lock(&mutex_); - peer_connection_ = peer_connection; - signaling_thread_for_dcheck_only_ = - peer_connection_->signaling_thread(); - success_future.Set(true); - }); - - ExceptionOr result = success_future.Get(kPeerConnectionTimeout); - bool success = result.ok() && result.result(); - if (!success) { - shutdown_latch_.CountDown(); - LOG(ERROR) << "Failed to create peer connection: " << result.exception(); - } - return success; -} - -void ConnectionFlow::OnSignalingStable() { - if (state_ != State::kWaitingToConnect && state_ != State::kConnected) return; - auto pc = GetPeerConnection(); - for (auto&& ice_candidate : cached_remote_ice_candidates_) { - if (!pc->AddIceCandidate(ice_candidate.get())) { - LOG(WARNING) << "Unable to add remote ice candidate."; - } - } - cached_remote_ice_candidates_.clear(); -} - -void ConnectionFlow::CreateSocketFromDataChannel( - webrtc::scoped_refptr data_channel) { - LOG(INFO) << "Creating data channel socket"; - auto socket = - std::make_unique("WebRtcSocket", std::move(data_channel)); - socket->SetSocketListener({ - .socket_ready_cb = {[this](WebRtcSocket* socket) { - CHECK(IsRunningOnSignalingThread()); - if (!TransitionState(State::kWaitingToConnect, State::kConnected)) { - LOG(ERROR) << "Data channel socket is open but connection " - "flow was not in the required state"; - socket->Close(); - return; - } - // Pass socket wrapper by copy on purpose - data_channel_listener_.data_channel_open_cb(socket_wrapper_); - }}, - .socket_closed_cb = - [this](WebRtcSocket*) { - data_channel_listener_.data_channel_closed_cb(); - }, - }); - socket_wrapper_ = WebRtcSocketWrapper(std::move(socket)); -} - -void ConnectionFlow::OnIceCandidate(const webrtc::IceCandidate* candidate) { - CHECK(IsRunningOnSignalingThread()); - local_ice_candidate_listener_.local_ice_candidate_found_cb(candidate); -} - -void ConnectionFlow::OnSignalingChange( - webrtc::PeerConnectionInterface::SignalingState new_state) { - LOG(INFO) << "OnSignalingChange: " << new_state; - CHECK(IsRunningOnSignalingThread()); - if (new_state == webrtc::PeerConnectionInterface::SignalingState::kStable) { - OnSignalingStable(); - } -} - -void ConnectionFlow::OnDataChannel( - webrtc::scoped_refptr data_channel) { - LOG(INFO) << "OnDataChannel"; - CHECK(IsRunningOnSignalingThread()); - CreateSocketFromDataChannel(std::move(data_channel)); -} - -void ConnectionFlow::OnIceGatheringChange( - webrtc::PeerConnectionInterface::IceGatheringState new_state) { - LOG(INFO) << "OnIceGatheringChange: " << new_state; - CHECK(IsRunningOnSignalingThread()); -} - -void ConnectionFlow::OnConnectionChange( - webrtc::PeerConnectionInterface::PeerConnectionState new_state) { - LOG(INFO) << "OnConnectionChange: " << static_cast(new_state); - CHECK(IsRunningOnSignalingThread()); - if (new_state == PeerConnectionState::kClosed || - new_state == PeerConnectionState::kFailed || - new_state == PeerConnectionState::kDisconnected) { - LOG(INFO) << "Closing due to peer connection state change: " - << static_cast(new_state); - CloseOnSignalingThread(); - } -} - -void ConnectionFlow::OnRenegotiationNeeded() { - LOG(INFO) << "OnRenegotiationNeeded"; - CHECK(IsRunningOnSignalingThread()); -} - -void ConnectionFlow::OnIceSelectedCandidatePairChanged( - const webrtc::CandidatePairChangeEvent& event) { - LOG(INFO) << "OnIceSelectedCandidatePairChanged"; - CHECK(IsRunningOnSignalingThread()); - // TODO(edwinwu) - Implement the unit test for this. We should be able to get - // the adapter type from the PeerConnection. - adapter_type_listener_.adapter_type_changed_cb( - event.selected_candidate_pair.local_candidate().network_type()); -} - -bool ConnectionFlow::TransitionState(State current_state, State new_state) { - CHECK(IsRunningOnSignalingThread()); - if (current_state != state_) { - LOG(WARNING) << "Invalid state transition to " - << static_cast(new_state) << ": current state is " - << static_cast(state_) << " but expected " - << static_cast(current_state); - return false; - } - LOG(INFO) << "Transition: " << static_cast(state_) << "->" - << static_cast(new_state); - state_ = new_state; - return true; -} - -bool ConnectionFlow::CloseOnSignalingThread() { - if (state_ == State::kEnded) { - return false; - } - state_ = State::kEnded; - // Close the socket wrapper before terminating the PeerConnection - // since the teardown process of the PC may close threads that are - // otherwise depended upon by objects kept alive by the socket_wrapper. - if (socket_wrapper_.IsValid()) socket_wrapper_.Close(); - - // This prevents other tasks from queuing on the signaling thread for this - // object. - auto pc = GetAndResetPeerConnection(); - - LOG(INFO) << "Closing WebRTC peer connection."; - // NOTE: Closing the peer connection will close the data channel and thus the - // socket implicitly. - if (pc) pc->Close(); - LOG(INFO) << "Closed WebRTC peer connection."; - // Prevent any already queued tasks from running on the signaling thread - can_run_tasks_.reset(); - // If anyone was waiting for shutdown to be done let them know. - shutdown_latch_.CountDown(); - return true; -} - -bool ConnectionFlow::RunOnSignalingThread(Runnable&& runnable) { - CHECK(!IsRunningOnSignalingThread()); - auto pc = GetPeerConnection(); - if (!pc) { - LOG(WARNING) << "Peer connection not available. Cannot schedule tasks."; - return false; - } - // We are off signaling thread, so we can't use peer connection's methods - // but we can access the signaling thread handle. - pc->signaling_thread()->PostTask( - [can_run_tasks = std::weak_ptr(can_run_tasks_), - task = std::move(runnable)]() mutable { - // Don't run the task if the weak_ptr is no longer valid. - // shared_ptr |can_run_tasks_| is destroyed on the same thread - // (signaling thread). This guarantees that if the weak_ptr is valid - // when this task starts, it will stay valid until the task ends. - if (!can_run_tasks.lock()) { - LOG(INFO) << "Peer connection already closed. Cannot run tasks."; - return; - } - task(); - }); - return true; -} - -bool ConnectionFlow::IsRunningOnSignalingThread() { - return signaling_thread_for_dcheck_only_ != nullptr && - signaling_thread_for_dcheck_only_ == webrtc::Thread::Current(); -} - -webrtc::scoped_refptr -ConnectionFlow::GetPeerConnection() { - // We must use a mutex to ensure that peer connection is - // fully initialized. - // We increase the peer_connection_'s refcount to keep it - // alive while we use it. - MutexLock lock(&mutex_); - return peer_connection_; -} - -webrtc::scoped_refptr -ConnectionFlow::GetAndResetPeerConnection() { - MutexLock lock(&mutex_); - return std::move(peer_connection_); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc/connection_flow.h b/connections/implementation/mediums/webrtc/connection_flow.h deleted file mode 100644 index e0986786..00000000 --- a/connections/implementation/mediums/webrtc/connection_flow.h +++ /dev/null @@ -1,251 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ - -#ifndef NO_WEBRTC - -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/functional/any_invocable.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/webrtc/data_channel_listener.h" -#include "connections/implementation/mediums/webrtc/local_ice_candidate_listener.h" -#include "connections/implementation/mediums/webrtc/session_description_wrapper.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/future.h" -#include "internal/platform/listeners.h" -#include "internal/platform/mutex.h" -#include "internal/platform/runnable.h" -#include "internal/platform/webrtc.h" -#include "webrtc/api/data_channel_interface.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace nearby { -namespace connections { -namespace mediums { - -/** - * Flow for an offerer: - * - *

    - *
  • INITIALIZED: After construction. - *
  • CREATING_OFFER: After CreateOffer(). Local ice candidate collection - * begins. - *
  • WAITING_FOR_ANSWER: Until the remote peer sends their answer. - *
  • WAITING_TO_CONNECT: Until the data channel actually connects. Remote - * ice candidates should be added with OnRemoteIceCandidatesReceived as they are - * gathered. - *
  • CONNECTED: We successfully connected to the remote data - * channel. - *
  • ENDED: The final state that can occur from any of the previous - * states if we disconnect at any point in the flow. - *
- * - *

Flow for an answerer: - * - *

    - *
  • INITIALIZED: After construction. - *
  • RECEIVED_OFFER: After onOfferReceived(). - *
  • CREATING_ANSWER: After CreateAnswer(). Local ice candidate collection - * begins. - *
  • WAITING_TO_CONNECT: Until the data channel actually connects. - * Remote ice candidates should be added with OnRemoteIceCandidatesReceived as - * they are gathered. - *
  • CONNECTED: We successfully connected to the remote - * data channel. - *
  • ENDED: The final state that can occur from any of the - * previous states if we disconnect at any point in the flow. - *
- */ -class ConnectionFlow : public webrtc::PeerConnectionObserver { - public: - enum class State { - kInitialized, - kCreatingOffer, - kWaitingForAnswer, - kReceivedOffer, - kCreatingAnswer, - kWaitingToConnect, - kConnected, - kEnded, - }; - - struct AdapterTypeListener { - absl::AnyInvocable - adapter_type_changed_cb = DefaultCallback(); - }; - - // This method blocks on the creation of the peer connection object. - // Can be called on any thread but never called on signaling thread. - static std::unique_ptr Create( - LocalIceCandidateListener local_ice_candidate_listener, - DataChannelListener data_channel_listener, - AdapterTypeListener adapter_type_listener, WebRtcMedium& webrtc_medium); - ~ConnectionFlow() override; - - // Create the offer that will be sent to the remote. Mirrors the behaviour of - // PeerConnectionInterface::CreateOffer. - // Can be called on any thread but never called on signaling thread. - SessionDescriptionWrapper CreateOffer() ABSL_LOCKS_EXCLUDED(mutex_); - // Create the answer that will be sent to the remote. Mirrors the behaviour of - // PeerConnectionInterface::CreateAnswer. - // Can be called on any thread but never called on signaling thread. - SessionDescriptionWrapper CreateAnswer() ABSL_LOCKS_EXCLUDED(mutex_); - // Set the local session description. |sdp| was created via CreateOffer() - // or CreateAnswer(). - // Can be called on any thread but never called on signaling thread. - bool SetLocalSessionDescription(SessionDescriptionWrapper sdp) - ABSL_LOCKS_EXCLUDED(mutex_); - // Invoked when an offer was received from a remote; this will set the remote - // session description on the peer connection. Returns true if the offer was - // successfully set as remote session description. - // Can be called on any thread but never called on signaling thread. - bool OnOfferReceived(SessionDescriptionWrapper offer) - ABSL_LOCKS_EXCLUDED(mutex_); - // Invoked when an answer was received from a remote; this will set the remote - // session description on the peer connection. Returns true if the offer was - // successfully set as remote session description. - // Can be called on any thread but never called on signaling thread. - bool OnAnswerReceived(SessionDescriptionWrapper answer) - ABSL_LOCKS_EXCLUDED(mutex_); - // Invoked when an ice candidate was received from a remote; this will add the - // ice candidate to the peer connection if ready or cache it otherwise. - // Can be called on any thread but never called on signaling thread. - bool OnRemoteIceCandidatesReceived( - std::vector> ice_candidates) - ABSL_LOCKS_EXCLUDED(mutex_); - // Close the peer connection and data channel if not connected. - // Can be called on any thread but never called on signaling thread. - bool CloseIfNotConnected() ABSL_LOCKS_EXCLUDED(mutex_); - - // webrtc::PeerConnectionObserver: - // All methods called only on signaling thread. - void OnIceCandidate(const webrtc::IceCandidate* candidate) override; - void OnSignalingChange( - webrtc::PeerConnectionInterface::SignalingState new_state) override; - void OnDataChannel(webrtc::scoped_refptr - data_channel) override; - void OnIceGatheringChange( - webrtc::PeerConnectionInterface::IceGatheringState new_state) override; - void OnConnectionChange( - webrtc::PeerConnectionInterface::PeerConnectionState new_state) override; - void OnRenegotiationNeeded() override; - void OnIceSelectedCandidatePairChanged( - const webrtc::CandidatePairChangeEvent& event) override; - - // Public because it's used in tests too. - webrtc::scoped_refptr GetPeerConnection(); - - private: - ConnectionFlow(LocalIceCandidateListener local_ice_candidate_listener, - DataChannelListener data_channel_listener, - AdapterTypeListener adapter_type_listener); - - // Resets peer connection reference. Returns old value. - webrtc::scoped_refptr - GetAndResetPeerConnection(); - void CreateOfferOnSignalingThread( - Future success_future); - void CreateAnswerOnSignalingThread( - Future success_future); - void AddIceCandidatesOnSignalingThread( - std::vector> ice_candidates); - // Invoked when the peer connection indicates that signaling is stable. - void OnSignalingStable() ABSL_LOCKS_EXCLUDED(mutex_); - - void CreateSocketFromDataChannel( - webrtc::scoped_refptr data_channel); - - // TODO(bfranz): Consider whether this needs to be configurable per platform - static constexpr absl::Duration kTimeout = absl::Milliseconds(250); - static constexpr absl::Duration kPeerConnectionTimeout = - absl::Milliseconds(2500); - - bool InitPeerConnection(WebRtcMedium& webrtc_medium); - - bool TransitionState(State current_state, State new_state); - - bool SetRemoteSessionDescription(SessionDescriptionWrapper sdp, - State expected_entry_state, - State exit_state); - - bool CloseOnSignalingThread() ABSL_LOCKS_EXCLUDED(mutex_); - - bool RunOnSignalingThread(Runnable&& runnable); - bool IsRunningOnSignalingThread(); - - Mutex mutex_; - // Used to prevent the destructor from returning while the signaling thread is - // still running CloseOnSignalingThread() - CountDownLatch shutdown_latch_{1}; - - // State is used on signaling thread only. - State state_ = State::kInitialized; - // Used to communicate data channel events back to the caller of Create() - DataChannelListener data_channel_listener_; - - LocalIceCandidateListener local_ice_candidate_listener_; - // Peer connection can be used only on signaling thread. The only exception - // is accessing the signaling thread handle. Tasks posted on the - // signaling thread may outlive both |peer_connection_| and |this| objects. - // A mutex is required to access peer connection reference because peer - // connection object and the reference can be initialized on different - // threads - the reference could be initialized before peer connection's - // constructor has finished. - // |peer_connection_| is actually implemented by PeerConnectionProxy, which - // runs the real PeerConnection's methods on the correct thread (signaling or - // worker). If a proxy method is called on the correct thread, then the real - // method is called directly. Otherwise, a task is posted on the correct - // thread and the current thread is blocked until that task finishes. We - // choose to explicitly use |peer_connection_| on the signaling thread, - // because it allows us to do state management on the signaling thread too, - // simplifies locking, and we don't have to block the current thread for every - // peer connection call. - webrtc::scoped_refptr peer_connection_ - ABSL_GUARDED_BY(mutex_); - - // Used to hold a reference to the WebRtcSocket while the data channel is - // connecting. - WebRtcSocketWrapper socket_wrapper_; - - std::vector> - cached_remote_ice_candidates_; - // This pointer is only for DCHECK() assertions. - // It allows us to check if we are running on signaling thread even - // after destroying |peer_connection_|. - const void* signaling_thread_for_dcheck_only_ = nullptr; - // This shared_ptr is reset on the signaling thread when ConnectionFlow is - // closed. This prevents us from running tasks on the signaling thread when - // peer connection is closed. The value stored in |can_run_tasks_| is not - // used. We are using std::shared_ptr instead of webrtc::WeakPtrFactory - // because the former is thread-safe. - std::shared_ptr can_run_tasks_ = std::make_shared(); - - AdapterTypeListener adapter_type_listener_; - - friend class CreateSessionDescriptionObserverImpl; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_CONNECTION_FLOW_H_ diff --git a/connections/implementation/mediums/webrtc/connection_flow_test.cc b/connections/implementation/mediums/webrtc/connection_flow_test.cc deleted file mode 100644 index 64a7766d..00000000 --- a/connections/implementation/mediums/webrtc/connection_flow_test.cc +++ /dev/null @@ -1,441 +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 "connections/implementation/mediums/webrtc/connection_flow.h" - -#include -#include -#include - -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "connections/implementation/mediums/webrtc/data_channel_listener.h" -#include "connections/implementation/mediums/webrtc/local_ice_candidate_listener.h" -#include "connections/implementation/mediums/webrtc/session_description_wrapper.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/exception.h" -#include "internal/platform/future.h" -#include "internal/platform/medium_environment.h" -#include "internal/platform/webrtc.h" -#include "webrtc/api/jsep.h" -#include "webrtc/api/scoped_refptr.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace { - -class ConnectionFlowTest : public ::testing::Test { - protected: - ConnectionFlowTest() { - MediumEnvironment::Instance().Start({.webrtc_enabled = true}); - } - ~ConnectionFlowTest() override { MediumEnvironment::Instance().Stop(); } -}; - -std::unique_ptr CopyCandidate( - const webrtc::IceCandidate* candidate) { - return webrtc::CreateIceCandidate(candidate->sdp_mid(), - candidate->sdp_mline_index(), - candidate->candidate()); -} - -// TODO(bfranz) - Add test that deterministically sends answerer_ice_candidates -// before answer is sent. -TEST_F(ConnectionFlowTest, SuccessfulOfferAnswerFlow) { - WebRtcMedium webrtc_medium_offerer, webrtc_medium_answerer; - - Future message_received_future; - - Future offerer_socket_future, answerer_socket_future; - - std::unique_ptr offerer, answerer; - - // Send Ice Candidates immediately when you retrieve them - offerer = ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - [&answerer](const webrtc::IceCandidate* candidate) { - std::vector> vec; - vec.push_back(CopyCandidate(candidate)); - // The callback might be alive while the objects in test are - // destroyed. - if (answerer) - answerer->OnRemoteIceCandidatesReceived(std::move(vec)); - }}, - {.data_channel_open_cb = - [&offerer_socket_future](WebRtcSocketWrapper socket) { - offerer_socket_future.Set(std::move(socket)); - }}, - {.adapter_type_changed_cb = - [](webrtc::AdapterType adapter_type) { - // Do nothing - }}, - webrtc_medium_offerer); - ASSERT_NE(offerer, nullptr); - answerer = ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - [&offerer](const webrtc::IceCandidate* candidate) { - std::vector> vec; - vec.push_back(CopyCandidate(candidate)); - // The callback might be alive while the objects in test are - // destroyed. - if (offerer) - offerer->OnRemoteIceCandidatesReceived(std::move(vec)); - }}, - {.data_channel_open_cb = - [&answerer_socket_future](WebRtcSocketWrapper socket) { - answerer_socket_future.Set(std::move(socket)); - }}, - {.adapter_type_changed_cb = - [](webrtc::AdapterType adapter_type) { - // Do nothing - }}, - webrtc_medium_answerer); - ASSERT_NE(answerer, nullptr); - - // Create and send offer - SessionDescriptionWrapper offer = offerer->CreateOffer(); - ASSERT_TRUE(offer.IsValid()); - EXPECT_EQ(offer.GetType(), webrtc::SdpType::kOffer); - EXPECT_TRUE(answerer->OnOfferReceived(offer)); - EXPECT_TRUE(offerer->SetLocalSessionDescription(std::move(offer))); - - // Create and send answer - SessionDescriptionWrapper answer = answerer->CreateAnswer(); - ASSERT_TRUE(answer.IsValid()); - EXPECT_EQ(answer.GetType(), webrtc::SdpType::kAnswer); - EXPECT_TRUE(offerer->OnAnswerReceived(answer)); - EXPECT_TRUE(answerer->SetLocalSessionDescription(std::move(answer))); - - // Retrieve Data Channels - ExceptionOr offerer_socket = - offerer_socket_future.Get(absl::Seconds(1)); - EXPECT_TRUE(offerer_socket.ok()); - ExceptionOr answerer_socket = - answerer_socket_future.Get(absl::Seconds(1)); - EXPECT_TRUE(answerer_socket.ok()); - - // Send message on data channel - absl::string_view message = "Test"; - offerer_socket.result().GetImpl().GetOutputStream().Write(message); - ExceptionOr received_message = - answerer_socket.result().GetImpl().GetInputStream().Read(4); - EXPECT_TRUE(received_message.ok()); - EXPECT_EQ(received_message.result(), ByteArray{message.data()}); -} - -TEST_F(ConnectionFlowTest, CreateAnswerBeforeOfferReceived) { - WebRtcMedium webrtc_medium; - - std::unique_ptr answerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium); - ASSERT_NE(answerer, nullptr); - - SessionDescriptionWrapper answer = answerer->CreateAnswer(); - EXPECT_FALSE(answer.IsValid()); -} - -TEST_F(ConnectionFlowTest, SetAnswerBeforeOffer) { - WebRtcMedium webrtc_medium_offerer, webrtc_medium_answerer; - - std::unique_ptr offerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium_offerer); - ASSERT_NE(offerer, nullptr); - std::unique_ptr answerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium_answerer); - ASSERT_NE(answerer, nullptr); - - SessionDescriptionWrapper offer = offerer->CreateOffer(); - ASSERT_TRUE(offer.IsValid()); - EXPECT_EQ(offer.GetType(), webrtc::SdpType::kOffer); - // Did not set offer as local session description - EXPECT_TRUE(answerer->OnOfferReceived(offer)); - - SessionDescriptionWrapper answer = answerer->CreateAnswer(); - ASSERT_TRUE(answer.IsValid()); - EXPECT_EQ(answer.GetType(), webrtc::SdpType::kAnswer); - EXPECT_FALSE(offerer->OnAnswerReceived(answer)); -} - -TEST_F(ConnectionFlowTest, CannotCreateOfferAfterClose) { - WebRtcMedium webrtc_medium; - - std::unique_ptr offerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium); - ASSERT_NE(offerer, nullptr); - - EXPECT_TRUE(offerer->CloseIfNotConnected()); - - EXPECT_FALSE(offerer->CreateOffer().IsValid()); -} - -TEST_F(ConnectionFlowTest, CannotSetSessionDescriptionAfterClose) { - WebRtcMedium webrtc_medium; - - std::unique_ptr offerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium); - ASSERT_NE(offerer, nullptr); - - SessionDescriptionWrapper offer = offerer->CreateOffer(); - ASSERT_TRUE(offer.IsValid()); - EXPECT_EQ(offer.GetType(), webrtc::SdpType::kOffer); - - EXPECT_TRUE(offerer->CloseIfNotConnected()); - - EXPECT_FALSE(offerer->SetLocalSessionDescription(offer)); -} - -TEST_F(ConnectionFlowTest, CannotReceiveOfferAfterClose) { - WebRtcMedium webrtc_medium_offerer, webrtc_medium_answerer; - - std::unique_ptr offerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium_offerer); - ASSERT_NE(offerer, nullptr); - std::unique_ptr answerer = ConnectionFlow::Create( - LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), webrtc_medium_answerer); - ASSERT_NE(answerer, nullptr); - - EXPECT_TRUE(answerer->CloseIfNotConnected()); - - SessionDescriptionWrapper offer = offerer->CreateOffer(); - ASSERT_TRUE(offer.IsValid()); - EXPECT_EQ(offer.GetType(), webrtc::SdpType::kOffer); - - EXPECT_FALSE(answerer->OnOfferReceived(offer)); -} - -TEST_F(ConnectionFlowTest, NullPeerConnection) { - MediumEnvironment::Instance().SetUseValidPeerConnection( - /*use_valid_peer_connection=*/false); - - WebRtcMedium medium; - std::unique_ptr answerer = - ConnectionFlow::Create(LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), medium); - EXPECT_EQ(answerer, nullptr); -} - -TEST_F(ConnectionFlowTest, PeerConnectionTimeout) { - MediumEnvironment::Instance().SetUseValidPeerConnection( - /*use_valid_peer_connection=*/true); - WebRtcMedium medium1; - std::unique_ptr flow1 = - ConnectionFlow::Create(LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), medium1); - EXPECT_NE(flow1, nullptr); - - // Attempt to trigger the 2.5s peer connection timeout. - MediumEnvironment::Instance().SetPeerConnectionLatency(absl::Seconds(5)); - WebRtcMedium medium2; - std::unique_ptr flow2 = - ConnectionFlow::Create(LocalIceCandidateListener(), DataChannelListener(), - ConnectionFlow::AdapterTypeListener(), medium2); - EXPECT_EQ(flow2, nullptr); -} - -TEST_F(ConnectionFlowTest, TerminateAnswerer) { - WebRtcMedium webrtc_medium_offerer, webrtc_medium_answerer; - - Future message_received_future; - - Future offerer_socket_future, answerer_socket_future; - - std::unique_ptr offerer, answerer; - - // Send Ice Candidates immediately when you retrieve them - offerer = ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - [&answerer](const webrtc::IceCandidate* candidate) { - std::vector> vec; - vec.push_back(CopyCandidate(candidate)); - // The callback might be alive while the objects in test are - // destroyed. - if (answerer) - answerer->OnRemoteIceCandidatesReceived(std::move(vec)); - }}, - {.data_channel_open_cb = - [&offerer_socket_future](WebRtcSocketWrapper socket) { - offerer_socket_future.Set(std::move(socket)); - }}, - {.adapter_type_changed_cb = - [](webrtc::AdapterType adapter_type) { - // Do nothing - }}, - webrtc_medium_offerer); - ASSERT_NE(offerer, nullptr); - answerer = ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - [&offerer](const webrtc::IceCandidate* candidate) { - std::vector> vec; - vec.push_back(CopyCandidate(candidate)); - // The callback might be alive while the objects in test are - // destroyed. - if (offerer) - offerer->OnRemoteIceCandidatesReceived(std::move(vec)); - }}, - {.data_channel_open_cb = - [&answerer_socket_future](WebRtcSocketWrapper wrapper) { - answerer_socket_future.Set(std::move(wrapper)); - }}, - {.adapter_type_changed_cb = - [](webrtc::AdapterType adapter_type) { - EXPECT_GE(adapter_type, webrtc::ADAPTER_TYPE_UNKNOWN); - EXPECT_LE(adapter_type, webrtc::ADAPTER_TYPE_CELLULAR_5G); - }}, - webrtc_medium_answerer); - ASSERT_NE(answerer, nullptr); - - // Create and send offer - SessionDescriptionWrapper offer = offerer->CreateOffer(); - ASSERT_TRUE(offer.IsValid()); - EXPECT_EQ(offer.GetType(), webrtc::SdpType::kOffer); - EXPECT_TRUE(answerer->OnOfferReceived(offer)); - EXPECT_TRUE(offerer->SetLocalSessionDescription(std::move(offer))); - - // Create and send answer - SessionDescriptionWrapper answer = answerer->CreateAnswer(); - ASSERT_TRUE(answer.IsValid()); - EXPECT_EQ(answer.GetType(), webrtc::SdpType::kAnswer); - EXPECT_TRUE(offerer->OnAnswerReceived(answer)); - EXPECT_TRUE(answerer->SetLocalSessionDescription(std::move(answer))); - - // Retrieve Data Channels - ExceptionOr offerer_socket = - offerer_socket_future.Get(absl::Seconds(1)); - EXPECT_TRUE(offerer_socket.ok()); - ExceptionOr answerer_socket = - answerer_socket_future.Get(absl::Seconds(1)); - EXPECT_TRUE(offerer_socket.ok()); - - CountDownLatch latch(1); - auto pc = answerer->GetPeerConnection(); - pc->signaling_thread()->PostTask([pc, latch]() mutable { - pc->Close(); - latch.CountDown(); - }); - latch.Await(); - - // Send message on data channel - absl::string_view message = "Test"; - offerer_socket.result().GetOutputStream().Write(message); - ExceptionOr received_message = - answerer_socket.result().GetInputStream().Read(4); - EXPECT_TRUE(received_message.GetResult().Empty()); -} - -TEST_F(ConnectionFlowTest, TerminateOfferer) { - WebRtcMedium webrtc_medium_offerer, webrtc_medium_answerer; - - Future message_received_future; - - Future offerer_socket_future, answerer_socket_future; - - std::unique_ptr offerer, answerer; - - // Send Ice Candidates immediately when you retrieve them - offerer = ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - [&answerer](const webrtc::IceCandidate* candidate) { - std::vector> vec; - vec.push_back(CopyCandidate(candidate)); - // The callback might be alive while the objects in test are - // destroyed. - if (answerer) - answerer->OnRemoteIceCandidatesReceived(std::move(vec)); - }}, - {.data_channel_open_cb = - [&offerer_socket_future](WebRtcSocketWrapper socket) { - offerer_socket_future.Set(std::move(socket)); - }}, - {.adapter_type_changed_cb = - [](webrtc::AdapterType adapter_type) { - EXPECT_GE(adapter_type, webrtc::ADAPTER_TYPE_UNKNOWN); - EXPECT_LE(adapter_type, webrtc::ADAPTER_TYPE_CELLULAR_5G); - }}, - webrtc_medium_offerer); - ASSERT_NE(offerer, nullptr); - answerer = ConnectionFlow::Create( - {.local_ice_candidate_found_cb = - [&offerer](const webrtc::IceCandidate* candidate) { - std::vector> vec; - vec.push_back(CopyCandidate(candidate)); - // The callback might be alive while the objects in test are - // destroyed. - if (offerer) - offerer->OnRemoteIceCandidatesReceived(std::move(vec)); - }}, - {.data_channel_open_cb = - [&answerer_socket_future](WebRtcSocketWrapper wrapper) { - answerer_socket_future.Set(std::move(wrapper)); - }}, - {.adapter_type_changed_cb = - [](webrtc::AdapterType adapter_type) { - EXPECT_GE(adapter_type, webrtc::ADAPTER_TYPE_UNKNOWN); - EXPECT_LE(adapter_type, webrtc::ADAPTER_TYPE_CELLULAR_5G); - }}, - webrtc_medium_answerer); - ASSERT_NE(answerer, nullptr); - - // Create and send offer - SessionDescriptionWrapper offer = offerer->CreateOffer(); - ASSERT_TRUE(offer.IsValid()); - EXPECT_EQ(offer.GetType(), webrtc::SdpType::kOffer); - EXPECT_TRUE(answerer->OnOfferReceived(offer)); - EXPECT_TRUE(offerer->SetLocalSessionDescription(std::move(offer))); - - // Create and send answer - SessionDescriptionWrapper answer = answerer->CreateAnswer(); - ASSERT_TRUE(answer.IsValid()); - EXPECT_EQ(answer.GetType(), webrtc::SdpType::kAnswer); - EXPECT_TRUE(offerer->OnAnswerReceived(answer)); - EXPECT_TRUE(answerer->SetLocalSessionDescription(std::move(answer))); - - // Retrieve Data Channels - ExceptionOr offerer_socket = - offerer_socket_future.Get(absl::Seconds(1)); - EXPECT_TRUE(offerer_socket.ok()); - ExceptionOr answerer_socket = - answerer_socket_future.Get(absl::Seconds(1)); - EXPECT_TRUE(offerer_socket.ok()); - - CountDownLatch latch(1); - auto pc = offerer->GetPeerConnection(); - pc->signaling_thread()->PostTask([pc, latch]() mutable { - pc->Close(); - latch.CountDown(); - }); - latch.Await(); - - // Send message on data channel - absl::string_view message = "Test"; - offerer_socket.result().GetOutputStream().Write(message); - ExceptionOr received_message = - answerer_socket.result().GetInputStream().Read(4); - EXPECT_TRUE(received_message.GetResult().Empty()); -} - -} // namespace -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/webrtc/data_channel_listener.h b/connections/implementation/mediums/webrtc/data_channel_listener.h deleted file mode 100644 index 17e6a0dc..00000000 --- a/connections/implementation/mediums/webrtc/data_channel_listener.h +++ /dev/null @@ -1,44 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ - -#ifndef NO_WEBRTC - -#include "absl/functional/any_invocable.h" -#include "connections/implementation/mediums/webrtc_socket.h" - -namespace nearby { -namespace connections { -namespace mediums { - -// Callbacks from the data channel. -struct DataChannelListener { - // Called when the data channel is open and the socket wrapper is ready to - // read and write. - absl::AnyInvocable data_channel_open_cb = - [](WebRtcSocketWrapper) {}; - - // Called when the data channel is closed. - absl::AnyInvocable data_channel_closed_cb = []() {}; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_DATA_CHANNEL_LISTENER_H_ diff --git a/connections/implementation/mediums/webrtc/local_ice_candidate_listener.h b/connections/implementation/mediums/webrtc/local_ice_candidate_listener.h deleted file mode 100644 index da71236f..00000000 --- a/connections/implementation/mediums/webrtc/local_ice_candidate_listener.h +++ /dev/null @@ -1,42 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ - -#ifndef NO_WEBRTC - -#include "connections/listeners.h" -#include "webrtc/api/jsep.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace nearby { -namespace connections { -namespace mediums { - -// Callbacks from local ice candidate collection. -struct LocalIceCandidateListener { - // Called when a new local ice candidate has been found. - absl::AnyInvocable - local_ice_candidate_found_cb = - nearby::DefaultCallback(); -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_LOCAL_ICE_CANDIDATE_LISTENER_H_ diff --git a/connections/implementation/mediums/webrtc/session_description_wrapper.h b/connections/implementation/mediums/webrtc/session_description_wrapper.h deleted file mode 100644 index ef468120..00000000 --- a/connections/implementation/mediums/webrtc/session_description_wrapper.h +++ /dev/null @@ -1,68 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ - -#ifndef NO_WEBRTC - -#include "webrtc/api/peer_connection_interface.h" - -// Wrapper object around SessionDescriptionInterface*. -// This object owns the SessionDescriptionInterface* unless Release() has been -// called. -class SessionDescriptionWrapper { - public: - SessionDescriptionWrapper() = default; - explicit SessionDescriptionWrapper(webrtc::SessionDescriptionInterface* sdp) - : impl_(sdp) {} - - // Copy constructor that performs a deep copy, i.e. creates a new - // SessionDescriptionInterface. - SessionDescriptionWrapper(const SessionDescriptionWrapper& sdp) { - if (sdp.IsValid()) { - impl_ = webrtc::CreateSessionDescription(sdp.GetType(), sdp.ToString()); - } - } - - SessionDescriptionWrapper(SessionDescriptionWrapper&&) = default; - SessionDescriptionWrapper& operator=(SessionDescriptionWrapper&&) = default; - - // Release the ownership of the SessionDescriptionInterface*. - webrtc::SessionDescriptionInterface* Release() { return impl_.release(); } - - // Returns a string representation of the sdp. Only call this, if IsValid() is - // true. - std::string ToString() const { - std::string str; - impl_->ToString(&str); - return str; - } - - // Returns the SdpType of the SessionDescriptionInterface. Only call this, if - // IsValid() is true. - webrtc::SdpType GetType() const { return impl_->GetType(); } - - const webrtc::SessionDescriptionInterface& GetSdp() { return *impl_; } - - // Return whether this object currently holds a SessionDescriptionInterface. - bool IsValid() const { return impl_ != nullptr; } - - private: - std::unique_ptr impl_; -}; - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SESSION_DESCRIPTION_WRAPPER_H_ diff --git a/connections/implementation/mediums/webrtc/signaling_frames.cc b/connections/implementation/mediums/webrtc/signaling_frames.cc deleted file mode 100644 index 8991c60a..00000000 --- a/connections/implementation/mediums/webrtc/signaling_frames.cc +++ /dev/null @@ -1,135 +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 NO_WEBRTC - -#include "connections/implementation/mediums/webrtc/signaling_frames.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace webrtc_frames { -using WebRtcSignalingFrame = ::location::nearby::mediums::WebRtcSignalingFrame; - -namespace { - -ByteArray FrameToByteArray(const WebRtcSignalingFrame& signaling_frame) { - std::string message; - signaling_frame.SerializeToString(&message); - return ByteArray(message.c_str(), message.size()); -} - -void SetSenderId(const WebrtcPeerId& sender_id, WebRtcSignalingFrame& frame) { - frame.mutable_sender_id()->set_id(sender_id.GetId()); -} - -std::unique_ptr DecodeIceCandidate( - location::nearby::mediums::IceCandidate ice_candidate_proto) { - webrtc::SdpParseError error; - return std::unique_ptr(webrtc::CreateIceCandidate( - ice_candidate_proto.sdp_mid(), ice_candidate_proto.sdp_m_line_index(), - ice_candidate_proto.sdp(), &error)); -} - -} // namespace - -ByteArray EncodeReadyForSignalingPoke(const WebrtcPeerId& sender_id) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::READY_FOR_SIGNALING_POKE_TYPE); - SetSenderId(sender_id, signaling_frame); - signaling_frame.set_allocated_ready_for_signaling_poke( - new location::nearby::mediums::ReadyForSignalingPoke()); - return FrameToByteArray(std::move(signaling_frame)); -} - -ByteArray EncodeOffer(const WebrtcPeerId& sender_id, - const webrtc::SessionDescriptionInterface& offer) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::OFFER_TYPE); - SetSenderId(sender_id, signaling_frame); - std::string offer_str; - offer.ToString(&offer_str); - signaling_frame.mutable_offer() - ->mutable_session_description() - ->set_description(offer_str); - return FrameToByteArray(std::move(signaling_frame)); -} - -ByteArray EncodeAnswer(const WebrtcPeerId& sender_id, - const webrtc::SessionDescriptionInterface& answer) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::ANSWER_TYPE); - SetSenderId(sender_id, signaling_frame); - std::string answer_str; - answer.ToString(&answer_str); - signaling_frame.mutable_answer() - ->mutable_session_description() - ->set_description(answer_str); - return FrameToByteArray(std::move(signaling_frame)); -} - -ByteArray EncodeIceCandidates( - const WebrtcPeerId& sender_id, - const std::vector& - ice_candidates) { - WebRtcSignalingFrame signaling_frame; - signaling_frame.set_type(WebRtcSignalingFrame::ICE_CANDIDATES_TYPE); - SetSenderId(sender_id, signaling_frame); - for (const auto& ice_candidate : ice_candidates) { - *signaling_frame.mutable_ice_candidates()->add_ice_candidates() = - ice_candidate; - } - return FrameToByteArray(std::move(signaling_frame)); -} - -std::unique_ptr DecodeOffer( - const WebRtcSignalingFrame& frame) { - return webrtc::CreateSessionDescription( - webrtc::SdpType::kOffer, - frame.offer().session_description().description()); -} - -std::unique_ptr DecodeAnswer( - const WebRtcSignalingFrame& frame) { - return webrtc::CreateSessionDescription( - webrtc::SdpType::kAnswer, - frame.answer().session_description().description()); -} - -std::vector> DecodeIceCandidates( - const WebRtcSignalingFrame& frame) { - std::vector> ice_candidates; - for (const auto& candidate : frame.ice_candidates().ice_candidates()) { - ice_candidates.push_back(DecodeIceCandidate(candidate)); - } - return ice_candidates; -} - -location::nearby::mediums::IceCandidate EncodeIceCandidate( - const webrtc::IceCandidate& ice_candidate) { - std::string sdp; - ice_candidate.ToString(&sdp); - location::nearby::mediums::IceCandidate ice_candidate_proto; - ice_candidate_proto.set_sdp(sdp); - ice_candidate_proto.set_sdp_mid(ice_candidate.sdp_mid()); - ice_candidate_proto.set_sdp_m_line_index(ice_candidate.sdp_mline_index()); - return ice_candidate_proto; -} - -} // namespace webrtc_frames -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc/signaling_frames.h b/connections/implementation/mediums/webrtc/signaling_frames.h deleted file mode 100644 index 6e13645d..00000000 --- a/connections/implementation/mediums/webrtc/signaling_frames.h +++ /dev/null @@ -1,60 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_ - -#ifndef NO_WEBRTC - -#include - -#include "connections/implementation/mediums/webrtc_peer_id.h" -#include "internal/platform/byte_array.h" -#include "proto/mediums/web_rtc_signaling_frames.pb.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace webrtc_frames { - -ByteArray EncodeReadyForSignalingPoke(const WebrtcPeerId& sender_id); - -ByteArray EncodeOffer(const WebrtcPeerId& sender_id, - const webrtc::SessionDescriptionInterface& offer); -ByteArray EncodeAnswer(const WebrtcPeerId& sender_id, - const webrtc::SessionDescriptionInterface& answer); - -ByteArray EncodeIceCandidates( - const WebrtcPeerId& sender_id, - const std::vector& ice_candidates); -location::nearby::mediums::IceCandidate EncodeIceCandidate( - const webrtc::IceCandidate& ice_candidate); - -std::unique_ptr DecodeOffer( - const location::nearby::mediums::WebRtcSignalingFrame& frame); -std::unique_ptr DecodeAnswer( - const location::nearby::mediums::WebRtcSignalingFrame& frame); - -std::vector> DecodeIceCandidates( - const location::nearby::mediums::WebRtcSignalingFrame& frame); - -} // namespace webrtc_frames -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SIGNALING_FRAMES_H_ diff --git a/connections/implementation/mediums/webrtc/signaling_frames_test.cc b/connections/implementation/mediums/webrtc/signaling_frames_test.cc deleted file mode 100644 index de5f92bb..00000000 --- a/connections/implementation/mediums/webrtc/signaling_frames_test.cc +++ /dev/null @@ -1,198 +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 "connections/implementation/mediums/webrtc/signaling_frames.h" - -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "connections/implementation/mediums/webrtc_peer_id.h" -#include "google/protobuf/text_format.h" -#include "webrtc/api/jsep.h" - -namespace nearby { -namespace connections { -namespace mediums { -namespace webrtc_frames { - -namespace { - -using ::location::nearby::mediums::IceCandidate; -using ::location::nearby::mediums::WebRtcSignalingFrame; -const char kSampleSdp[] = - "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 " - "0\r\na=msid-semantic: WMS\r\n"; - -const char kIceCandidateSdp1[] = - "a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host"; -const char kIceCandidateSdp2[] = - "a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr"; - -const char kIceSdpMid[] = "data"; -const int kIceSdpMLineIndex = 0; - -const char kOfferProto[] = R"( - sender_id { id: "abc" } - type: OFFER_TYPE - offer { - session_description { - description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n" - } - } - )"; - -const char kAnswerProto[] = R"( - sender_id { id: "abc" } - type: ANSWER_TYPE - answer { - session_description { - description: "v=0\r\no=- 7859371131 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=msid-semantic: WMS\r\n" - } - } - )"; - -const char kIceCandidatesProto[] = R"( - sender_id { id: "abc" } - type: ICE_CANDIDATES_TYPE - ice_candidates { - ice_candidates { - sdp: "candidate:1 1 udp 2130706431 10.0.1.1 8998 typ host generation 0" - sdp_mid: "data" - sdp_m_line_index: 0 - } - ice_candidates { - sdp: "candidate:2 1 udp 1694498815 192.0.2.3 45664 typ srflx generation 0" - sdp_mid: "data" - sdp_m_line_index: 0 - } - } - )"; -} // namespace - -TEST(SignalingFramesTest, SignalingPoke) { - WebrtcPeerId sender_id("abc"); - ByteArray encoded_poke = EncodeReadyForSignalingPoke(sender_id); - - WebRtcSignalingFrame frame; - frame.ParseFromString(std::string(encoded_poke.data(), encoded_poke.size())); - - EXPECT_THAT(frame, protobuf_matchers::EqualsProto(R"pb( - sender_id { id: "abc" } - type: READY_FOR_SIGNALING_POKE_TYPE - ready_for_signaling_poke {} - )pb")); -} - -TEST(SignalingFramesTest, EncodeValidOffer) { - WebrtcPeerId sender_id("abc"); - std::unique_ptr offer = - webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, kSampleSdp); - ByteArray encoded_offer = EncodeOffer(sender_id, *offer); - - WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_offer.data(), encoded_offer.size())); - - EXPECT_THAT(frame, protobuf_matchers::EqualsProto(kOfferProto)); -} - -TEST(SignaingFramesTest, DecodeValidOffer) { - WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kOfferProto, &frame); - std::unique_ptr decoded_offer = - DecodeOffer(frame); - - EXPECT_EQ(webrtc::SdpType::kOffer, decoded_offer->GetType()); - std::string description; - decoded_offer->ToString(&description); - EXPECT_EQ(kSampleSdp, description); -} - -TEST(SignalingFramesTest, EncodeValidAnswer) { - WebrtcPeerId sender_id("abc"); - std::unique_ptr answer( - webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, kSampleSdp)); - ByteArray encoded_answer = EncodeAnswer(sender_id, *answer); - - WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_answer.data(), encoded_answer.size())); - - EXPECT_THAT(frame, protobuf_matchers::EqualsProto(kAnswerProto)); -} - -TEST(SignalingFramesTest, DecodeValidAnswer) { - WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kAnswerProto, &frame); - std::unique_ptr decoded_answer = - DecodeAnswer(frame); - - EXPECT_EQ(webrtc::SdpType::kAnswer, decoded_answer->GetType()); - std::string description; - decoded_answer->ToString(&description); - EXPECT_EQ(kSampleSdp, description); -} - -TEST(SignalingFramesTest, EncodeValidIceCandidates) { - WebrtcPeerId sender_id("abc"); - webrtc::SdpParseError error; - - std::vector> ice_candidates; - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error)); - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error)); - std::vector encoded_candidates_vec; - for (const auto& ice_candidate : ice_candidates) { - encoded_candidates_vec.push_back(EncodeIceCandidate(*ice_candidate)); - } - ByteArray encoded_candidates = - EncodeIceCandidates(sender_id, encoded_candidates_vec); - - WebRtcSignalingFrame frame; - frame.ParseFromString( - std::string(encoded_candidates.data(), encoded_candidates.size())); - - EXPECT_THAT(frame, protobuf_matchers::EqualsProto(kIceCandidatesProto)); -} - -TEST(SignalingFramesTest, DecodeValidIceCandidates) { - webrtc::SdpParseError error; - std::vector> ice_candidates; - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp1, &error)); - ice_candidates.emplace_back(webrtc::CreateIceCandidate( - kIceSdpMid, kIceSdpMLineIndex, kIceCandidateSdp2, &error)); - - WebRtcSignalingFrame frame; - proto2::TextFormat::ParseFromString(kIceCandidatesProto, &frame); - std::vector> decoded_candidates = - DecodeIceCandidates(frame); - - ASSERT_EQ(2u, decoded_candidates.size()); - for (int i = 0; i < static_cast(decoded_candidates.size()); i++) { - EXPECT_TRUE(ice_candidates[i]->candidate().IsEquivalent( - decoded_candidates[i]->candidate())); - EXPECT_EQ(ice_candidates[i]->sdp_mid(), decoded_candidates[i]->sdp_mid()); - EXPECT_EQ(ice_candidates[i]->sdp_mline_index(), - decoded_candidates[i]->sdp_mline_index()); - } -} - -} // namespace webrtc_frames -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc b/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc deleted file mode 100644 index aca93c67..00000000 --- a/connections/implementation/mediums/webrtc/webrtc_socket_impl.cc +++ /dev/null @@ -1,202 +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 -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/pipe.h" -#ifndef NO_WEBRTC - -#include "connections/implementation/mediums/webrtc/webrtc_socket_impl.h" -#include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" - -namespace nearby { -namespace connections { -namespace mediums { - -// OutputStreamImpl -Exception WebRtcSocket::OutputStreamImpl::Write(absl::string_view data) { - if (data.size() > kMaxDataSize) { - LOG(WARNING) << "Sending data larger than 1MB"; - return {Exception::kIo}; - } - - socket_->BlockUntilSufficientSpaceInBuffer(data.size()); - - if (socket_->IsClosed()) { - LOG(WARNING) << "Tried sending message while socket is closed"; - return {Exception::kIo}; - } - - if (!socket_->SendMessage(ByteArray::FromStringView(data))) { - LOG(INFO) << "Unable to write data to socket."; - return {Exception::kIo}; - } - return {Exception::kSuccess}; -} - -Exception WebRtcSocket::OutputStreamImpl::Flush() { - // Java implementation is empty. - return {Exception::kSuccess}; -} - -Exception WebRtcSocket::OutputStreamImpl::Close() { - socket_->Close(); - return {Exception::kSuccess}; -} - -// WebRtcSocket -WebRtcSocket::WebRtcSocket( - const std::string& name, - webrtc::scoped_refptr data_channel) - : name_(name), data_channel_(std::move(data_channel)) { - LOG(INFO) << "WebRtcSocket::WebRtcSocket(" << name_ << ") this: " << this; - std::tie(pipe_input_, pipe_output_) = CreatePipe(); - data_channel_->RegisterObserver(this); -} - -WebRtcSocket::~WebRtcSocket() { - LOG(INFO) << "WebRtcSocket::~WebRtcSocket(" << name_ << ") this: " << this; - - if (!IsClosed()) { - data_channel_->UnregisterObserver(); - Close(); - } - - LOG(INFO) << "WebRtcSocket::~WebRtcSocket(" << name_ << ") this: " << this - << " done"; -} - -InputStream& WebRtcSocket::GetInputStream() { return *pipe_input_; } - -OutputStream& WebRtcSocket::GetOutputStream() { return output_stream_; } - -Exception WebRtcSocket::Close() { - LOG(INFO) << "WebRtcSocket::Close(" << name_ << ") this: " << this; - if (closed_.Set(true)) return {Exception::kSuccess}; - - ClosePipe(); - // NOTE: This call blocks and triggers a state change on the siginaling thread - // to 'closing' but does not block until 'closed' is sent so the data channel - // is not fully closed when this call is done. - data_channel_->Close(); - LOG(INFO) << "WebRtcSocket::Close(" << name_ << ") this: " << this << " done"; - return {Exception::kSuccess}; -} - -void WebRtcSocket::OnStateChange() { - // Running on the signaling thread right now. - LOG(ERROR) << "WebRtcSocket::OnStateChange() webrtc data channel state: " - << webrtc::DataChannelInterface::DataStateString( - data_channel_->state()); - switch (data_channel_->state()) { - case webrtc::DataChannelInterface::DataState::kConnecting: - break; - case webrtc::DataChannelInterface::DataState::kOpen: - // We implicitly depend on the |socket_listener_| to offload from - // the signaling thread so it does not get blocked. - socket_listener_.socket_ready_cb(this); - break; - case webrtc::DataChannelInterface::DataState::kClosing: - break; - case webrtc::DataChannelInterface::DataState::kClosed: - LOG(ERROR) << "WebRtcSocket::OnStateChange() unregistering data " - "channel observer."; - // This will trigger a destruction of the owning connection flow - // We implicitly depend on the |socket_listener_| to offload from - // the signaling thread so it does not get blocked. - socket_listener_.socket_closed_cb(this); - - if (!closed_.Set(true)) { - OffloadFromSignalingThread([this] { ClosePipe(); }); - } - break; - } -} -void WebRtcSocket::OnMessage(const webrtc::DataBuffer& buffer) { - // This is a data channel callback on the signaling thread, lets off load so - // we don't block signaling. - OffloadFromSignalingThread( - [this, buffer = ByteArray(buffer.data.data(), buffer.size())] { - if (!pipe_output_->Write(buffer.AsStringView()).Ok()) { - Close(); - return; - } - - if (!pipe_output_->Flush().Ok()) { - Close(); - } - }); -} - -void WebRtcSocket::OnBufferedAmountChange(uint64_t sent_data_size) { - // This is a data channel callback on the signaling thread, lets off load so - // we don't block signaling. - OffloadFromSignalingThread([this] { WakeUpWriter(); }); -} - -bool WebRtcSocket::SendMessage(const ByteArray& data) { - return data_channel_->Send( - webrtc::DataBuffer(std::string(data.data(), data.size()))); -} - -bool WebRtcSocket::IsClosed() { return closed_.Get(); } - -void WebRtcSocket::ClosePipe() { - LOG(INFO) << "WebRtcSocket::ClosePipe(" << name_ << ") this: " << this; - // This is thread-safe to close these sockets even if a read or write is in - // process on another thread, Close will wait for the exclusive mutex before - // setting state. - pipe_input_->Close(); - pipe_output_->Close(); - WakeUpWriter(); - LOG(INFO) << "WebRtcSocket::ClosePipe(" << name_ << ") this: " << this - << " done"; -} - -// Must not be called on signalling thread. -void WebRtcSocket::WakeUpWriter() { - MutexLock lock(&backpressure_mutex_); - buffer_variable_.Notify(); -} - -void WebRtcSocket::SetSocketListener(SocketListener&& listener) { - socket_listener_ = std::move(listener); -} - -void WebRtcSocket::BlockUntilSufficientSpaceInBuffer(int length) { - MutexLock lock(&backpressure_mutex_); - while (!IsClosed() && - (data_channel_->buffered_amount() + length > kMaxDataSize)) { - // TODO(himanshujaju): Add wait with timeout. - buffer_variable_.Wait(); - } -} - -void WebRtcSocket::OffloadFromSignalingThread(Runnable runnable) { - single_thread_executor_.Execute(std::move(runnable)); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc/webrtc_socket_impl.h b/connections/implementation/mediums/webrtc/webrtc_socket_impl.h deleted file mode 100644 index 109367b7..00000000 --- a/connections/implementation/mediums/webrtc/webrtc_socket_impl.h +++ /dev/null @@ -1,129 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_IMPL_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_IMPL_H_ - -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "internal/platform/listeners.h" -#include "internal/platform/runnable.h" -#ifndef NO_WEBRTC -#include "internal/platform/atomic_boolean.h" -#include "internal/platform/condition_variable.h" -#include "internal/platform/input_stream.h" -#include "internal/platform/mutex.h" -#include "internal/platform/output_stream.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/platform/socket.h" - -namespace nearby { -namespace connections { -namespace mediums { - -// Maximum data size: 1 MB -constexpr int kMaxDataSize = 1 * 1024 * 1024; - -// Defines the Socket implementation specific to WebRTC, which uses the WebRTC -// data channel to send and receive messages. -// -// Messages are buffered here to prevent the data channel from overflowing, -// which could lead to data loss. -class WebRtcSocket : public Socket, public webrtc::DataChannelObserver { - public: - WebRtcSocket( - const std::string& name, - webrtc::scoped_refptr data_channel); - ~WebRtcSocket() override; - - WebRtcSocket(const WebRtcSocket& other) = delete; - WebRtcSocket& operator=(const WebRtcSocket& other) = delete; - - // Overrides for nearby::Socket: - InputStream& GetInputStream() override; - OutputStream& GetOutputStream() override; - Exception Close() override; - - // webrtc::DataChannelObserver: - void OnStateChange() override; - void OnMessage(const webrtc::DataBuffer& buffer) override; - void OnBufferedAmountChange(uint64_t sent_data_size) override; - - // Listener class the gets called when the socket is ready or closed - struct SocketListener { - absl::AnyInvocable socket_ready_cb = - DefaultCallback(); - absl::AnyInvocable socket_closed_cb = - DefaultCallback(); - }; - - void SetSocketListener(SocketListener&& listener); - - private: - class OutputStreamImpl : public OutputStream { - public: - explicit OutputStreamImpl(WebRtcSocket* const socket) : socket_(socket) {} - ~OutputStreamImpl() override = default; - - OutputStreamImpl(const OutputStreamImpl& other) = delete; - OutputStreamImpl& operator=(const OutputStreamImpl& other) = delete; - - // OutputStream: - Exception Write(absl::string_view data) override; - Exception Flush() override; - Exception Close() override; - - private: - // |this| OutputStreamImpl is owned by |socket_|. - WebRtcSocket* const socket_; - }; - - void WakeUpWriter(); - bool IsClosed(); - void ClosePipe(); - bool SendMessage(const ByteArray& data); - void BlockUntilSufficientSpaceInBuffer(int length); - void OffloadFromSignalingThread(Runnable runnable); - - std::string name_; - webrtc::scoped_refptr data_channel_; - - std::unique_ptr pipe_input_; - std::unique_ptr pipe_output_; - OutputStreamImpl output_stream_{this}; - - AtomicBoolean closed_{false}; - - SocketListener socket_listener_; - - mutable Mutex backpressure_mutex_; - ConditionVariable buffer_variable_{&backpressure_mutex_}; - - // This should be destroyed first to ensure any remaining tasks flushed on - // shutdown get run while the other members are still alive. - SingleThreadExecutor single_thread_executor_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_IMPL_H_ diff --git a/connections/implementation/mediums/webrtc/webrtc_socket_impl_test.cc b/connections/implementation/mediums/webrtc/webrtc_socket_impl_test.cc deleted file mode 100644 index 78ec1771..00000000 --- a/connections/implementation/mediums/webrtc/webrtc_socket_impl_test.cc +++ /dev/null @@ -1,247 +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 "connections/implementation/mediums/webrtc/webrtc_socket_impl.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/exception.h" -#include "webrtc/api/data_channel_interface.h" - -namespace nearby { -namespace connections { -namespace mediums { - -namespace { - -// using TestPlatform = platform::ImplementationPlatform; - -const char kSocketName[] = "TestSocket"; - -class MockDataChannel - : public webrtc::RefCountedObject { - public: - MOCK_METHOD(void, RegisterObserver, (webrtc::DataChannelObserver*)); - MOCK_METHOD(void, UnregisterObserver, ()); - - MOCK_METHOD(std::string, label, (), (const)); - - MOCK_METHOD(bool, reliable, (), (const)); - MOCK_METHOD(int, id, (), (const)); - MOCK_METHOD(DataState, state, (), (const)); - MOCK_METHOD(uint32_t, messages_sent, (), (const)); - MOCK_METHOD(uint64_t, bytes_sent, (), (const)); - MOCK_METHOD(uint32_t, messages_received, (), (const)); - MOCK_METHOD(uint64_t, bytes_received, (), (const)); - - MOCK_METHOD(uint64_t, buffered_amount, (), (const)); - - MOCK_METHOD(void, Close, ()); - - MOCK_METHOD(bool, Send, (const webrtc::DataBuffer&)); -}; - -} // namespace - -TEST(WebRtcSocketTest, ReadFromSocket) { - const char* message = "message"; - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - webrtc_socket.OnMessage(webrtc::DataBuffer{message}); - ExceptionOr result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{message}); -} - -TEST(WebRtcSocketTest, ReadMultipleMessages) { - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - webrtc_socket.OnMessage(webrtc::DataBuffer{"Me"}); - webrtc_socket.OnMessage(webrtc::DataBuffer{"ssa"}); - webrtc_socket.OnMessage(webrtc::DataBuffer{"ge"}); - - ExceptionOr result; - - // This behaviour is different from the Java code - result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{"Me"}); - - result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{"ssa"}); - - result = webrtc_socket.GetInputStream().Read(7); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(result.result(), ByteArray{"ge"}); -} - -TEST(WebRtcSocketTest, WriteToSocket) { - absl::string_view kMessage{"Message"}; - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - EXPECT_CALL(*mock_data_channel, Send(testing::_)) - .WillRepeatedly(testing::Return(true)); - EXPECT_TRUE(webrtc_socket.GetOutputStream().Write(kMessage).Ok()); -} - -TEST(WebRtcSocketTest, SendDataBiggerThanMax) { - std::string kMessage(kMaxDataSize + 1, '0'); - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0); - EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), - Exception{Exception::kIo}); -} - -TEST(WebRtcSocketTest, WriteToDataChannelFails) { - absl::string_view kMessage{"Message"}; - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - ON_CALL(*mock_data_channel, Send(testing::_)) - .WillByDefault(testing::Return(false)); - EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), - Exception{Exception::kIo}); -} - -TEST(WebRtcSocketTest, Close) { - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - EXPECT_CALL(*mock_data_channel, Close()); - - int socket_closed_cb_called = 0; - - webrtc_socket.SetSocketListener( - {.socket_closed_cb = [&](WebRtcSocket* socket) { - socket_closed_cb_called++; - }}); - webrtc_socket.Close(); - - // We have to fake the close event to get the callback to run. - ON_CALL(*mock_data_channel, state()) - .WillByDefault( - testing::Return(webrtc::DataChannelInterface::DataState::kClosed)); - - webrtc_socket.OnStateChange(); - - EXPECT_EQ(socket_closed_cb_called, 1); -} - -TEST(WebRtcSocketTest, WriteOnClosedChannel) { - absl::string_view kMessage{"Message"}; - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - webrtc_socket.Close(); - - EXPECT_CALL(*mock_data_channel, Send(testing::_)).Times(0); - EXPECT_EQ(webrtc_socket.GetOutputStream().Write(kMessage), - Exception{Exception::kIo}); -} - -TEST(WebRtcSocketTest, ReadFromClosedChannel) { - absl::string_view kMessage{"Message"}; - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - ON_CALL(*mock_data_channel, Send(testing::_)) - .WillByDefault(testing::Return(true)); - - webrtc_socket.GetOutputStream().Write(kMessage); - webrtc_socket.Close(); - - EXPECT_TRUE(webrtc_socket.GetInputStream().Read(7).GetResult().Empty()); -} - -TEST(WebRtcSocketTest, DataChannelCloseEventCleansUp) { - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - ON_CALL(*mock_data_channel, state()) - .WillByDefault( - testing::Return(webrtc::DataChannelInterface::DataState::kClosed)); - - webrtc_socket.OnStateChange(); - - EXPECT_TRUE(webrtc_socket.GetInputStream().Read(7).GetResult().Empty()); - - // Calling Close again should be safe even if the channel is already shut - // down. - webrtc_socket.Close(); -} - -TEST(WebRtcSocketTest, OpenStateTriggersCallback) { - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - int socket_ready_cb_called = 0; - - webrtc_socket.SetSocketListener( - {.socket_ready_cb = [&](WebRtcSocket* socket) { - socket_ready_cb_called++; - }}); - - ON_CALL(*mock_data_channel, state()) - .WillByDefault( - testing::Return(webrtc::DataChannelInterface::DataState::kOpen)); - - webrtc_socket.OnStateChange(); - - EXPECT_EQ(socket_ready_cb_called, 1); -} - -TEST(WebRtcSocketTest, CloseStateTriggersCallback) { - webrtc::scoped_refptr mock_data_channel( - new MockDataChannel()); - WebRtcSocket webrtc_socket(kSocketName, mock_data_channel); - - int socket_closed_cb_called = 0; - - webrtc_socket.SetSocketListener( - {.socket_closed_cb = [&](WebRtcSocket* socket) { - socket_closed_cb_called++; - }}); - - ON_CALL(*mock_data_channel, state()) - .WillByDefault( - testing::Return(webrtc::DataChannelInterface::DataState::kClosed)); - - webrtc_socket.OnStateChange(); - - EXPECT_EQ(socket_closed_cb_called, 1); -} - -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/webrtc_peer_id.cc b/connections/implementation/mediums/webrtc_peer_id.cc index 801d40c6..5e7f6224 100644 --- a/connections/implementation/mediums/webrtc_peer_id.cc +++ b/connections/implementation/mediums/webrtc_peer_id.cc @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef NO_WEBRTC - #include "connections/implementation/mediums/webrtc_peer_id.h" -#include +#include #include "absl/strings/ascii.h" #include "absl/strings/escaping.h" #include "connections/implementation/mediums/utils.h" +#include "internal/platform/byte_array.h" namespace nearby { namespace connections { @@ -52,5 +51,3 @@ bool WebrtcPeerId::IsValid() const { return !id_.empty(); } } // namespace mediums } // namespace connections } // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc_peer_id.h b/connections/implementation/mediums/webrtc_peer_id.h index 93013902..e97deee3 100644 --- a/connections/implementation/mediums/webrtc_peer_id.h +++ b/connections/implementation/mediums/webrtc_peer_id.h @@ -15,9 +15,6 @@ #ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ #define CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ -#ifndef NO_WEBRTC - -#include #include #include "internal/platform/byte_array.h" @@ -49,6 +46,4 @@ class WebrtcPeerId { } // namespace connections } // namespace nearby -#endif - #endif // CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_H_ diff --git a/connections/implementation/mediums/webrtc_peer_id_stub.cc b/connections/implementation/mediums/webrtc_peer_id_stub.cc deleted file mode 100644 index 1b74dad2..00000000 --- a/connections/implementation/mediums/webrtc_peer_id_stub.cc +++ /dev/null @@ -1,39 +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. - -#ifdef NO_WEBRTC - -#include "connections/implementation/mediums/webrtc_peer_id_stub.h" - -#include - -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "connections/implementation/mediums/utils.h" - -namespace nearby { -namespace connections { -namespace mediums { - -WebrtcPeerId WebrtcPeerId::FromRandom() { return {}; } - -WebrtcPeerId WebrtcPeerId::FromSeed(const ByteArray& seed) { return {}; } - -bool WebrtcPeerId::IsValid() const { return false; } - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc_peer_id_stub.h b/connections/implementation/mediums/webrtc_peer_id_stub.h deleted file mode 100644 index 8d249a8c..00000000 --- a/connections/implementation/mediums/webrtc_peer_id_stub.h +++ /dev/null @@ -1,54 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_STUB_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_STUB_H_ - -#ifdef NO_WEBRTC - -#include -#include - -#include "internal/platform/byte_array.h" - -namespace nearby { -namespace connections { -namespace mediums { - -// WebrtcPeerId is used as an identifier to exchange SDP messages to establish -// WebRTC p2p connection. An empty WebrtcPeerId is considered to be invalid. -class WebrtcPeerId { - public: - WebrtcPeerId() = default; - explicit WebrtcPeerId(const std::string& id) : id_(id) {} - ~WebrtcPeerId() = default; - - static WebrtcPeerId FromRandom(); - static WebrtcPeerId FromSeed(const ByteArray& seed); - - bool IsValid() const; - - const std::string& GetId() const { return id_; } - - private: - std::string id_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_PEER_ID_STUB_H_ diff --git a/connections/implementation/mediums/webrtc_socket.h b/connections/implementation/mediums/webrtc_socket.h index 724e247a..3881c2f0 100644 --- a/connections/implementation/mediums/webrtc_socket.h +++ b/connections/implementation/mediums/webrtc_socket.h @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2026 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,44 +15,57 @@ #ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_SOCKET_H_ #define CORE_INTERNAL_MEDIUMS_WEBRTC_SOCKET_H_ +#include + +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" #include "internal/platform/exception.h" -#ifndef NO_WEBRTC - -#include - -#include "connections/implementation/mediums/webrtc/webrtc_socket_impl.h" +#include "internal/platform/input_stream.h" +#include "internal/platform/output_stream.h" +#include "internal/platform/socket.h" namespace nearby { namespace connections { namespace mediums { -class WebRtcSocketWrapper final { +// A base implementation that creates a non-working WebRtcSocket that can be +// used as a placeholder when WebRTC is disabled. +class WebRtcSocket : public Socket { public: - WebRtcSocketWrapper() = default; - WebRtcSocketWrapper(const WebRtcSocketWrapper&) = default; - WebRtcSocketWrapper& operator=(const WebRtcSocketWrapper&) = default; - explicit WebRtcSocketWrapper(std::unique_ptr socket) - : impl_(socket.release()) {} - ~WebRtcSocketWrapper() = default; + ~WebRtcSocket() override = default; - InputStream& GetInputStream() { return impl_->GetInputStream(); } + InputStream& GetInputStream() override { return fake_input_stream_; } - OutputStream& GetOutputStream() { return impl_->GetOutputStream(); } + OutputStream& GetOutputStream() override { return fake_output_stream_; } - Exception Close() { return impl_->Close(); } + Exception Close() override { return {Exception::kSuccess}; } - bool IsValid() const { return impl_ != nullptr; } - - WebRtcSocket& GetImpl() { return *impl_; } + virtual bool IsValid() const { return false; } private: - std::shared_ptr impl_; + class FakeInputStream : public InputStream { + public: + ExceptionOr Read(std::int64_t size) override { + return {Exception::kSuccess}; + } + Exception Close() override { return {Exception::kSuccess}; } + }; + + class FakeOutputStream : public OutputStream { + public: + Exception Write(absl::string_view data) override { + return {Exception::kSuccess}; + } + Exception Flush() override { return {Exception::kSuccess}; } + Exception Close() override { return {Exception::kSuccess}; } + }; + + FakeInputStream fake_input_stream_; + FakeOutputStream fake_output_stream_; }; } // namespace mediums } // namespace connections } // namespace nearby -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_WEBRTC_SOCKET_H_ +#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SOCKET_H_ diff --git a/connections/implementation/mediums/webrtc_socket_stub.h b/connections/implementation/mediums/webrtc_socket_stub.h deleted file mode 100644 index f3f104ef..00000000 --- a/connections/implementation/mediums/webrtc_socket_stub.h +++ /dev/null @@ -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. - -#ifndef CORE_INTERNAL_MEDIUMS_WEBRTC_SOCKET_STUB_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_SOCKET_STUB_H_ - -#ifdef NO_WEBRTC - -#include - -#include "internal/platform/input_stream.h" -#include "internal/platform/output_stream.h" - -namespace nearby { -namespace connections { -namespace mediums { -class FakeInputStream : public InputStream { - public: - ExceptionOr Read(std::int64_t size) { - return {Exception::kSuccess}; - } - Exception Close() { return {Exception::kSuccess}; } -}; - -class FakeOutputStream : public OutputStream { - public: - Exception Write(absl::string_view data) override { - return {Exception::kSuccess}; - } - Exception Flush() override { return {Exception::kSuccess}; } - Exception Close() override { return {Exception::kSuccess}; } -}; - -class WebRtcSocketWrapper final { - public: - WebRtcSocketWrapper() = default; - WebRtcSocketWrapper(const WebRtcSocketWrapper&) = default; - WebRtcSocketWrapper& operator=(const WebRtcSocketWrapper&) = default; - ~WebRtcSocketWrapper() = default; - - InputStream& GetInputStream() { return fake_input_stream_; } - - OutputStream& GetOutputStream() { return fake_output_stream_; } - - void Close() {} - - bool IsValid() const { return false; } - - private: - FakeInputStream fake_input_stream_; - FakeOutputStream fake_output_stream_; -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_SOCKET_STUB_H_ diff --git a/connections/implementation/mediums/webrtc_stub.cc b/connections/implementation/mediums/webrtc_stub.cc deleted file mode 100644 index 385fc882..00000000 --- a/connections/implementation/mediums/webrtc_stub.cc +++ /dev/null @@ -1,67 +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. - -#ifdef NO_WEBRTC - -#include "connections/implementation/mediums/webrtc_stub.h" - -#include -#include - -#include "connections/implementation/mediums/webrtc_socket_stub.h" -#include "internal/platform/cancelable_alarm.h" -#include "internal/platform/expected.h" -#include "internal/platform/future.h" -#include "internal/platform/listeners.h" - -namespace nearby { -namespace connections { -namespace mediums { -using ::location::nearby::connections::LocationHint; -using ::location::nearby::proto::connections::OperationResultCode; - -WebRtc::WebRtc() = default; - -WebRtc::~WebRtc() {} - -std::string WebRtc::GetDefaultCountryCode() { return "US"; } - -bool WebRtc::IsAvailable() { return false; } - -bool WebRtc::IsAcceptingConnections(const std::string& service_id) { - return false; -} - -bool WebRtc::StartAcceptingConnections(const std::string& service_id, - const WebrtcPeerId& self_peer_id, - const LocationHint& location_hint, - AcceptedConnectionCallback callback) { - return false; -} - -void WebRtc::StopAcceptingConnections(const std::string& service_id) {} - -ErrorOr WebRtc::Connect( - const std::string& service_id, const WebrtcPeerId& remote_peer_id, - const LocationHint& location_hint, CancellationFlag* cancellation_flag) { - return {Error(OperationResultCode::DETAIL_UNKNOWN)}; -} - -bool WebRtc::IsUsingCellular() { return false; } - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/mediums/webrtc_stub.h b/connections/implementation/mediums/webrtc_stub.h deleted file mode 100644 index 787acd7a..00000000 --- a/connections/implementation/mediums/webrtc_stub.h +++ /dev/null @@ -1,86 +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 CORE_INTERNAL_MEDIUMS_WEBRTC_STUB_H_ -#define CORE_INTERNAL_MEDIUMS_WEBRTC_STUB_H_ - -#ifdef NO_WEBRTC - -#include -#include -#include -#include - -#include "connections/implementation/mediums/webrtc_peer_id_stub.h" -#include "connections/implementation/mediums/webrtc_socket_stub.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" -#include "internal/platform/cancellation_flag.h" -#include "internal/platform/expected.h" -#include "internal/platform/listeners.h" - -namespace nearby { -namespace connections { -namespace mediums { - -// Entry point for connecting a data channel between two devices via WebRtc. -class WebRtc { - public: - // Callback that is invoked when a new connection is accepted. - using AcceptedConnectionCallback = - absl::AnyInvocable; - WebRtc(); - ~WebRtc(); - - // Gets the default two-letter country code associated with current locale. - // For example, en_US locale resolves to "US". - std::string GetDefaultCountryCode(); - - // Returns if WebRtc is available as a medium for nearby to transport data. - // Runs on @MainThread. - bool IsAvailable(); - - // Returns if the device is accepting connection with specific service id. - // Runs on @MainThread. - bool IsAcceptingConnections(const std::string& service_id); - - // Prepares the device to accept incoming WebRtc connections. Returns a - // boolean value indicating if the device has started accepting connections. - // Runs on @MainThread. - bool StartAcceptingConnections( - const std::string& service_id, const WebrtcPeerId& self_peer_id, - const location::nearby::connections::LocationHint& location_hint, - AcceptedConnectionCallback callback); - - // Try to stop (accepting) the specific connection with provided service id. - // Runs on @MainThread - void StopAcceptingConnections(const std::string& service_id); - - // Initiates a WebRtc connection with peer device identified by |peer_id| - // with internal retry for maximum attempts of kConnectAttemptsLimit. - // Runs on @MainThread. - ErrorOr Connect( - const std::string& service_id, const WebrtcPeerId& peer_id, - const location::nearby::connections::LocationHint& location_hint, - CancellationFlag* cancellation_flag); - - bool IsUsingCellular(); -}; - -} // namespace mediums -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_MEDIUMS_WEBRTC_STUB_H_ diff --git a/connections/implementation/mediums/webrtc_test.cc b/connections/implementation/mediums/webrtc_test.cc deleted file mode 100644 index 061dbd4c..00000000 --- a/connections/implementation/mediums/webrtc_test.cc +++ /dev/null @@ -1,641 +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 "connections/implementation/mediums/webrtc.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "connections/implementation/mediums/webrtc_peer_id.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/cancellation_flag.h" -#include "internal/platform/exception.h" -#include "internal/platform/expected.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/medium_environment.h" -#include "internal/platform/webrtc.h" -#include "internal/test/fake_webrtc.h" - -namespace nearby { -namespace connections { -namespace mediums { - -namespace { - -using FeatureFlags = FeatureFlags::Flags; -using ::location::nearby::connections::LocationHint; - -struct WebRtcTestParams { - FeatureFlags feature_flags; - bool non_cellular; -}; - -class TestWebRtc : public WebRtc { - public: - explicit TestWebRtc(std::unique_ptr medium) - : WebRtc(std::move(medium)) {} - - int connect_attempts_count(std::string service_id) { - return service_id_to_connect_attempts_count_map_[service_id]; - } -}; - -class WebRtcTest : public ::testing::TestWithParam { - protected: - using MockAcceptedCallback = testing::MockFunction; - - MediumEnvironment& env_{MediumEnvironment::Instance()}; -}; - -// Tests the flow when the two devices exchange SDP messages and connect to each -// other but the signaling channel is closed before sending the data. -TEST_P(WebRtcTest, ConnectBothDevices_ShutdownSignaling_SendData) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - env_.SetFeatureFlags(params.feature_flags); - WebRtc receiver, sender; - WebRtcSocketWrapper receiver_socket; - const WebrtcPeerId self_id("self_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - absl::string_view message("message xyz"); - - receiver.StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - CancellationFlag flag; - ErrorOr sender_socket_result = sender.Connect( - service_id, self_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - ExceptionOr devices_connected = connected.Get(); - ASSERT_TRUE(devices_connected.ok()); - EXPECT_TRUE(devices_connected.result()); - - // Only shuts down signaling channel. - receiver.StopAcceptingConnections(service_id); - - sender_socket_result.value().GetOutputStream().Write(message); - ExceptionOr received_msg = - receiver_socket.GetInputStream().Read(/*size=*/32); - ASSERT_TRUE(received_msg.ok()); - EXPECT_EQ(message, received_msg.result().AsStringView()); - env_.Stop(); -} - -TEST_P(WebRtcTest, CanCancelConnect) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - env_.SetFeatureFlags(params.feature_flags); - WebRtc receiver, sender; - WebRtcSocketWrapper receiver_socket; - const WebrtcPeerId self_id("self_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - absl::string_view message("message"); - - receiver.StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - CancellationFlag flag(true); - ErrorOr sender_socket_result = sender.Connect( - service_id, self_id, location_hint, &flag, params.non_cellular); - // If FeatureFlag is disabled, Cancelled is false as no-op. - if (!params.feature_flags.enable_cancellation_flag) { - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - ExceptionOr devices_connected = connected.Get(); - ASSERT_TRUE(devices_connected.ok()); - EXPECT_TRUE(devices_connected.result()); - - sender_socket_result.value().GetOutputStream().Write(message); - ExceptionOr received_msg = - receiver_socket.GetInputStream().Read(/*size=*/32); - ASSERT_TRUE(received_msg.ok()); - EXPECT_EQ(message, received_msg.result().AsStringView()); - - receiver_socket.Close(); - } else { - EXPECT_TRUE(sender_socket_result.has_error()); - } - env_.Stop(); -} - -// Basic test to check that device is accepting connections when initialized. -TEST_P(WebRtcTest, NotAcceptingConnections) { - env_.Start({.webrtc_enabled = true}); - WebRtc webrtc; - ASSERT_TRUE(webrtc.IsAvailable()); - EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{})); - env_.Stop(); -} - -// Tests the flow when the device tries to accept connections twice. In this -// case, only the first call is successful and subsequent calls fail. -TEST_P(WebRtcTest, StartAcceptingConnectionTwice) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - testing::StrictMock mock_accepted_callback_; - WebRtc webrtc; - WebrtcPeerId self_id("peer_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint{}; - - ASSERT_TRUE(webrtc.IsAvailable()); - ASSERT_TRUE(webrtc.StartAcceptingConnections( - service_id, self_id, location_hint, - mock_accepted_callback_.AsStdFunction(), params.non_cellular)); - EXPECT_FALSE(webrtc.StartAcceptingConnections( - service_id, self_id, location_hint, - mock_accepted_callback_.AsStdFunction(), params.non_cellular)); - EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); - EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{})); - env_.Stop(); -} - -// Tests the flow when the device tries to connect but there is no peer -// accepting connections at the given peer ID. -TEST_P(WebRtcTest, Connect_NoPeer) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - WebRtc webrtc; - WebrtcPeerId peer_id("peer_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - - ASSERT_TRUE(webrtc.IsAvailable()); - CancellationFlag flag; - ErrorOr wrapper_1_result = webrtc.Connect( - service_id, peer_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(wrapper_1_result.has_error()); - - EXPECT_TRUE(webrtc.StartAcceptingConnections( - service_id, peer_id, location_hint, nullptr, params.non_cellular)); - env_.Stop(); -} - -// Tests the flow when the device calls Connect() after calling -// StartAcceptingConnections() without StopAcceptingConnections(). -TEST_P(WebRtcTest, StartAcceptingConnection_ThenConnect) { - env_.Start({.webrtc_enabled = true}); - testing::StrictMock mock_accepted_callback_; - WebRtcTestParams params = GetParam(); - WebRtc webrtc; - WebrtcPeerId self_id("peer_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - - ASSERT_TRUE(webrtc.IsAvailable()); - ASSERT_TRUE(webrtc.StartAcceptingConnections( - service_id, self_id, location_hint, - mock_accepted_callback_.AsStdFunction(), params.non_cellular)); - CancellationFlag flag; - ErrorOr wrapper_result = - webrtc.Connect(service_id, WebrtcPeerId("random_peer_id"), location_hint, - &flag, params.non_cellular); - EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); - EXPECT_TRUE(wrapper_result.has_error()); - EXPECT_FALSE(webrtc.StartAcceptingConnections( - service_id, self_id, location_hint, - mock_accepted_callback_.AsStdFunction(), params.non_cellular)); - env_.Stop(); -} - -// Tests the flow when the device calls StartAcceptingConnections but the medium -// is closed before a peer device can connect to it. -TEST_P(WebRtcTest, StartAndStopAcceptingConnections) { - env_.Start({.webrtc_enabled = true}); - testing::StrictMock mock_accepted_callback_; - WebRtcTestParams params = GetParam(); - WebRtc webrtc; - WebrtcPeerId self_id("peer_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - - ASSERT_TRUE(webrtc.IsAvailable()); - ASSERT_TRUE(webrtc.StartAcceptingConnections( - service_id, self_id, location_hint, - mock_accepted_callback_.AsStdFunction(), params.non_cellular)); - EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); - webrtc.StopAcceptingConnections(service_id); - EXPECT_FALSE(webrtc.IsAcceptingConnections(service_id)); - env_.Stop(); -} - -// Tests the flow when the device tries to connect to two different peers -// without disconnecting in between. -TEST_P(WebRtcTest, ConnectTwice) { - env_.Start({.webrtc_enabled = true}); - WebRtc receiver, sender, device_c; - WebRtcSocketWrapper receiver_socket; - WebRtcTestParams params = GetParam(); - const WebrtcPeerId self_id("self_id"), other_id("other_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - absl::string_view message("message xyz"); - - receiver.StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - device_c.StartAcceptingConnections( - service_id, other_id, location_hint, - [](const std::string& service_id, WebRtcSocketWrapper wrapper) {}, - params.non_cellular); - - CancellationFlag flag; - ErrorOr sender_socket_result = sender.Connect( - service_id, self_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - ExceptionOr devices_connected = connected.Get(); - ASSERT_TRUE(devices_connected.ok()); - EXPECT_TRUE(devices_connected.result()); - - ErrorOr socket_result = sender.Connect( - service_id, other_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(socket_result.has_value()); - EXPECT_TRUE(socket_result.value().IsValid()); - socket_result.value().Close(); - - EXPECT_TRUE(receiver_socket.IsValid()); - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - sender_socket_result.value().GetOutputStream().Write(message); - ExceptionOr received_msg = - receiver_socket.GetInputStream().Read(/*size=*/32); - ASSERT_TRUE(received_msg.ok()); - EXPECT_EQ(message, received_msg.result().AsStringView()); - - receiver_socket.Close(); - env_.Stop(); -} - -// Tests the flow when the two devices exchange SDP messages and connect to each -// other but disconnect before being able to send/receive the actual data. -TEST_P(WebRtcTest, ConnectBothDevicesAndAbort) { - env_.Start({.webrtc_enabled = true}); - WebRtc receiver, sender; - WebRtcSocketWrapper receiver_socket, sender_socket; - WebRtcTestParams params = GetParam(); - const WebrtcPeerId self_id("self_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - - receiver.StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - CancellationFlag flag; - ErrorOr sender_socket_result = sender.Connect( - service_id, self_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - ExceptionOr devices_connected = connected.Get(); - ASSERT_TRUE(devices_connected.ok()); - EXPECT_TRUE(devices_connected.result()); - - receiver_socket.Close(); - env_.Stop(); -} - -// Tests the flow when the two devices exchange SDP messages and connect to each -// other and the actual data is exchanged successfully between the devices. -TEST_P(WebRtcTest, ConnectBothDevicesAndSendData) { - env_.Start({.webrtc_enabled = true}); - WebRtc receiver, sender; - WebRtcSocketWrapper receiver_socket; - WebRtcTestParams params = GetParam(); - const WebrtcPeerId self_id("self_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - absl::string_view message("message"); - - receiver.StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - CancellationFlag flag; - ErrorOr sender_socket_result = sender.Connect( - service_id, self_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - ExceptionOr devices_connected = connected.Get(); - ASSERT_TRUE(devices_connected.ok()); - EXPECT_TRUE(devices_connected.result()); - - sender_socket_result.value().GetOutputStream().Write(message); - ExceptionOr received_msg = - receiver_socket.GetInputStream().Read(/*size=*/32); - ASSERT_TRUE(received_msg.ok()); - EXPECT_EQ(message, received_msg.result().AsStringView()); - - receiver_socket.Close(); - env_.Stop(); -} - -TEST_P(WebRtcTest, Connect_NullPeerConnection) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - testing::StrictMock mock_accepted_callback_; - env_.SetUseValidPeerConnection( - /*use_valid_peer_connection=*/false); - - WebRtc webrtc; - const std::string service_id("NearbySharing"); - WebrtcPeerId self_id("peer_id"); - LocationHint location_hint; - - ASSERT_TRUE(webrtc.IsAvailable()); - CancellationFlag flag; - ErrorOr wrapper_result = - webrtc.Connect(service_id, WebrtcPeerId("random_peer_id"), location_hint, - &flag, params.non_cellular); - EXPECT_TRUE(wrapper_result.has_error()); - env_.Stop(); -} - -// Tests the flow when the device calls StartAcceptingConnections and the -// receive messages stream fails. -TEST_P(WebRtcTest, ContinueAcceptingConnectionsOnComplete) { - env_.Start({.webrtc_enabled = true}); - testing::StrictMock mock_accepted_callback_; - WebRtcTestParams params = GetParam(); - WebRtc webrtc; - WebrtcPeerId self_id("peer_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - - ASSERT_TRUE(webrtc.IsAvailable()); - ASSERT_TRUE(webrtc.StartAcceptingConnections( - service_id, self_id, location_hint, - mock_accepted_callback_.AsStdFunction(), params.non_cellular)); - EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); - - // Simulate a failure in receiving messages stream, WebRtc should restart - // accepting connections. - env_.SendWebRtcSignalingComplete(self_id.GetId(), - /*success=*/false); - EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); - - // And a "success" message should not cause accepting connections to stop. - env_.SendWebRtcSignalingComplete(self_id.GetId(), - /*success=*/true); - EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id)); - - webrtc.StopAcceptingConnections(service_id); - EXPECT_FALSE(webrtc.IsAcceptingConnections(service_id)); - env_.Stop(); -} - -// Tests when a CancellationFlag is cancelled during an attempt to -// `WebRtc::AttemptToConnect` triggered by `WebRtc::Connect`. -TEST_P(WebRtcTest, CancelDuringConnect) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - - // Enable cancellation flags. - env_.SetFeatureFlags(FeatureFlags{ - .enable_cancellation_flag = true, - }); - - WebRtcSocketWrapper receiver_socket, sender_socket; - const WebrtcPeerId self_id("self_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - - CancellationFlag receiver_flag; - std::unique_ptr receiver = std::make_unique( - std::make_unique(&receiver_flag)); - - CancellationFlag sender_flag; - std::unique_ptr sender_medium = - std::make_unique(&sender_flag); - FakeWebRtcMedium* fake_sender_medium = - static_cast(sender_medium.get()); - auto sender = std::make_unique(std::move(sender_medium)); - - // Calls `CancellationFlag::Cancel` during a call to `GetSignalingMessenger` - // to simulate the cancellation occuring during an `AttemptToConnect`. - fake_sender_medium->TriggerCancellationDuringGetSignalingMessenger(); - - receiver->StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - ErrorOr sender_socket_result = sender->Connect( - service_id, self_id, location_hint, &sender_flag, params.non_cellular); - - // Since the flag was cancelled during the initial `AttemptToConnect`, except - // only one attempt instead of the usual three, because the cancellation flag - // should short-circuit the lengthy connection attempts during shutdown. - // Because of the way the iteration happens, the check for is cancelled - // happens after the counter has already been incremented, but before the - // attempt actually occurs. - EXPECT_TRUE(sender_socket_result.has_error()); - EXPECT_EQ(2, sender->connect_attempts_count(service_id)); - - env_.Stop(); -} - -// Tests when a CancellationFlag is cancelled before `WebRtc::Connect` is -// called. -TEST_P(WebRtcTest, CancelBeforeConnect) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - - // Enable cancellation flags. - env_.SetFeatureFlags(FeatureFlags{ - .enable_cancellation_flag = true, - }); - - WebRtcSocketWrapper receiver_socket; - const WebrtcPeerId self_id("self_id"); - const std::string service_id("NearbySharing"); - LocationHint location_hint; - Future connected; - - CancellationFlag receiver_flag; - std::unique_ptr receiver = std::make_unique( - std::make_unique(&receiver_flag)); - - CancellationFlag sender_flag(true); - auto sender = std::make_unique( - std::make_unique(&sender_flag)); - - receiver->StartAcceptingConnections( - service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - ErrorOr sender_socket_result = sender->Connect( - service_id, self_id, location_hint, &sender_flag, params.non_cellular); - - // Expect an invalid socket from stopping during the first attempt to connect, - // because `Connect` returned immediatley when it checked for cancellation. - EXPECT_TRUE(sender_socket_result.has_error()); - EXPECT_EQ(1, sender->connect_attempts_count(service_id)); - - env_.Stop(); -} - -// Tests when a CancellationFlag is cancelled during an attempt to -// `WebRtc::AttemptToConnect` triggered by `WebRtc::Connect` when multiple -// `WebRTC::Connect` calls are in flight for multiple service ids. -TEST_P(WebRtcTest, CancelDuringConnect_MultipleConnect) { - env_.Start({.webrtc_enabled = true}); - WebRtcTestParams params = GetParam(); - - // Enable cancellation flags. - env_.SetFeatureFlags(FeatureFlags{ - .enable_cancellation_flag = true, - }); - - WebRtcSocketWrapper receiver_socket; - const WebrtcPeerId self_id("self_id"); - const std::string ns_service_id("NearbySharing"); - const std::string ph_service_id("PhoneHub"); - LocationHint location_hint; - Future connected; - - CancellationFlag receiver_flag; - std::unique_ptr receiver = std::make_unique( - std::make_unique(&receiver_flag)); - - CancellationFlag flag; - auto sender_medium = std::make_unique(&flag); - FakeWebRtcMedium* fake_sender_medium = sender_medium.get(); - auto sender = std::make_unique(std::move(sender_medium)); - - receiver->StartAcceptingConnections( - ns_service_id, self_id, location_hint, - [&receiver_socket, connected](const std::string& ns_service_id, - WebRtcSocketWrapper wrapper) mutable { - receiver_socket = wrapper; - connected.Set(receiver_socket.IsValid()); - }, - params.non_cellular); - - // Simulate a successful connect for the endpoint of NearbySharing. - ErrorOr sender_socket_result = sender->Connect( - ns_service_id, self_id, location_hint, &flag, params.non_cellular); - EXPECT_TRUE(sender_socket_result.has_value()); - EXPECT_TRUE(sender_socket_result.value().IsValid()); - - // Calls `CancellationFlag::Cancel` during a call to `GetSignalingMessenger` - // to simulate the cancellation occuring during an `AttemptToConnect` for the - // endpoint of Phone Hub. - fake_sender_medium->TriggerCancellationDuringGetSignalingMessenger(); - sender_socket_result = sender->Connect(ph_service_id, self_id, location_hint, - &flag, params.non_cellular); - EXPECT_TRUE(sender_socket_result.has_error()); - - // Since the flag was cancelled during the initial `AttemptToConnect`, except - // only one attempt instead of the usual three, because the cancellation flag - // should short-circuit the lengthy connection attempts during shutdown. - // Because of the way the iteration happens, the check for is cancelled - // happens after the counter has already been incremented, but before the - // attempt actually occurs. For the successful connect, expect only one - // attempt. - EXPECT_EQ(1, sender->connect_attempts_count(ns_service_id)); - EXPECT_EQ(2, sender->connect_attempts_count(ph_service_id)); - - env_.Stop(); -} - -INSTANTIATE_TEST_SUITE_P(ParametrisedWebRtcTest, WebRtcTest, - testing::ValuesIn({ - {.feature_flags = - FeatureFlags{ - .enable_cancellation_flag = true, - }, - .non_cellular = true}, - {.feature_flags = - FeatureFlags{ - .enable_cancellation_flag = true, - }, - .non_cellular = false}, - {.feature_flags = - FeatureFlags{ - .enable_cancellation_flag = false, - }, - .non_cellular = true}, - {.feature_flags = - FeatureFlags{ - .enable_cancellation_flag = false, - }, - .non_cellular = false}, - })); - -} // namespace - -} // namespace mediums -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/mediums/wifi_direct.cc b/connections/implementation/mediums/wifi_direct.cc index 75f7b35d..1d1559a8 100644 --- a/connections/implementation/mediums/wifi_direct.cc +++ b/connections/implementation/mediums/wifi_direct.cc @@ -14,12 +14,15 @@ #include "connections/implementation/mediums/wifi_direct.h" +#include #include #include #include #include #include "absl/strings/string_view.h" +#include "connections/implementation/bwu_handler.h" +#include "connections/implementation/mediums/wifi_direct_bwu_handler.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/logging.h" @@ -307,5 +310,12 @@ bool WifiDirect::SetPreferredWifiDirectAuthType(WifiDirectAuthType auth_type) { return true; } +std::unique_ptr WifiDirect::CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback) { + MutexLock lock(&mutex_); + return std::make_unique( + this, std::move(incoming_connection_callback)); +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/wifi_direct.h b/connections/implementation/mediums/wifi_direct.h index e85d2e64..1ea6211d 100644 --- a/connections/implementation/mediums/wifi_direct.h +++ b/connections/implementation/mediums/wifi_direct.h @@ -19,6 +19,7 @@ #include #include "absl/base/thread_annotations.h" +#include "connections/implementation/bwu_handler.h" #include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" @@ -110,6 +111,9 @@ class WifiDirect { // Sets the preferred WifiDirect auth type. bool SetPreferredWifiDirectAuthType(WifiDirectAuthType auth_type); + std::unique_ptr CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback); + private: mutable Mutex mutex_; static constexpr int kMaxConcurrentAcceptLoops = 5; diff --git a/connections/implementation/wifi_direct_bwu_handler.cc b/connections/implementation/mediums/wifi_direct_bwu_handler.cc similarity index 92% rename from connections/implementation/wifi_direct_bwu_handler.cc rename to connections/implementation/mediums/wifi_direct_bwu_handler.cc index d637e0e4..b9925b84 100644 --- a/connections/implementation/wifi_direct_bwu_handler.cc +++ b/connections/implementation/mediums/wifi_direct_bwu_handler.cc @@ -12,23 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_direct_bwu_handler.h" +#include "connections/implementation/mediums/wifi_direct_bwu_handler.h" #include #include #include #include +#include "absl/base/nullability.h" #include "absl/functional/bind_front.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" +#include "connections/implementation/mediums/wifi_direct.h" +#include "connections/implementation/mediums/wifi_direct_endpoint_channel.h" #include "connections/implementation/offline_frames.h" -#include "connections/implementation/wifi_direct_endpoint_channel.h" #include "connections/strategy.h" #include "internal/base/masker.h" -#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/logging.h" #include "internal/platform/wifi_credential.h" @@ -42,14 +43,15 @@ using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::proto::connections::OperationResultCode; } // namespace WifiDirectBwuHandler::WifiDirectBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + WifiDirect* absl_nonnull wifi_direct_medium, + IncomingConnectionCallback incoming_connection_callback) : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} + wifi_direct_medium_(*wifi_direct_medium) {} // Called by BWU initiator. Set up WifiDirect upgraded medium for this // endpoint, and returns an upgrade path info (ServiceName, Pin for Wifi WPS, // Gateway used as IPAddress, Port) for remote party to perform connection. -ByteArray WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( +std::string WifiDirectBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) { // Create WifiDirect GO @@ -172,8 +174,10 @@ WifiDirectBwuHandler::CreateUpgradedEndpointChannel( OperationResultCode::CONNECTIVITY_WIFI_DIRECT_INVALID_CREDENTIAL)}; } + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint_id); ErrorOr socket_result = wifi_direct_medium_.Connect( - service_id, gateway, port, client->GetCancellationFlag(endpoint_id)); + service_id, gateway, port, cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "WifiDirectBwuHandler failed to connect to the WifiDirect service(" diff --git a/connections/implementation/wifi_direct_bwu_handler.h b/connections/implementation/mediums/wifi_direct_bwu_handler.h similarity index 88% rename from connections/implementation/wifi_direct_bwu_handler.h rename to connections/implementation/mediums/wifi_direct_bwu_handler.h index 34623d83..6fec11d3 100644 --- a/connections/implementation/wifi_direct_bwu_handler.h +++ b/connections/implementation/mediums/wifi_direct_bwu_handler.h @@ -12,19 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_WIFI_DIRECT_BWU_HANDLER_H_ -#define CORE_INTERNAL_WIFI_DIRECT_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_DIRECT_BWU_HANDLER_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_DIRECT_BWU_HANDLER_H_ #include #include +#include "absl/base/nullability.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" #include "connections/implementation/mediums/wifi_direct.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" #include "internal/platform/wifi_direct.h" @@ -35,8 +34,8 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WifiDirectBwuHandler : public BaseBwuHandler { public: - explicit WifiDirectBwuHandler( - Mediums& mediums, + WifiDirectBwuHandler( + WifiDirect* absl_nonnull wifi_direct_medium, IncomingConnectionCallback incoming_connection_callback); private: @@ -73,7 +72,7 @@ class WifiDirectBwuHandler : public BaseBwuHandler { // Called by BWU initiator. Set up WifiDirect upgraded medium for this // endpoint, and returns a upgrade path info (SSID, Password, Gateway used as // IPAddress, Port) for remote party to perform connection. - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final; @@ -86,11 +85,10 @@ class WifiDirectBwuHandler : public BaseBwuHandler { const std::string& upgrade_service_id, WifiDirectSocket socket); - Mediums& mediums_; - WifiDirect& wifi_direct_medium_ = mediums_.GetWifiDirect(); + WifiDirect& wifi_direct_medium_; }; } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_WIFI_DIRECT_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_DIRECT_BWU_HANDLER_H_ diff --git a/connections/implementation/wifi_direct_bwu_test.cc b/connections/implementation/mediums/wifi_direct_bwu_handler_test.cc similarity index 92% rename from connections/implementation/wifi_direct_bwu_test.cc rename to connections/implementation/mediums/wifi_direct_bwu_handler_test.cc index f9eed52f..fd3dccec 100644 --- a/connections/implementation/wifi_direct_bwu_test.cc +++ b/connections/implementation/mediums/wifi_direct_bwu_handler_test.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "connections/implementation/mediums/wifi_direct_bwu_handler.h" + #include #include #include @@ -26,9 +28,7 @@ #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/offline_frames.h" -#include "connections/implementation/wifi_direct_bwu_handler.h" #include "internal/flags/nearby_flags.h" -#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" @@ -68,7 +68,8 @@ TEST_F(WifiDirectTest, CanCreateBwuHandler) { ClientProxy client; Mediums mediums; - auto handler = std::make_unique(mediums, nullptr); + auto handler = + std::make_unique(&mediums.GetWifiDirect(), nullptr); handler->InitializeUpgradedMediumForEndpoint(&client, std::string(kServiceID), std::string(kEndpointID)); @@ -87,7 +88,7 @@ TEST_F(WifiDirectTest, WFDGOBWUInit_GCCreateEndpointChannel) { ExceptionOr upgrade_frame; auto wfd_go_bwu_handler = std::make_unique( - mediums_wfd_go, [&](ClientProxy* client, + &mediums_wfd_go.GetWifiDirect(), [&](ClientProxy* client, std::unique_ptr mutable_connection) { LOG(INFO) << "Server socket connection accept call back, Socket name: " @@ -98,10 +99,10 @@ TEST_F(WifiDirectTest, WFDGOBWUInit_GCCreateEndpointChannel) { SingleThreadExecutor wfd_go_executor; wfd_go_executor.Execute([&]() { - ByteArray upgrade_path_available_frame = + std::string upgrade_path_available_frame = wfd_go_bwu_handler->InitializeUpgradedMediumForEndpoint( &wifi_direct_go, std::string(kServiceID), std::string(kEndpointID)); - EXPECT_FALSE(upgrade_path_available_frame.Empty()); + EXPECT_FALSE(upgrade_path_available_frame.empty()); upgrade_frame = parser::FromBytes(upgrade_path_available_frame); start_latch.CountDown(); @@ -113,7 +114,8 @@ TEST_F(WifiDirectTest, WFDGOBWUInit_GCCreateEndpointChannel) { EXPECT_TRUE(start_latch.Await(kWaitDuration).result()); EXPECT_FALSE(mediums_wfd_gc.GetWifiDirect().IsConnectedToGO()); std::unique_ptr wfd_gc_bwu_handler = - std::make_unique(mediums_wfd_gc, nullptr); + std::make_unique(&mediums_wfd_gc.GetWifiDirect(), + nullptr); wfd_gc_executor.Execute([&]() { UpgradePathInfo upgrade_path_info; diff --git a/connections/implementation/wifi_direct_endpoint_channel.cc b/connections/implementation/mediums/wifi_direct_endpoint_channel.cc similarity index 95% rename from connections/implementation/wifi_direct_endpoint_channel.cc rename to connections/implementation/mediums/wifi_direct_endpoint_channel.cc index 379112b8..b271d475 100644 --- a/connections/implementation/wifi_direct_endpoint_channel.cc +++ b/connections/implementation/mediums/wifi_direct_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_direct_endpoint_channel.h" +#include "connections/implementation/mediums/wifi_direct_endpoint_channel.h" #include #include diff --git a/connections/implementation/wifi_direct_endpoint_channel.h b/connections/implementation/mediums/wifi_direct_endpoint_channel.h similarity index 89% rename from connections/implementation/wifi_direct_endpoint_channel.h rename to connections/implementation/mediums/wifi_direct_endpoint_channel.h index 9cf735b6..45d4d6f9 100644 --- a/connections/implementation/wifi_direct_endpoint_channel.h +++ b/connections/implementation/mediums/wifi_direct_endpoint_channel.h @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. - -#ifndef CORE_INTERNAL_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ #include @@ -48,4 +47,4 @@ class WifiDirectEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_DIRECT_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/mediums/wifi_hotspot.cc b/connections/implementation/mediums/wifi_hotspot.cc index 6d91e27e..4701a176 100644 --- a/connections/implementation/mediums/wifi_hotspot.cc +++ b/connections/implementation/mediums/wifi_hotspot.cc @@ -15,6 +15,7 @@ #include "connections/implementation/mediums/wifi_hotspot.h" #include +#include #include #include #include @@ -22,12 +23,15 @@ #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "connections/implementation/bwu_handler.h" +#include "connections/implementation/mediums/wifi_hotspot_bwu_handler.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/flags/nearby_platform_feature_flags.h" #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" +#include "internal/platform/service_address.h" #include "internal/platform/wifi_credential.h" #include "internal/platform/wifi_hotspot.h" @@ -325,5 +329,12 @@ ErrorOr WifiHotspot::Connect( return socket; } +std::unique_ptr WifiHotspot::CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback) { + MutexLock lock(&mutex_); + return std::make_unique( + this, std::move(incoming_connection_callback)); +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/wifi_hotspot.h b/connections/implementation/mediums/wifi_hotspot.h index 11b0bd3e..06e622c9 100644 --- a/connections/implementation/mediums/wifi_hotspot.h +++ b/connections/implementation/mediums/wifi_hotspot.h @@ -21,6 +21,7 @@ #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" +#include "connections/implementation/bwu_handler.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/multi_thread_executor.h" @@ -86,6 +87,9 @@ class WifiHotspot { HotspotCredentials* GetCredentials(absl::string_view service_id) ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback); + private: mutable Mutex mutex_; static constexpr int kMaxConcurrentAcceptLoops = 5; diff --git a/connections/implementation/wifi_hotspot_bwu_handler.cc b/connections/implementation/mediums/wifi_hotspot_bwu_handler.cc similarity index 93% rename from connections/implementation/wifi_hotspot_bwu_handler.cc rename to connections/implementation/mediums/wifi_hotspot_bwu_handler.cc index f369a3aa..d31b8a15 100644 --- a/connections/implementation/wifi_hotspot_bwu_handler.cc +++ b/connections/implementation/mediums/wifi_hotspot_bwu_handler.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_hotspot_bwu_handler.h" +#include "connections/implementation/mediums/wifi_hotspot_bwu_handler.h" #if !defined(_WIN32) #include @@ -27,17 +27,18 @@ #include #include +#include "absl/base/nullability.h" #include "absl/functional/bind_front.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" +#include "connections/implementation/mediums/wifi_hotspot.h" +#include "connections/implementation/mediums/wifi_hotspot_endpoint_channel.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" -#include "connections/implementation/wifi_hotspot_endpoint_channel.h" #include "connections/strategy.h" #include "internal/base/masker.h" -#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/wifi_utils.h" #include "internal/platform/logging.h" @@ -67,14 +68,15 @@ std::vector GatewayToAddressBytes(const std::string& gateway) { } // namespace WifiHotspotBwuHandler::WifiHotspotBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + WifiHotspot* absl_nonnull wifi_hotspot_medium, + IncomingConnectionCallback incoming_connection_callback) : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} + wifi_hotspot_medium_(*wifi_hotspot_medium) {} // Called by BWU initiator. Set up WifiHotspot upgraded medium for this // endpoint, and returns a upgrade path info (SSID, Password, Gateway used as // IPAddress, Port) for remote party to perform connection. -ByteArray WifiHotspotBwuHandler::HandleInitializeUpgradedMediumForEndpoint( +std::string WifiHotspotBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) { // Create SoftAP @@ -219,9 +221,11 @@ WifiHotspotBwuHandler::CreateUpgradedEndpointChannel( CONNECTIVITY_WIFI_HOTSPOT_LEGACY_STA_CONNECTION_FAILURE)}; } + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint_id); ErrorOr socket_result = wifi_hotspot_medium_.Connect( service_id, hotspot_credentials.GetAddressCandidates(), - client->GetCancellationFlag(endpoint_id)); + cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "WifiHotspotBwuHandler failed to connect to the WifiHotspot " "service for endpoint " diff --git a/connections/implementation/wifi_hotspot_bwu_handler.h b/connections/implementation/mediums/wifi_hotspot_bwu_handler.h similarity index 86% rename from connections/implementation/wifi_hotspot_bwu_handler.h rename to connections/implementation/mediums/wifi_hotspot_bwu_handler.h index a21705b9..1c3c8f83 100644 --- a/connections/implementation/wifi_hotspot_bwu_handler.h +++ b/connections/implementation/mediums/wifi_hotspot_bwu_handler.h @@ -12,19 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_WIFI_HOTSPOT_BWU_HANDLER_H_ -#define CORE_INTERNAL_WIFI_HOTSPOT_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_BWU_HANDLER_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_BWU_HANDLER_H_ #include #include +#include "absl/base/nullability.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" #include "connections/implementation/mediums/wifi_hotspot.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" #include "internal/platform/wifi_hotspot.h" @@ -35,8 +34,8 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WifiHotspotBwuHandler : public BaseBwuHandler { public: - explicit WifiHotspotBwuHandler( - Mediums& mediums, + WifiHotspotBwuHandler( + WifiHotspot* absl_nonnull wifi_hotspot_medium, IncomingConnectionCallback incoming_connection_callback); // BwuHandler implementation: @@ -68,7 +67,7 @@ class WifiHotspotBwuHandler : public BaseBwuHandler { }; // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final; void HandleRevertInitiatorStateForService( @@ -78,11 +77,10 @@ class WifiHotspotBwuHandler : public BaseBwuHandler { const std::string& upgrade_service_id, WifiHotspotSocket socket); - Mediums& mediums_; - WifiHotspot& wifi_hotspot_medium_{mediums_.GetWifiHotspot()}; + WifiHotspot& wifi_hotspot_medium_; }; } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_WIFI_HOTSPOT_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_BWU_HANDLER_H_ diff --git a/connections/implementation/wifi_hotspot_bwu_test.cc b/connections/implementation/mediums/wifi_hotspot_bwu_handler_test.cc similarity index 93% rename from connections/implementation/wifi_hotspot_bwu_test.cc rename to connections/implementation/mediums/wifi_hotspot_bwu_handler_test.cc index 125e4028..fcd42428 100644 --- a/connections/implementation/wifi_hotspot_bwu_test.cc +++ b/connections/implementation/mediums/wifi_hotspot_bwu_handler_test.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "connections/implementation/mediums/wifi_hotspot_bwu_handler.h" + #include #include #include @@ -25,9 +27,7 @@ #include "connections/implementation/endpoint_channel.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/offline_frames.h" -#include "connections/implementation/wifi_hotspot_bwu_handler.h" #include "internal/flags/nearby_flags.h" -#include "internal/platform/byte_array.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" @@ -69,7 +69,8 @@ TEST_F(WifiHotspotTest, CanCreateBwuHandler) { ClientProxy client; Mediums mediums; - auto handler = std::make_unique(mediums, nullptr); + auto handler = std::make_unique( + &mediums.GetWifiHotspot(), nullptr); handler->InitializeUpgradedMediumForEndpoint(&client, std::string(kServiceID), std::string(kEndpointID)); @@ -88,7 +89,7 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) { ExceptionOr upgrade_frame; auto handler_1 = std::make_unique( - mediums_HS_ap, [&](ClientProxy* client, + &mediums_HS_ap.GetWifiHotspot(), [&](ClientProxy* client, std::unique_ptr mutable_connection) { LOG(INFO) << "Server socket connection accept call back, Socket name: " @@ -100,11 +101,11 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) { // client_hotspot_ap works as Hotspot SoftAP SingleThreadExecutor server_executor; server_executor.Execute([&]() { - ByteArray upgrade_path_available_frame = + std::string upgrade_path_available_frame = handler_1->InitializeUpgradedMediumForEndpoint( &client_hotspot_ap, std::string(kServiceID), std::string(kEndpointID)); - EXPECT_FALSE(upgrade_path_available_frame.Empty()); + EXPECT_FALSE(upgrade_path_available_frame.empty()); upgrade_frame = parser::FromBytes(upgrade_path_available_frame); start_latch.CountDown(); @@ -117,7 +118,8 @@ TEST_F(WifiHotspotTest, SoftAPBWUInit_STACreateEndpointChannel) { // Wait till client_hotspot_ap started as hotspot and then connect to it EXPECT_TRUE(start_latch.Await(kWaitDuration).result()); std::unique_ptr handler_2 = - std::make_unique(mediums_HS_sta, nullptr); + std::make_unique(&mediums_HS_sta.GetWifiHotspot(), + nullptr); client_executor.Execute([&]() { UpgradePathInfo upgrade_path_info; diff --git a/connections/implementation/wifi_hotspot_endpoint_channel.cc b/connections/implementation/mediums/wifi_hotspot_endpoint_channel.cc similarity index 95% rename from connections/implementation/wifi_hotspot_endpoint_channel.cc rename to connections/implementation/mediums/wifi_hotspot_endpoint_channel.cc index 53e99fbe..0b355d36 100644 --- a/connections/implementation/wifi_hotspot_endpoint_channel.cc +++ b/connections/implementation/mediums/wifi_hotspot_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_hotspot_endpoint_channel.h" +#include "connections/implementation/mediums/wifi_hotspot_endpoint_channel.h" #include #include diff --git a/connections/implementation/wifi_hotspot_endpoint_channel.h b/connections/implementation/mediums/wifi_hotspot_endpoint_channel.h similarity index 89% rename from connections/implementation/wifi_hotspot_endpoint_channel.h rename to connections/implementation/mediums/wifi_hotspot_endpoint_channel.h index b44da4de..2cb2b67f 100644 --- a/connections/implementation/wifi_hotspot_endpoint_channel.h +++ b/connections/implementation/mediums/wifi_hotspot_endpoint_channel.h @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. - -#ifndef CORE_INTERNAL_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ #include @@ -48,4 +47,4 @@ class WifiHotspotEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_HOTSPOT_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/mediums/wifi_lan.cc b/connections/implementation/mediums/wifi_lan.cc index ff3c58ad..d789590b 100644 --- a/connections/implementation/mediums/wifi_lan.cc +++ b/connections/implementation/mediums/wifi_lan.cc @@ -22,29 +22,24 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" -#include "connections/implementation/mediums/multiplex/multiplex_socket.h" +#include "connections/implementation/bwu_handler.h" #include "connections/implementation/mediums/utils.h" -#include "connections/medium_selector.h" -#include "internal/platform/base64_utils.h" +#include "connections/implementation/mediums/wifi_lan_bwu_handler.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/upgrade_address_info.h" -#include "internal/platform/implementation/wifi_utils.h" #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" #include "internal/platform/nsd_service_info.h" #include "internal/platform/service_address.h" -#include "internal/platform/socket.h" -#include "internal/platform/types.h" #include "internal/platform/wifi_lan.h" namespace nearby { namespace connections { namespace { -using MultiplexSocket = mediums::multiplex::MultiplexSocket; using location::nearby::proto::connections::OperationResultCode; } // namespace @@ -59,18 +54,6 @@ WifiLan::~WifiLan() { while (!advertising_info_.nsd_service_infos.empty()) { StopAdvertising(advertising_info_.nsd_service_infos.begin()->first); } - { - MutexLock lock(&mutex_); - if (is_multiplex_enabled_) { - LOG(INFO) << "Closing multiplex sockets for " << multiplex_sockets_.size() - << " IPs"; - for (auto& [ip_addr, multiplex_socket] : multiplex_sockets_) { - LOG(INFO) << "Closing multiplex sockets for: " << ip_addr; - multiplex_socket->~MultiplexSocket(); - } - multiplex_sockets_.clear(); - } - } // All the AcceptLoopRunnable objects in here should already have gotten an // opportunity to shut themselves down cleanly in the calls to // StopAcceptingConnections() above. @@ -265,18 +248,6 @@ ErrorOr WifiLan::StartAcceptingConnectionsLocked( server_sockets_.insert({service_id, std::move(server_socket)}) .first->second; - // Register the callback to listen for incoming multiplex virtual socket. - if (is_multiplex_enabled_) { - MultiplexSocket::ListenForIncomingConnection( - service_id, Medium::WIFI_LAN, - [&callback](const std::string& listening_service_id, - MediumSocket* virtual_socket) mutable { - if (callback) { - callback(listening_service_id, - *(down_cast(virtual_socket))); - } - }); - } port = owned_server_socket.GetPort(); // Start the accept loop on a dedicated thread - this stays alive and // listening for new incoming connections until StopAcceptingConnections() is @@ -284,7 +255,7 @@ ErrorOr WifiLan::StartAcceptingConnectionsLocked( accept_loops_runner_.Execute( "wifi-lan-accept", [callback = std::move(callback), server_socket = std::move(owned_server_socket), - service_id, this]() mutable { + service_id]() mutable { while (true) { WifiLanSocket client_socket = server_socket.Accept(); if (!client_socket.IsValid()) { @@ -293,53 +264,6 @@ ErrorOr WifiLan::StartAcceptingConnectionsLocked( } LOG(INFO) << "Accepted connection for " << service_id; bool callback_called = false; - { - MutexLock lock(&mutex_); - if (is_multiplex_enabled_) { - // Observed from the log that when the sender tries to connect to - // the receiver's server socket, the server side will somehow - // receive 3 connection request events(don’t know what’s happening - // in Windows’s lower layer code). The 2nd normally is the real - // one. The other two will result in a failed data receiving in - // Windows platform layer. To avoid creating multiplex - // IncomingSocket, we will check if the first read is successful - // or not. If not, discard it. If yes, save that packet - // content(the first frame length), then create the multiplex - // socket, then feed that content to that multiplex socket. - ExceptionOr read_int = - Base64Utils::ReadInt(&client_socket.GetInputStream()); - if (!read_int.ok()) { - LOG(WARNING) - << __func__ - << "Failed to read. Exception:" << read_int.exception() - << "Discard the connection."; - continue; - } - WifiLanSocket client_socket_bak = client_socket; - auto physical_socket_ptr = - std::make_shared(client_socket_bak); - - MultiplexSocket* multiplex_socket = - MultiplexSocket::CreateIncomingSocket( - physical_socket_ptr, service_id, read_int.result()); - if (multiplex_socket != nullptr && - multiplex_socket->GetVirtualSocket(service_id)) { - multiplex_sockets_.emplace(server_socket.GetIPAddress(), - multiplex_socket); - MultiplexSocket::StopListeningForIncomingConnection( - service_id, Medium::WIFI_LAN); - LOG(INFO) << "Multiplex virtaul socket created for " - << server_socket.GetIPAddress(); - if (callback) { - callback( - service_id, - *(down_cast( - multiplex_socket->GetVirtualSocket(service_id)))); - callback_called = true; - } - } - } - } if (callback && !callback_called) { LOG(INFO) << "Call back triggered for physical socket."; callback(service_id, std::move(client_socket)); @@ -402,10 +326,6 @@ bool WifiLan::StopAcceptingConnectionsLocked(const std::string& service_id) { << " because it was never started."; return false; } - if (is_multiplex_enabled_) { - MultiplexSocket::StopListeningForIncomingConnection(service_id, - Medium::WIFI_LAN); - } // Closing the WifiLanServerSocket will kick off the suicide of the thread // in accept_loops_thread_pool_ that blocks on WifiLanServerSocket.accept(). @@ -555,60 +475,12 @@ ErrorOr WifiLan::Connect(const std::string& service_id, ExceptionOr WifiLan::ConnectWithMultiplexSocketLocked( const std::string& service_id, const std::string& ip_address) { - if (is_multiplex_enabled_) { - LOG(INFO) << "multiplex_sockets_ size:" << multiplex_sockets_.size(); - auto it = multiplex_sockets_.find(ip_address); - if (it != multiplex_sockets_.end()) { - MultiplexSocket* multiplex_socket = it->second; - if (multiplex_socket->IsShutdown()) { - LOG(INFO) << "Erase multiplex_socket(already shutdown) for ip_address: " - << WifiUtils::GetHumanReadableIpAddress(ip_address); - multiplex_socket->~MultiplexSocket(); - multiplex_sockets_.erase(it); - return ExceptionOr(Exception::kFailed); - } - if (multiplex_socket->IsEnabled()) { - auto* virtual_socket = - multiplex_socket->EstablishVirtualSocket(service_id); - // Should not happen. - auto* wlan_socket = down_cast(virtual_socket); - if (wlan_socket == nullptr) { - LOG(INFO) << "Failed to cast to WifiLanSocket for " << service_id - << " with ip_address: " - << WifiUtils::GetHumanReadableIpAddress(ip_address); - return ExceptionOr(Exception::kFailed); - } - return ExceptionOr(*wlan_socket); - } - } - } return ExceptionOr(Exception::kFailed); } ExceptionOr WifiLan::CreateOutgoingMultiplexSocketLocked( WifiLanSocket& socket, const std::string& service_id, const std::string& ip_address) { - if (is_multiplex_enabled_) { - // Create MultiplexSocket, but set it to be disabled as default. It will be - // enabled if both side support multiplex for WIFI_LAN - auto physical_socket_ptr = std::make_shared(socket); - MultiplexSocket* multiplex_socket = - MultiplexSocket::CreateOutgoingSocket(physical_socket_ptr, service_id); - - auto* virtual_socket = multiplex_socket->GetVirtualSocket(service_id); - // Should not happen. - auto* wlan_socket = down_cast(virtual_socket); - if (wlan_socket == nullptr) { - LOG(INFO) << "Failed to cast to WifiLanSocket for " << service_id - << " with ip_address: " - << WifiUtils::GetHumanReadableIpAddress(ip_address); - return ExceptionOr(Exception::kFailed); - } - LOG(INFO) << "Multiplex socket created for ip_address: " - << WifiUtils::GetHumanReadableIpAddress(ip_address); - multiplex_sockets_.emplace(ip_address, multiplex_socket); - return ExceptionOr(*wlan_socket); - } return ExceptionOr(Exception::kFailed); } @@ -648,5 +520,12 @@ int WifiLan::GeneratePort(const std::string& service_id, (uint_of_service_id_hash % (port_range.second - port_range.first)); } +std::unique_ptr WifiLan::CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback) { + MutexLock lock(&mutex_); + return std::make_unique( + this, std::move(incoming_connection_callback)); +} + } // namespace connections } // namespace nearby diff --git a/connections/implementation/mediums/wifi_lan.h b/connections/implementation/mediums/wifi_lan.h index 990439ce..7d6e6cb1 100644 --- a/connections/implementation/mediums/wifi_lan.h +++ b/connections/implementation/mediums/wifi_lan.h @@ -16,17 +16,15 @@ #define CORE_INTERNAL_MEDIUMS_WIFI_LAN_H_ #include +#include #include #include -#include #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 "connections/implementation/flags/nearby_connections_feature_flags.h" -#include "connections/implementation/mediums/multiplex/multiplex_socket.h" -#include "internal/flags/nearby_flags.h" +#include "connections/implementation/bwu_handler.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" #include "internal/platform/expected.h" @@ -118,6 +116,9 @@ class WifiLan { api::UpgradeAddressInfo GetUpgradeAddressCandidates( const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + std::unique_ptr CreateBwuHandler( + BwuHandler::IncomingConnectionCallback incoming_connection_callback); + private: struct AdvertisingInfo { bool Empty() const { return nsd_service_infos.empty(); } @@ -218,17 +219,6 @@ class WifiLan { absl::flat_hash_map server_sockets_ ABSL_GUARDED_BY(mutex_); - // Whether the multiplex feature is enabled. - bool is_multiplex_enabled_ = NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature::kEnableMultiplex) && - NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnableMultiplexWifiLan); - - // A map of IpAddress -> MultiplexSocket. - absl::flat_hash_map - multiplex_sockets_ ABSL_GUARDED_BY(mutex_); - std::string last_mdns_service_name_ ABSL_GUARDED_BY(mutex_); int last_server_port_ ABSL_GUARDED_BY(mutex_) = 0; }; diff --git a/connections/implementation/wifi_lan_bwu_handler.cc b/connections/implementation/mediums/wifi_lan_bwu_handler.cc similarity index 88% rename from connections/implementation/wifi_lan_bwu_handler.cc rename to connections/implementation/mediums/wifi_lan_bwu_handler.cc index 1a31c931..a25cd81c 100644 --- a/connections/implementation/wifi_lan_bwu_handler.cc +++ b/connections/implementation/mediums/wifi_lan_bwu_handler.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_lan_bwu_handler.h" +#include "connections/implementation/mediums/wifi_lan_bwu_handler.h" #include #include @@ -20,14 +20,15 @@ #include #include +#include "absl/base/nullability.h" #include "absl/functional/bind_front.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" +#include "connections/implementation/mediums/wifi_lan.h" +#include "connections/implementation/mediums/wifi_lan_endpoint_channel.h" #include "connections/implementation/offline_frames.h" -#include "connections/implementation/wifi_lan_endpoint_channel.h" -#include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/upgrade_address_info.h" #include "internal/platform/logging.h" @@ -43,9 +44,10 @@ using ::location::nearby::proto::connections::OperationResultCode; } // namespace WifiLanBwuHandler::WifiLanBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) + WifiLan* absl_nonnull wifi_lan_medium, + IncomingConnectionCallback incoming_connection_callback) : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} + wifi_lan_medium_(*wifi_lan_medium) {} // Called by BWU target. Retrieves a new medium info from incoming message, // and establishes connection over WifiLan using this info. @@ -92,9 +94,10 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel( VLOG(1) << "WifiLanBwuHandler is attempting to connect to available " "WifiLan service (" << address_candidate << ") for endpoint " << endpoint_id; - ErrorOr socket_result = - wifi_lan_medium_.Connect(service_id, address_candidate, - client->GetCancellationFlag(endpoint_id)); + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint_id); + ErrorOr socket_result = wifi_lan_medium_.Connect( + service_id, address_candidate, cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "WifiLanBwuHandler failed to connect to the WifiLan service (" @@ -118,9 +121,10 @@ WifiLanBwuHandler::CreateUpgradedEndpointChannel( // Called by BWU initiator. Set up WifiLan upgraded medium for this endpoint, // and returns a upgrade path info (ip address, port) for remote party to // perform discovery. -ByteArray WifiLanBwuHandler::HandleInitializeUpgradedMediumForEndpoint( +std::string WifiLanBwuHandler::HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) { + bool started_accepting = false; if (!wifi_lan_medium_.IsAcceptingConnections(upgrade_service_id)) { if (!wifi_lan_medium_.StartAcceptingConnections( upgrade_service_id, @@ -137,6 +141,7 @@ ByteArray WifiLanBwuHandler::HandleInitializeUpgradedMediumForEndpoint( << "WifiLanBwuHandler successfully started listening for incoming " "WifiLan connections while upgrading endpoint " << endpoint_id; + started_accepting = true; } // Address candidates are not populated until StartAcceptingConnections() is @@ -148,6 +153,9 @@ ByteArray WifiLanBwuHandler::HandleInitializeUpgradedMediumForEndpoint( LOG(INFO) << "WifiLanBwuHandler couldn't initiate the wifi_lan upgrade for " << "service " << upgrade_service_id << " and endpoint " << endpoint_id << " because there are no available ip addresses."; + if (started_accepting) { + wifi_lan_medium_.StopAcceptingConnections(upgrade_service_id); + } return {}; } client->GetAnalyticsRecorder().UpdateBwUpgradeNetworkInfo( diff --git a/connections/implementation/wifi_lan_bwu_handler.h b/connections/implementation/mediums/wifi_lan_bwu_handler.h similarity index 87% rename from connections/implementation/wifi_lan_bwu_handler.h rename to connections/implementation/mediums/wifi_lan_bwu_handler.h index 2e00bf79..46c4c0a0 100644 --- a/connections/implementation/wifi_lan_bwu_handler.h +++ b/connections/implementation/mediums/wifi_lan_bwu_handler.h @@ -12,19 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_WIFI_LAN_BWU_HANDLER_H_ -#define CORE_INTERNAL_WIFI_LAN_BWU_HANDLER_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_LAN_BWU_HANDLER_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_LAN_BWU_HANDLER_H_ #include #include +#include "absl/base/nullability.h" #include "connections/implementation/base_bwu_handler.h" #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" #include "connections/implementation/mediums/wifi_lan.h" -#include "internal/platform/byte_array.h" #include "internal/platform/expected.h" #include "internal/platform/wifi_lan.h" @@ -35,8 +34,8 @@ namespace connections { // per-Medium-specific operations needed to upgrade an EndpointChannel. class WifiLanBwuHandler : public BaseBwuHandler { public: - explicit WifiLanBwuHandler( - Mediums& mediums, + WifiLanBwuHandler( + WifiLan* absl_nonnull wifi_lan_medium, IncomingConnectionCallback incoming_connection_callback); // BwuHandler implementation: @@ -68,7 +67,7 @@ class WifiLanBwuHandler : public BaseBwuHandler { }; // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( + std::string HandleInitializeUpgradedMediumForEndpoint( ClientProxy* client, const std::string& upgrade_service_id, const std::string& endpoint_id) final; void HandleRevertInitiatorStateForService( @@ -78,11 +77,10 @@ class WifiLanBwuHandler : public BaseBwuHandler { const std::string& upgrade_service_id, WifiLanSocket socket); - Mediums& mediums_; - WifiLan& wifi_lan_medium_{mediums_.GetWifiLan()}; + WifiLan& wifi_lan_medium_; }; } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_WIFI_LAN_BWU_HANDLER_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_BWU_HANDLER_H_ diff --git a/connections/implementation/wifi_lan_bwu_handler_test.cc b/connections/implementation/mediums/wifi_lan_bwu_handler_test.cc similarity index 74% rename from connections/implementation/wifi_lan_bwu_handler_test.cc rename to connections/implementation/mediums/wifi_lan_bwu_handler_test.cc index f6623db9..1cf09752 100644 --- a/connections/implementation/wifi_lan_bwu_handler_test.cc +++ b/connections/implementation/mediums/wifi_lan_bwu_handler_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_lan_bwu_handler.h" +#include "connections/implementation/mediums/wifi_lan_bwu_handler.h" #include #include @@ -26,10 +26,6 @@ #include "connections/implementation/bwu_handler.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/mediums/mediums.h" -#include "connections/strategy.h" -#include "internal/analytics/mock_event_logger.h" -#include "internal/analytics/sharing_log_matchers.h" -#include "internal/platform/byte_array.h" #include "internal/platform/implementation/platform.h" #include "internal/platform/implementation/upgrade_address_info.h" #include "internal/platform/implementation/wifi_lan.h" @@ -40,7 +36,7 @@ #include "internal/platform/mock_wifi_lan_server_socket.h" #include "internal/platform/mock_wifi_lan_socket.h" #include "internal/platform/service_address.h" -#include "internal/proto/analytics/connections_log.pb.h" +#include "internal/platform/wifi_lan.h" namespace nearby { @@ -48,18 +44,14 @@ MockWifiLanMedium* wifi_lan_medium = nullptr; namespace connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::V1Frame; -using ::location::nearby::proto::connections::EventType; using ::location::nearby::proto::connections::OperationResultCode; -using ::nearby::analytics::HasEventType; using ::testing::_; using ::testing::ByMove; using ::protobuf_matchers::EqualsProto; using ::testing::InSequence; -using ::testing::Matcher; using ::testing::MockFunction; using ::testing::Return; using ::testing::ReturnRef; @@ -73,19 +65,19 @@ constexpr absl::string_view kEndpointId{"endpoint_id"}; class WifiLanBwuHandlerTest : public ::testing::Test { protected: WifiLanBwuHandlerTest() - : handler_(mediums_, incoming_connection_callback_.AsStdFunction()) {} + : handler_(&mediums_.GetWifiLan(), + incoming_connection_callback_.AsStdFunction()) {} Mediums mediums_; MockFunction)> incoming_connection_callback_; WifiLanBwuHandler handler_; - nearby::analytics::MockEventLogger mock_event_logger_; }; TEST_F(WifiLanBwuHandlerTest, CreateUpgradedEndpointChannel_EmptyPathInfo_Fails) { - ClientProxy client(&mock_event_logger_); + ClientProxy client; BandwidthUpgradeNegotiationFrame::UpgradePathInfo path_info; // Create an empty wifi_lan_socket. path_info.mutable_wifi_lan_socket(); @@ -99,7 +91,7 @@ TEST_F(WifiLanBwuHandlerTest, }; TEST_F(WifiLanBwuHandlerTest, CreateUpgradedEndpointChannel_IpAddress_Success) { - ClientProxy client(&mock_event_logger_); + ClientProxy client; client.AddCancellationFlag(std::string(kEndpointId)); MockInputStream input_stream; MockOutputStream output_stream; @@ -132,7 +124,7 @@ TEST_F(WifiLanBwuHandlerTest, CreateUpgradedEndpointChannel_IpAddress_Success) { TEST_F(WifiLanBwuHandlerTest, CreateUpgradedEndpointChannel_AddressCandidates_FirstCandidate_Success) { - ClientProxy client(&mock_event_logger_); + ClientProxy client; client.AddCancellationFlag(std::string(kEndpointId)); MockInputStream input_stream; MockOutputStream output_stream; @@ -171,7 +163,7 @@ TEST_F(WifiLanBwuHandlerTest, TEST_F(WifiLanBwuHandlerTest, CreateUpgradedEndpointChannel_AddressCandidates_FirstCandidate_Fails) { - ClientProxy client(&mock_event_logger_); + ClientProxy client; client.AddCancellationFlag(std::string(kEndpointId)); MockInputStream input_stream; MockOutputStream output_stream; @@ -219,18 +211,7 @@ TEST_F(WifiLanBwuHandlerTest, TEST_F(WifiLanBwuHandlerTest, InitializeUpgradedMediumForEndpoint_Success) { MediumEnvironment::Instance().Start({.use_simulated_clock = true}); - ClientProxy client(&mock_event_logger_); - client.GetAnalyticsRecorder().OnStartAdvertising( - Strategy::kP2pPointToPoint, - {location::nearby::proto::connections::Medium::BLUETOOTH}, - /*advertising_metadata_params=*/nullptr); - client.GetAnalyticsRecorder().OnBandwidthUpgradeStarted( - std::string(kEndpointId), - location::nearby::proto::connections::Medium::BLUETOOTH, - location::nearby::proto::connections::Medium::WIFI_LAN, - location::nearby::proto::connections::ConnectionAttemptDirection:: - OUTGOING, - /*connection_token=*/""); + ClientProxy client; client.AddCancellationFlag(std::string(kEndpointId)); auto wifi_lan_server_socket = std::make_unique(); EXPECT_CALL(*wifi_lan_server_socket, GetPort()).WillRepeatedly(Return(8080)); @@ -271,77 +252,78 @@ TEST_F(WifiLanBwuHandlerTest, InitializeUpgradedMediumForEndpoint_Success) { address_candidate->set_port(8888); upgrade_path_info->set_supports_client_introduction_ack(true); - ByteArray result = handler_.InitializeUpgradedMediumForEndpoint( + std::string result = handler_.InitializeUpgradedMediumForEndpoint( &client, std::string(kServiceId), std::string(kEndpointId)); - EXPECT_FALSE(result.Empty()); + EXPECT_FALSE(result.empty()); OfflineFrame result_frame; - EXPECT_TRUE(result_frame.ParseFromString(std::string(result))); + EXPECT_TRUE(result_frame.ParseFromString(result)); EXPECT_THAT(result_frame, EqualsProto(expected_frame)); +} - constexpr absl::string_view kClientSessionLog = R"pb( - event_type: CLIENT_SESSION - client_session { duration_millis: 0 } - version: "v1.5.0" - )pb"; - constexpr absl::string_view kExpectedUpgradeLog = R"pb( - event_type: CLIENT_SESSION - client_session { - duration_millis: 0 - strategy_session { - duration_millis: 0 - strategy: P2P_POINT_TO_POINT - role: ADVERTISER - advertising_phase { - duration_millis: 0 - medium: BLUETOOTH - advertising_metadata { - supports_extended_ble_advertisements: false - connected_ap_frequency: 0 - supports_nfc_technology: false - } - stop_reason: FINISH_SESSION_STOP_ADVERTISING - } - upgrade_attempt { - direction: OUTGOING - duration_millis: 0 - from_medium: BLUETOOTH - to_medium: WIFI_LAN - upgrade_result: UNFINISHED_ERROR - error_stage: UPGRADE_UNFINISHED - connection_token: "" - operation_result { - result_category: CATEGORY_DEVICE_STATE_ERROR - result_code: DEVICE_STATE_ERROR_UNFINISHED_UPGRADE_ATTEMPTS - } - num_interfaces: 1 - num_ipv6_only_interfaces: 1 - } - } - } - version: "v1.5.0" - )pb"; - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::STOP_STRATEGY_SESSION)))) - .Times(1); - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::STOP_CLIENT_SESSION)))) - .Times(3); - EXPECT_CALL(mock_event_logger_, - Log(Matcher( - HasEventType(EventType::START_CLIENT_SESSION)))) - .Times(3); - EXPECT_CALL( - mock_event_logger_, - Log(Matcher(EqualsProto(kClientSessionLog)))) - .Times(2); - EXPECT_CALL( - mock_event_logger_, - Log(Matcher(EqualsProto(kExpectedUpgradeLog)))); - // Flush pending logs. - client.GetAnalyticsRecorder().LogSession(); +TEST_F(WifiLanBwuHandlerTest, + InitializeUpgradedMediumForEndpoint_EmptyCandidates_StopsAccepting) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + auto mock_server_socket = std::make_unique(); + MockWifiLanServerSocket* raw_server_socket = mock_server_socket.get(); + + EXPECT_CALL(*raw_server_socket, GetPort()).WillRepeatedly(Return(8080)); + EXPECT_CALL(*wifi_lan_medium, IsNetworkConnected()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(*wifi_lan_medium, ListenForService(_)) + .WillOnce(Return(ByMove(std::move(mock_server_socket)))); + + EXPECT_CALL(*wifi_lan_medium, GetUpgradeAddressCandidates(_)) + .WillOnce(Return(api::UpgradeAddressInfo{.num_interfaces = 0, + .num_ipv6_only_interfaces = 0, + .address_candidates = {}})); + + std::string result = handler_.InitializeUpgradedMediumForEndpoint( + &client, std::string(kServiceId), std::string(kEndpointId)); + + EXPECT_TRUE(result.empty()); + EXPECT_FALSE( + mediums_.GetWifiLan().IsAcceptingConnections("service_id_UPGRADE")); +} + +TEST_F( + WifiLanBwuHandlerTest, + InitializeUpgradedMediumForEndpoint_AlreadyAccepting_KeepAccepting) { + MediumEnvironment::Instance().Start({.use_simulated_clock = true}); + ClientProxy client; + client.AddCancellationFlag(std::string(kEndpointId)); + + auto mock_server_socket = std::make_unique(); + MockWifiLanServerSocket* raw_server_socket = mock_server_socket.get(); + + EXPECT_CALL(*raw_server_socket, GetPort()).WillRepeatedly(Return(8080)); + EXPECT_CALL(*wifi_lan_medium, IsNetworkConnected()) + .WillRepeatedly(Return(true)); + EXPECT_CALL(*wifi_lan_medium, ListenForService(_)) + .WillOnce(Return(ByMove(std::move(mock_server_socket)))); + + EXPECT_TRUE( + mediums_.GetWifiLan() + .StartAcceptingConnections("service_id_UPGRADE", + [](const std::string&, WifiLanSocket) {}) + .has_value()); + EXPECT_TRUE( + mediums_.GetWifiLan().IsAcceptingConnections("service_id_UPGRADE")); + + EXPECT_CALL(*wifi_lan_medium, GetUpgradeAddressCandidates(_)) + .WillOnce(Return(api::UpgradeAddressInfo{.num_interfaces = 0, + .num_ipv6_only_interfaces = 0, + .address_candidates = {}})); + + std::string result = handler_.InitializeUpgradedMediumForEndpoint( + &client, std::string(kServiceId), std::string(kEndpointId)); + + EXPECT_TRUE(result.empty()); + EXPECT_TRUE( + mediums_.GetWifiLan().IsAcceptingConnections("service_id_UPGRADE")); } } // namespace diff --git a/connections/implementation/wifi_lan_endpoint_channel.cc b/connections/implementation/mediums/wifi_lan_endpoint_channel.cc similarity index 96% rename from connections/implementation/wifi_lan_endpoint_channel.cc rename to connections/implementation/mediums/wifi_lan_endpoint_channel.cc index ec3e02b1..94fb69e4 100644 --- a/connections/implementation/wifi_lan_endpoint_channel.cc +++ b/connections/implementation/mediums/wifi_lan_endpoint_channel.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "connections/implementation/wifi_lan_endpoint_channel.h" +#include "connections/implementation/mediums/wifi_lan_endpoint_channel.h" #include diff --git a/connections/implementation/wifi_lan_endpoint_channel.h b/connections/implementation/mediums/wifi_lan_endpoint_channel.h similarity index 87% rename from connections/implementation/wifi_lan_endpoint_channel.h rename to connections/implementation/mediums/wifi_lan_endpoint_channel.h index 587f5002..59d5d9e3 100644 --- a/connections/implementation/wifi_lan_endpoint_channel.h +++ b/connections/implementation/mediums/wifi_lan_endpoint_channel.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ +#ifndef CORE_INTERNAL_MEDIUMS_WIFI_LAN_ENDPOINT_CHANNEL_H_ +#define CORE_INTERNAL_MEDIUMS_WIFI_LAN_ENDPOINT_CHANNEL_H_ #include @@ -41,4 +41,4 @@ class WifiLanEndpointChannel final : public BaseEndpointChannel { } // namespace connections } // namespace nearby -#endif // CORE_INTERNAL_WIFI_LAN_ENDPOINT_CHANNEL_H_ +#endif // CORE_INTERNAL_MEDIUMS_WIFI_LAN_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/mediums/wifi_lan_test.cc b/connections/implementation/mediums/wifi_lan_test.cc index 95bbfa5c..b8d47d04 100644 --- a/connections/implementation/mediums/wifi_lan_test.cc +++ b/connections/implementation/mediums/wifi_lan_test.cc @@ -168,11 +168,6 @@ TEST_P(WifiLanTest, CanConnect) { } TEST_P(WifiLanTest, CanConnectWithMultiplex) { - bool is_multiplex_enabled = NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature::kEnableMultiplex); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableMultiplex, - true); bool is_multiplex_enabled_wifi_lan = NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature:: kEnableMultiplexWifiLan); @@ -190,6 +185,7 @@ TEST_P(WifiLanTest, CanConnectWithMultiplex) { std::string endpoint_info_name(kEndpointName); CountDownLatch discovered_latch(1); CountDownLatch accept_latch(1); + CountDownLatch connect_latch(1); WifiLanSocket socket_for_server; NsdServiceInfo nsd_service_info; @@ -226,18 +222,16 @@ TEST_P(WifiLanTest, CanConnectWithMultiplex) { ErrorOr socket_for_client_result = wifi_lan_client.Connect(service_id, discovered_service_info, &flag); socket_for_client = std::move(socket_for_client_result.value()); - Base64Utils::WriteInt(&socket_for_client_result.value().GetOutputStream(), - 4); + Base64Utils::WriteInt(&socket_for_client.GetOutputStream(), 4); + connect_latch.CountDown(); }); EXPECT_TRUE(accept_latch.Await(kWaitDuration).result()); + EXPECT_TRUE(connect_latch.Await(kWaitDuration).result()); EXPECT_TRUE(wifi_lan_server.StopAcceptingConnections(service_id)); EXPECT_TRUE(wifi_lan_server.StopAdvertising(service_id)); EXPECT_TRUE(socket_for_server.IsValid()); EXPECT_TRUE(socket_for_client.IsValid()); env_.Stop(); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableMultiplex, - is_multiplex_enabled); NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnableMultiplexWifiLan, diff --git a/connections/implementation/mock_endpoint_channel.h b/connections/implementation/mock_endpoint_channel.h new file mode 100644 index 00000000..14ea499e --- /dev/null +++ b/connections/implementation/mock_endpoint_channel.h @@ -0,0 +1,76 @@ +// Copyright 2026 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_CONNECTIONS_IMPLEMENTATION_MOCK_ENDPOINT_CHANNEL_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_MOCK_ENDPOINT_CHANNEL_H_ + +#include +#include +#include +#include "gmock/gmock.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "connections/implementation/analytics/analytics_recorder.h" +#include "connections/implementation/endpoint_channel.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/exception.h" + +namespace nearby::connections { + +class MockEndpointChannel : public EndpointChannel { + public: + MOCK_METHOD(ExceptionOr, Read, (), (override)); + MOCK_METHOD(Exception, Write, (absl::string_view data), + (override)); + MOCK_METHOD(void, Close, (), (override)); + MOCK_METHOD( + void, Close, + (location::nearby::proto::connections::DisconnectionReason reason), + (override)); + MOCK_METHOD(void, Close, + (location::nearby::proto::connections::DisconnectionReason reason, + nearby::analytics::SafeDisconnectionResult result), + (override)); + MOCK_METHOD(bool, IsClosed, (), (const, override)); + MOCK_METHOD(std::string, GetType, (), (const, override)); + MOCK_METHOD(std::string, GetServiceId, (), (const, override)); + MOCK_METHOD(std::string, GetName, (), (const, override)); + MOCK_METHOD(location::nearby::proto::connections::Medium, GetMedium, (), + (const, override)); + MOCK_METHOD(location::nearby::proto::connections::ConnectionTechnology, + GetTechnology, (), (const, override)); + MOCK_METHOD(location::nearby::proto::connections::ConnectionBand, GetBand, (), + (const, override)); + MOCK_METHOD(int, GetFrequency, (), (const, override)); + MOCK_METHOD(int, GetTryCount, (), (const, override)); + MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const, override)); + MOCK_METHOD(void, EnableEncryption, (std::shared_ptr), + (override)); + MOCK_METHOD(void, DisableEncryption, (), (override)); + MOCK_METHOD(bool, IsEncrypted, (), (override)); + MOCK_METHOD(ExceptionOr, TryDecrypt, (const ByteArray& data), + (override)); + MOCK_METHOD(bool, IsPaused, (), (const, override)); + MOCK_METHOD(void, Pause, (), (override)); + MOCK_METHOD(void, Resume, (), (override)); + MOCK_METHOD(absl::Time, GetLastReadTimestamp, (), (const, override)); + MOCK_METHOD(absl::Time, GetLastWriteTimestamp, (), (const, override)); + MOCK_METHOD(uint32_t, GetNextKeepAliveSeqNo, (), (const, override)); + MOCK_METHOD(void, SetAnalyticsRecorder, + (analytics::AnalyticsRecorder*, const std::string&), (override)); +}; + +} // namespace nearby::connections + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_IMPLEMENTATION_MOCK_ENDPOINT_CHANNEL_H_ diff --git a/connections/implementation/offline_frames.cc b/connections/implementation/offline_frames.cc index ce7ff30e..aef8c3dd 100644 --- a/connections/implementation/offline_frames.cc +++ b/connections/implementation/offline_frames.cc @@ -19,6 +19,7 @@ #include #include +#include "absl/strings/string_view.h" #include "connections/connection_options.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/internal_payload.h" @@ -27,7 +28,6 @@ #include "connections/medium_selector.h" #include "connections/status.h" #include "internal/flags/nearby_flags.h" -#include "internal/platform/byte_array.h" #include "internal/platform/exception.h" #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" @@ -38,7 +38,6 @@ namespace { using ExceptionOrOfflineFrame = ExceptionOr<::location::nearby::connections::OfflineFrame>; -using ::location::nearby::connections::AutoReconnectFrame; using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; using ::location::nearby::connections::ConnectionRequestFrame; using ::location::nearby::connections::ConnectionResponseFrame; @@ -50,19 +49,12 @@ using ::location::nearby::connections::OsInfo; using ::location::nearby::connections::PayloadTransferFrame; using ::location::nearby::connections::V1Frame; -ByteArray ToBytes(OfflineFrame&& frame) { - ByteArray bytes(frame.ByteSizeLong()); - frame.set_version(OfflineFrame::V1); - frame.SerializeToArray(bytes.data(), bytes.size()); - return bytes; -} - } // namespace -ExceptionOrOfflineFrame FromBytes(const ByteArray& bytes) { +ExceptionOrOfflineFrame FromBytes(absl::string_view bytes) { OfflineFrame frame; - if (frame.ParseFromString(std::string(bytes))) { + if (frame.ParseFromString(bytes)) { Exception validation_exception = EnsureValidOfflineFrame(frame); if (validation_exception.Raised()) { return ExceptionOrOfflineFrame(validation_exception); @@ -81,7 +73,7 @@ V1Frame::FrameType GetFrameType(const OfflineFrame& frame) { return V1Frame::UNKNOWN_FRAME_TYPE; } -ByteArray ForConnectionRequestConnections( +std::string ForConnectionRequestConnections( const location::nearby::connections::ConnectionsDevice& proto_connections_device, const ConnectionInfo& connection_info) { @@ -140,10 +132,10 @@ ByteArray ForConnectionRequestConnections( connection_info.keep_alive_timeout_millis); } - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForConnectionRequestPresence( +std::string ForConnectionRequestPresence( const location::nearby::connections::PresenceDevice& proto_presence_device, const ConnectionInfo& connection_info) { OfflineFrame frame; @@ -185,10 +177,10 @@ ByteArray ForConnectionRequestPresence( connection_info.keep_alive_timeout_millis); } - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForConnectionResponse(std::int32_t status, const OsInfo& os_info, +std::string ForConnectionResponse(std::int32_t status, const OsInfo& os_info, std::int32_t multiplex_socket_bitmask) { OfflineFrame frame; @@ -211,10 +203,10 @@ ByteArray ForConnectionResponse(std::int32_t status, const OsInfo& os_info, config_package_nearby::nearby_connections_feature:: kSafeToDisconnectVersion)); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForDataPayloadTransfer( +std::string ForDataPayloadTransfer( const PayloadTransferFrame::PayloadHeader& header, const PayloadTransferFrame::PayloadChunk& chunk) { OfflineFrame frame; @@ -227,10 +219,10 @@ ByteArray ForDataPayloadTransfer( *sub_frame->mutable_payload_header() = header; *sub_frame->mutable_payload_chunk() = chunk; - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForControlPayloadTransfer( +std::string ForControlPayloadTransfer( const PayloadTransferFrame::PayloadHeader& header, const PayloadTransferFrame::ControlMessage& control) { OfflineFrame frame; @@ -243,10 +235,10 @@ ByteArray ForControlPayloadTransfer( *sub_frame->mutable_payload_header() = header; *sub_frame->mutable_control_message() = control; - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForPayloadAckPayloadTransfer(std::int64_t payload_id) { +std::string ForPayloadAckPayloadTransfer(std::int64_t payload_id) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -260,10 +252,10 @@ ByteArray ForPayloadAckPayloadTransfer(std::int64_t payload_id) { header.set_total_size(InternalPayload::kIndeterminateSize); *sub_frame->mutable_payload_header() = header; - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuWifiHotspotPathAvailable( +std::string ForBwuWifiHotspotPathAvailable( BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WifiHotspotCredentials credentials, bool supports_disabling_encryption) { @@ -283,10 +275,10 @@ ByteArray ForBwuWifiHotspotPathAvailable( auto* wifi_hotspot_credentials = upgrade_path_info->mutable_wifi_hotspot_credentials(); *wifi_hotspot_credentials = std::move(credentials); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuWifiLanPathAvailable( +std::string ForBwuWifiLanPathAvailable( const std::vector& addresses) { OfflineFrame frame; @@ -315,10 +307,10 @@ ByteArray ForBwuWifiLanPathAvailable( VLOG(1) << "ForBwuWifiLanPathAvailable: " << address; } } - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuAwdlPathAvailable(const std::string& service_name, +std::string ForBwuAwdlPathAvailable(const std::string& service_name, const std::string& service_type, const std::string& password, bool supports_disabling_encryption) { @@ -340,10 +332,10 @@ ByteArray ForBwuAwdlPathAvailable(const std::string& service_name, awdl_socket->set_service_type(service_type); awdl_socket->set_password(password); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuWifiAwarePathAvailable(const std::string& service_id, +std::string ForBwuWifiAwarePathAvailable(const std::string& service_id, const std::string& service_info, const std::string& password, bool supports_disabling_encryption) { @@ -366,10 +358,10 @@ ByteArray ForBwuWifiAwarePathAvailable(const std::string& service_id, wifi_aware_credentials->set_service_info(service_info); if (!password.empty()) wifi_aware_credentials->set_password(password); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuWifiDirectPathAvailable( +std::string ForBwuWifiDirectPathAvailable( const std::string& ssid, const std::string& password, std::int32_t port, std::int32_t frequency, bool supports_disabling_encryption, const std::string& gateway, const std::string& service_name, @@ -397,10 +389,10 @@ ByteArray ForBwuWifiDirectPathAvailable( wifi_direct_credentials->set_service_name(service_name); wifi_direct_credentials->set_pin(pin); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, +std::string ForBwuBluetoothPathAvailable(const std::string& service_id, MacAddress mac_address) { OfflineFrame frame; @@ -418,10 +410,10 @@ ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, bluetooth_credentials->set_mac_address(mac_address.ToString()); bluetooth_credentials->set_service_name(service_id); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id, +std::string ForBwuWebrtcPathAvailable(const std::string& peer_id, const LocationHint& location_hint) { OfflineFrame frame; @@ -439,10 +431,10 @@ ByteArray ForBwuWebrtcPathAvailable(const std::string& peer_id, auto* local_location_hint = webrtc_credentials->mutable_location_hint(); *local_location_hint = location_hint; - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuLastWrite() { +std::string ForBwuLastWrite() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -452,10 +444,10 @@ ByteArray ForBwuLastWrite() { sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuSafeToClose() { +std::string ForBwuSafeToClose() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -465,10 +457,10 @@ ByteArray ForBwuSafeToClose() { sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuIntroduction(const std::string& endpoint_id, +std::string ForBwuIntroduction(const std::string& endpoint_id, bool supports_disabling_encryption) { OfflineFrame frame; @@ -483,10 +475,10 @@ ByteArray ForBwuIntroduction(const std::string& endpoint_id, client_introduction->set_supports_disabling_encryption( supports_disabling_encryption); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuIntroductionAck() { +std::string ForBwuIntroductionAck() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -496,10 +488,10 @@ ByteArray ForBwuIntroductionAck() { sub_frame->set_event_type( BandwidthUpgradeNegotiationFrame::CLIENT_INTRODUCTION_ACK); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuFailure(const UpgradePathInfo& info) { +std::string ForBwuFailure(const UpgradePathInfo& info) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -512,10 +504,10 @@ ByteArray ForBwuFailure(const UpgradePathInfo& info) { *sub_frame->mutable_upgrade_path_info() = info; - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForBwuPathRequest(const std::vector& mediums, +std::string ForBwuPathRequest(const std::vector& mediums, const MediumRole& medium_role) { OfflineFrame frame; @@ -534,10 +526,10 @@ ByteArray ForBwuPathRequest(const std::vector& mediums, upgrade_path_request->mutable_medium_meta_data()->mutable_medium_role(); role->MergeFrom(medium_role); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForKeepAlive() { +std::string ForKeepAlive() { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -545,10 +537,10 @@ ByteArray ForKeepAlive() { v1_frame->set_type(V1Frame::KEEP_ALIVE); v1_frame->mutable_keep_alive(); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForKeepAlive(bool ack, uint32_t seq_num) { +std::string ForKeepAlive(bool ack, uint32_t seq_num) { OfflineFrame frame; frame.set_version(OfflineFrame::V1); @@ -557,10 +549,10 @@ ByteArray ForKeepAlive(bool ack, uint32_t seq_num) { KeepAliveFrame* keep_alive = v1_frame->mutable_keep_alive(); keep_alive->set_ack(ack); keep_alive->set_seq_num(seq_num); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForDisconnection(bool request_safe_to_disconnect, +std::string ForDisconnection(bool request_safe_to_disconnect, bool ack_safe_to_disconnect) { OfflineFrame frame; @@ -571,33 +563,9 @@ ByteArray ForDisconnection(bool request_safe_to_disconnect, disconnection->set_request_safe_to_disconnect(request_safe_to_disconnect); disconnection->set_ack_safe_to_disconnect(ack_safe_to_disconnect); - return ToBytes(std::move(frame)); + return frame.SerializeAsString(); } -ByteArray ForAutoReconnectIntroduction(const std::string& endpoint_id) { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::AUTO_RECONNECT); - auto* auto_reconnect = v1_frame->mutable_auto_reconnect(); - auto_reconnect->set_endpoint_id(endpoint_id); - auto_reconnect->set_event_type(AutoReconnectFrame::CLIENT_INTRODUCTION); - - return ToBytes(std::move(frame)); -} - -ByteArray ForAutoReconnectIntroductionAck() { - OfflineFrame frame; - - frame.set_version(OfflineFrame::V1); - auto* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::AUTO_RECONNECT); - auto* auto_reconnect = v1_frame->mutable_auto_reconnect(); - auto_reconnect->set_event_type(AutoReconnectFrame::CLIENT_INTRODUCTION_ACK); - - return ToBytes(std::move(frame)); -} UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium) { switch (medium) { diff --git a/connections/implementation/offline_frames.h b/connections/implementation/offline_frames.h index 36567eba..bf7248b7 100644 --- a/connections/implementation/offline_frames.h +++ b/connections/implementation/offline_frames.h @@ -19,10 +19,10 @@ #include #include +#include "absl/strings/string_view.h" #include "connections/connection_options.h" #include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/medium_selector.h" -#include "internal/platform/byte_array.h" #include "internal/platform/exception.h" #include "internal/platform/mac_address.h" #include "internal/platform/service_address.h" @@ -43,7 +43,7 @@ using WifiDirectAuthType = // Returns OfflineFrame if parser was able to understand it, or // Exception::kInvalidProtocolBuffer, if parser failed. ExceptionOr FromBytes( - const ByteArray& offline_frame_bytes); + absl::string_view offline_frame_bytes); // Returns FrameType of a parsed message, or // V1Frame::UNKNOWN_FRAME_TYPE, if frame contents is not recognized. @@ -51,49 +51,49 @@ location::nearby::connections::V1Frame::FrameType GetFrameType( const location::nearby::connections::OfflineFrame& offline_frame); // Builds Connection Request / Response messages. -ByteArray ForConnectionRequestConnections( +std::string ForConnectionRequestConnections( const location::nearby::connections::ConnectionsDevice& proto_connections_device, const ConnectionInfo& connection_info); -ByteArray ForConnectionRequestPresence( +std::string ForConnectionRequestPresence( const location::nearby::connections::PresenceDevice& proto_presence_device, const ConnectionInfo& connection_info); -ByteArray ForConnectionResponse( +std::string ForConnectionResponse( std::int32_t status, const location::nearby::connections::OsInfo& os_info, std::int32_t multiplex_socket_bitmask); // Builds Payload transfer messages. -ByteArray ForDataPayloadTransfer( +std::string ForDataPayloadTransfer( const location::nearby::connections::PayloadTransferFrame::PayloadHeader& header, const location::nearby::connections::PayloadTransferFrame::PayloadChunk& chunk); -ByteArray ForControlPayloadTransfer( +std::string ForControlPayloadTransfer( const location::nearby::connections::PayloadTransferFrame::PayloadHeader& header, const location::nearby::connections::PayloadTransferFrame::ControlMessage& control); -ByteArray ForPayloadAckPayloadTransfer(std::int64_t payload_id); +std::string ForPayloadAckPayloadTransfer(std::int64_t payload_id); // Builds Bandwidth Upgrade [BWU] messages. -ByteArray ForBwuIntroduction(const std::string& endpoint_id, +std::string ForBwuIntroduction(const std::string& endpoint_id, bool supports_disabling_encryption); -ByteArray ForBwuIntroductionAck(); -ByteArray ForBwuWifiHotspotPathAvailable( +std::string ForBwuIntroductionAck(); +std::string ForBwuWifiHotspotPathAvailable( location::nearby::connections::BandwidthUpgradeNegotiationFrame:: UpgradePathInfo::WifiHotspotCredentials credentials, bool supports_disabling_encryption); -ByteArray ForBwuWifiLanPathAvailable( +std::string ForBwuWifiLanPathAvailable( const std::vector& addresses); -ByteArray ForBwuAwdlPathAvailable(const std::string& service_name, +std::string ForBwuAwdlPathAvailable(const std::string& service_name, const std::string& service_type, const std::string& password, bool supports_disabling_encryption); -ByteArray ForBwuWifiAwarePathAvailable(const std::string& service_id, +std::string ForBwuWifiAwarePathAvailable(const std::string& service_id, const std::string& service_info, const std::string& password, bool supports_disabling_encryption); -ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, +std::string ForBwuWifiDirectPathAvailable(const std::string& ssid, const std::string& password, std::int32_t port, std::int32_t frequency, @@ -101,24 +101,22 @@ ByteArray ForBwuWifiDirectPathAvailable(const std::string& ssid, const std::string& gateway, const std::string& service_name, const std::string& pin); -ByteArray ForBwuBluetoothPathAvailable(const std::string& service_id, +std::string ForBwuBluetoothPathAvailable(const std::string& service_id, MacAddress mac_address); -ByteArray ForBwuWebrtcPathAvailable( +std::string ForBwuWebrtcPathAvailable( const std::string& peer_id, const location::nearby::connections::LocationHint& location_hint_a); -ByteArray ForBwuFailure(const UpgradePathInfo& info); -ByteArray ForBwuPathRequest( +std::string ForBwuFailure(const UpgradePathInfo& info); +std::string ForBwuPathRequest( const std::vector& mediums, const location::nearby::connections::MediumRole& medium_role); -ByteArray ForBwuLastWrite(); -ByteArray ForBwuSafeToClose(); +std::string ForBwuLastWrite(); +std::string ForBwuSafeToClose(); -ByteArray ForKeepAlive(); -ByteArray ForKeepAlive(bool ack, uint32_t seq_num); -ByteArray ForDisconnection(bool request_safe_to_disconnect, +std::string ForKeepAlive(); +std::string ForKeepAlive(bool ack, uint32_t seq_num); +std::string ForDisconnection(bool request_safe_to_disconnect, bool ack_safe_to_disconnect); -ByteArray ForAutoReconnectIntroduction(const std::string& endpoint_id); -ByteArray ForAutoReconnectIntroductionAck(); UpgradePathInfo::Medium MediumToUpgradePathInfoMedium(Medium medium); Medium UpgradePathInfoMediumToMedium(UpgradePathInfo::Medium medium); diff --git a/connections/implementation/offline_frames_test.cc b/connections/implementation/offline_frames_test.cc index 2f3f7965..10fc9f07 100644 --- a/connections/implementation/offline_frames_test.cc +++ b/connections/implementation/offline_frames_test.cc @@ -88,8 +88,7 @@ TEST(OfflineFramesTest, CanParseMessageFromBytes) { sub_frame->add_mediums(MediumToConnectionRequestMedium(medium)); } } - auto serialized_bytes = ByteArray(tx_message.SerializeAsString()); - auto ret_value = FromBytes(serialized_bytes); + auto ret_value = FromBytes(tx_message.SerializeAsString()); ASSERT_TRUE(ret_value.ok()); const auto& rx_message = ret_value.result(); EXPECT_THAT(rx_message, EqualsProto(tx_message)); @@ -141,8 +140,8 @@ TEST(OfflineFramesTest, CanGenerateLegacyConnectionRequest) { kMediums.begin(), kMediums.end()), kKeepAliveIntervalMillis, kKeepAliveTimeoutMillis}; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info); - auto response = FromBytes(bytes); + auto response = + FromBytes(ForConnectionRequestConnections({}, connection_info)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -208,9 +207,8 @@ TEST(OfflineFramesTest, CanGenerateConnectionsConnectionRequest) { kKeepAliveIntervalMillis, kKeepAliveTimeoutMillis, medium_role}; - ByteArray bytes = - ForConnectionRequestConnections(connections_device, connection_info); - auto response = FromBytes(bytes); + auto response = FromBytes( + ForConnectionRequestConnections(connections_device, connection_info)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -268,9 +266,8 @@ TEST(OfflineFramesTest, CanGeneratePresenceConnectionRequest) { presence_device.set_endpoint_type( location::nearby::connections::PRESENCE_ENDPOINT); presence_device.set_device_name("TEST DEVICE"); - ByteArray bytes = - ForConnectionRequestPresence(presence_device, connection_info); - auto response = FromBytes(bytes); + auto response = + FromBytes(ForConnectionRequestPresence(presence_device, connection_info)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -336,9 +333,8 @@ TEST(OfflineFramesTest, location::nearby::connections::CONNECTIONS_ENDPOINT); connections_device.set_endpoint_info("XYZ"); - ByteArray bytes = - ForConnectionRequestConnections(connections_device, connection_info); - auto response = FromBytes(bytes); + auto response = FromBytes( + ForConnectionRequestConnections(connections_device, connection_info)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -365,9 +361,8 @@ TEST(OfflineFramesTest, CanGenerateConnectionResponse) { config_package_nearby::nearby_connections_feature:: kSafeToDisconnectVersion, 5); - ByteArray bytes = - ForConnectionResponse(1, os_info, /*multiplex_socket_bitmask=*/0x01); - auto response = FromBytes(bytes); + auto response = FromBytes( + ForConnectionResponse(1, os_info, /*multiplex_socket_bitmask=*/0x01)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -393,8 +388,7 @@ TEST(OfflineFramesTest, CanGenerateControlPayloadTransfer) { control_message: < event: PAYLOAD_CANCELED offset: 150 > > >)pb"; - ByteArray bytes = ForControlPayloadTransfer(header, control); - auto response = FromBytes(bytes); + auto response = FromBytes(ForControlPayloadTransfer(header, control)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -421,8 +415,7 @@ TEST(OfflineFramesTest, CanGenerateDataPayloadTransfer) { payload_chunk: < flags: 1 offset: 150 body: "payload data" > > >)pb"; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - auto response = FromBytes(bytes); + auto response = FromBytes(ForDataPayloadTransfer(header, chunk)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -439,8 +432,7 @@ TEST(OfflineFramesTest, CanGeneratePayloadAckPayloadTransfer) { payload_header: < id: 12345 total_size: -1 > > >)pb"; - ByteArray bytes = ForPayloadAckPayloadTransfer(12345); - auto response = FromBytes(bytes); + auto response = FromBytes(ForPayloadAckPayloadTransfer(12345)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -487,9 +479,8 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiHotspotPathAvailable) { address_candidate = credentials.add_address_candidates(); address_candidate->set_ip_address(std::string("\xc0\xa8\x00\x01", 4)); address_candidate->set_port(5678); - ByteArray bytes = - ForBwuWifiHotspotPathAvailable(std::move(credentials), false); - auto response = FromBytes(bytes); + auto response = + FromBytes(ForBwuWifiHotspotPathAvailable(std::move(credentials), false)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -521,7 +512,7 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiLanPathAvailable) { > > >)pb"; - ByteArray bytes = ForBwuWifiLanPathAvailable( + std::string bytes = ForBwuWifiLanPathAvailable( {ServiceAddress{ .address = {'\x2a', '\x00', '\x79', '\xe0', '\x2e', '\x87', '\x00', '\x06', '\xb7', '\x28', '\x67', '\x45', '\x7a', '\xdd', @@ -555,9 +546,8 @@ TEST(OfflineFramesTest, CanGenerateBwuAwdlPathAvailable) { > > >)pb"; - ByteArray bytes = ForBwuAwdlPathAvailable("service_name", "nearby_upgrade", - "password", true); - auto response = FromBytes(bytes); + auto response = FromBytes(ForBwuAwdlPathAvailable( + "service_name", "nearby_upgrade", "password", true)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -583,9 +573,9 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiAwarePathAvailable) { > > >)pb"; - ByteArray bytes = ForBwuWifiAwarePathAvailable("service_id", "service_info", - "password", false); - auto response = FromBytes(bytes); + auto response = FromBytes( + ForBwuWifiAwarePathAvailable("service_id", "service_info", "password", + /*supports_disabling_encryption=*/false)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -615,10 +605,10 @@ TEST(OfflineFramesTest, CanGenerateBwuWifiDirectPathAvailable) { > > >)pb"; - ByteArray bytes = ForBwuWifiDirectPathAvailable( - "", "", 1000, 2412, false, "192.168.1.1", - "NC-WifiDirectTest", "b592f7d3"); - auto response = FromBytes(bytes); + auto response = FromBytes(ForBwuWifiDirectPathAvailable( + /*ssid=*/"", /*password=*/"", /*port=*/1000, /*frequency=*/2412, + /*supports_disabling_encryption=*/false, "192.168.1.1", + "NC-WifiDirectTest", "b592f7d3")); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -644,8 +634,8 @@ TEST(OfflineFramesTest, CanGenerateBwuBluetoothPathAvailable) { >)pb"; MacAddress mac_address; MacAddress::FromString("11:22:33:44:55:66", mac_address); - ByteArray bytes = ForBwuBluetoothPathAvailable("service", mac_address); - auto response = FromBytes(bytes); + auto response = + FromBytes(ForBwuBluetoothPathAvailable("service", mac_address)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -659,8 +649,7 @@ TEST(OfflineFramesTest, CanGenerateBwuLastWrite) { type: BANDWIDTH_UPGRADE_NEGOTIATION bandwidth_upgrade_negotiation: < event_type: LAST_WRITE_TO_PRIOR_CHANNEL > >)pb"; - ByteArray bytes = ForBwuLastWrite(); - auto response = FromBytes(bytes); + auto response = FromBytes(ForBwuLastWrite()); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -674,8 +663,7 @@ TEST(OfflineFramesTest, CanGenerateBwuSafeToClose) { type: BANDWIDTH_UPGRADE_NEGOTIATION bandwidth_upgrade_negotiation: < event_type: SAFE_TO_CLOSE_PRIOR_CHANNEL > >)pb"; - ByteArray bytes = ForBwuSafeToClose(); - auto response = FromBytes(bytes); + auto response = FromBytes(ForBwuSafeToClose()); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -695,9 +683,8 @@ TEST(OfflineFramesTest, CanGenerateBwuIntroduction) { > > >)pb"; - ByteArray bytes = ForBwuIntroduction( - std::string(kEndpointId), false /* supports_disabling_encryption */); - auto response = FromBytes(bytes); + auto response = FromBytes(ForBwuIntroduction( + std::string(kEndpointId), false /* supports_disabling_encryption */)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -711,8 +698,7 @@ TEST(OfflineFramesTest, CanGenerateKeepAlive) { type: KEEP_ALIVE keep_alive: <> >)pb"; - ByteArray bytes = ForKeepAlive(); - auto response = FromBytes(bytes); + auto response = FromBytes(ForKeepAlive()); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); @@ -729,43 +715,14 @@ TEST(OfflineFramesTest, CanGenerateDisconnection) { ack_safe_to_disconnect: true > >)pb"; - ByteArray bytes = ForDisconnection(/* request_safe_to_disconnect */ true, - /* ack_safe_to_disconnect */ true); - auto response = FromBytes(bytes); + auto response = + FromBytes(ForDisconnection(/* request_safe_to_disconnect */ true, + /* ack_safe_to_disconnect */ true)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); } -TEST(OfflineFramesTest, CanGenerateAutoReconnectIntroduction) { - constexpr absl::string_view kExpected = - R"pb( - version: V1 - v1: < - type: AUTO_RECONNECT - auto_reconnect: < event_type: CLIENT_INTRODUCTION endpoint_id: "ABC" > - >)pb"; - ByteArray bytes = ForAutoReconnectIntroduction(std::string(kEndpointId)); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = response.result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} - -TEST(OfflineFramesTest, CanGenerateAutoReconnectIntroductionAck) { - constexpr absl::string_view kExpected = - R"pb( - version: V1 - v1: < - type: AUTO_RECONNECT - auto_reconnect: < event_type: CLIENT_INTRODUCTION_ACK > - >)pb"; - ByteArray bytes = ForAutoReconnectIntroductionAck(); - auto response = FromBytes(bytes); - ASSERT_TRUE(response.ok()); - OfflineFrame message = response.result(); - EXPECT_THAT(message, EqualsProto(kExpected)); -} TEST(OfflineFramesTest, CanGenerateBwuPathRequest) { constexpr absl::string_view kExpected = @@ -789,8 +746,7 @@ TEST(OfflineFramesTest, CanGenerateBwuPathRequest) { mediums.push_back(Medium::WIFI_HOTSPOT); MediumRole medium_role; medium_role.set_support_wifi_hotspot_client(true); - ByteArray bytes = ForBwuPathRequest(mediums, medium_role); - auto response = FromBytes(bytes); + auto response = FromBytes(ForBwuPathRequest(mediums, medium_role)); ASSERT_TRUE(response.ok()); OfflineFrame message = response.result(); EXPECT_THAT(message, EqualsProto(kExpected)); diff --git a/connections/implementation/offline_frames_validator_test.cc b/connections/implementation/offline_frames_validator_test.cc index 7695b64c..0a1376d7 100644 --- a/connections/implementation/offline_frames_validator_test.cc +++ b/connections/implementation/offline_frames_validator_test.cc @@ -66,24 +66,24 @@ constexpr int kKeepAliveTimeoutMillis = 5000; class OfflineFramesConnectionRequestTest : public testing::Test { protected: - ConnectionInfo connection_info_{std::string(kEndpointId), - ByteArray{std::string(kEndpointName)}, - kNonce, - kSupports5ghz, - std::string(kBssid), - kApFrequency, - std::vector>( - kMediums.begin(), kMediums.end()), - kKeepAliveIntervalMillis, - kKeepAliveTimeoutMillis}; + ConnectionInfo connection_info_{ + std::string(kEndpointId), + ByteArray{std::string(kEndpointName)}, + kNonce, + kSupports5ghz, + std::string(kBssid), + kApFrequency, + std::vector(kMediums.begin(), kMediums.end()), + kKeepAliveIntervalMillis, + kKeepAliveTimeoutMillis}; }; TEST_F(OfflineFramesConnectionRequestTest, ValidatesAsOkWithValidConnectionRequestFrame) { OfflineFrame offline_frame; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -94,8 +94,8 @@ TEST_F(OfflineFramesConnectionRequestTest, ValidatesAsFailWithNullConnectionRequestFrame) { OfflineFrame offline_frame; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); v1_frame->clear_connection_request(); @@ -110,8 +110,8 @@ TEST_F(OfflineFramesConnectionRequestTest, OfflineFrame offline_frame; connection_info_.local_endpoint_id = ""; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -121,9 +121,9 @@ TEST_F(OfflineFramesConnectionRequestTest, TEST_F(OfflineFramesConnectionRequestTest, ValidatesAsFailWithEmptyEndpointIdInConnectionRequestFrame) { connection_info_.local_endpoint_id = ""; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); location::nearby::connections::OfflineFrame frame; - frame.ParseFromString(bytes.AsStringView()); + frame.ParseFromString(bytes); frame.mutable_v1()->mutable_connection_request()->set_endpoint_id(""); ASSERT_TRUE(frame.v1().connection_request().has_endpoint_id()); @@ -140,8 +140,8 @@ TEST_F(OfflineFramesConnectionRequestTest, OfflineFrame offline_frame; connection_info_.local_endpoint_info = ByteArray{""}; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -153,8 +153,8 @@ TEST_F(OfflineFramesConnectionRequestTest, OfflineFrame offline_frame; connection_info_.bssid = ""; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -166,8 +166,8 @@ TEST_F(OfflineFramesConnectionRequestTest, OfflineFrame offline_frame; connection_info_.supported_mediums = {}; - ByteArray bytes = ForConnectionRequestConnections({}, connection_info_); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForConnectionRequestConnections({}, connection_info_); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -179,9 +179,9 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; OsInfo os_info; - ByteArray bytes = ForConnectionResponse(kStatusAccepted, os_info, + std::string bytes = ForConnectionResponse(kStatusAccepted, os_info, /*multiplex_socket_bitmask=*/0); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -193,9 +193,9 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; OsInfo os_info; - ByteArray bytes = ForConnectionResponse(kStatusAccepted, os_info, + std::string bytes = ForConnectionResponse(kStatusAccepted, os_info, /*multiplex_socket_bitmask=*/0); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); v1_frame->clear_connection_response(); @@ -210,9 +210,9 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; OsInfo os_info; - ByteArray bytes = + std::string bytes = ForConnectionResponse(-1, os_info, /*multiplex_socket_bitmask=*/0); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -234,8 +234,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsOkWithValidPayloadTransferFrame) { OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -259,8 +259,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -284,8 +284,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsOkTypeFileWithLegalFilePath) { OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -309,8 +309,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsFailedTypeFileWithIllegalFilePath) { OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -334,8 +334,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsOkTypeFileWithLegalParentFolder) { OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -360,8 +360,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -377,8 +377,8 @@ TEST(OfflineFramesValidatorTest, ValidatesAsFailWithNullPayloadTransferFrame) { OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); v1_frame->clear_payload_transfer(); @@ -401,8 +401,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); auto* payload_transfer = v1_frame->mutable_payload_transfer(); @@ -426,8 +426,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -447,8 +447,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); auto* payload_transfer = v1_frame->mutable_payload_transfer(); @@ -472,8 +472,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -493,8 +493,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -514,8 +514,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); auto* payload_transfer = v1_frame->mutable_payload_transfer(); auto* payload_chunk = payload_transfer->mutable_payload_chunk(); @@ -539,8 +539,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForControlPayloadTransfer(header, control); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForControlPayloadTransfer(header, control); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); auto* payload_transfer = v1_frame->mutable_payload_transfer(); @@ -564,8 +564,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForControlPayloadTransfer(header, control); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForControlPayloadTransfer(header, control); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -584,8 +584,8 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame; - ByteArray bytes = ForControlPayloadTransfer(header, control); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForControlPayloadTransfer(header, control); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -603,9 +603,9 @@ TEST(OfflineFramesValidatorTest, credentials.set_port(kPort); credentials.set_frequency(kHotspotFrequency); credentials.set_gateway(kWifiHotspotGateway); - ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::string bytes = ForBwuWifiHotspotPathAvailable( std::move(credentials), kSupportsDisablingEncryption); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -628,9 +628,9 @@ TEST(OfflineFramesValidatorTest, candidate = credentials.mutable_address_candidates()->Add(); candidate->set_ip_address(std::string("\xc0\xa8\x00\x01", 4)); candidate->set_port(kPort); - ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::string bytes = ForBwuWifiHotspotPathAvailable( std::move(credentials), kSupportsDisablingEncryption); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -650,9 +650,9 @@ TEST(OfflineFramesValidatorTest, candidate->set_ip_address(std::string( "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 12)); candidate->set_port(kPort); - ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::string bytes = ForBwuWifiHotspotPathAvailable( std::move(credentials), kSupportsDisablingEncryption); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -671,9 +671,9 @@ TEST(OfflineFramesValidatorTest, auto* candidate = credentials.mutable_address_candidates()->Add(); candidate->set_ip_address(std::string( "\xfe\x80\x00\x00\x00\x00\x00\x00\x4d\xb2\xb3\x5c\x22\x03\x98\xa1", 16)); - ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::string bytes = ForBwuWifiHotspotPathAvailable( std::move(credentials), kSupportsDisablingEncryption); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -689,8 +689,8 @@ TEST(OfflineFramesValidatorTest, kPort}, {{'\xc0', '\xa8', '\x00', '\x01'}, kPort}, }; - ByteArray bytes = ForBwuWifiLanPathAvailable(address_candidates); - offline_frame.ParseFromString(std::string(bytes)); + std::string bytes = ForBwuWifiLanPathAvailable(address_candidates); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -708,9 +708,9 @@ TEST(OfflineFramesValidatorTest, credentials.set_port(kPort); credentials.set_frequency(kHotspotFrequency); credentials.set_gateway(kWifiHotspotGateway); - ByteArray bytes = ForBwuWifiHotspotPathAvailable( + std::string bytes = ForBwuWifiHotspotPathAvailable( std::move(credentials), kSupportsDisablingEncryption); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto* v1_frame = offline_frame.mutable_v1(); v1_frame->clear_bandwidth_upgrade_negotiation(); @@ -723,11 +723,11 @@ TEST(OfflineFramesValidatorTest, TEST(OfflineFramesValidatorTest, ValidatesAsOkBandwidthUpgradeWifiDirect) { OfflineFrame offline_frame; - ByteArray bytes = ForBwuWifiDirectPathAvailable( + std::string bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway), std::string(kWifiDirectServiceName), std::string(kWifiDirectPin)); - offline_frame.ParseFromString(std::string(bytes)); + offline_frame.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame); @@ -740,11 +740,11 @@ TEST(OfflineFramesValidatorTest, OfflineFrame offline_frame_2; // Anything less than -1 is invalid - ByteArray bytes = ForBwuWifiDirectPathAvailable( + std::string bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, -2, kSupportsDisablingEncryption, std::string(kGateway), std::string(kWifiDirectServiceName), std::string(kWifiDirectPin)); - offline_frame_1.ParseFromString(std::string(bytes)); + offline_frame_1.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -755,7 +755,7 @@ TEST(OfflineFramesValidatorTest, std::string(kWifiDirectSsid), std::string(kWifiDirectPassword), kPort, -1, kSupportsDisablingEncryption, std::string(kGateway), std::string(kWifiDirectServiceName), std::string(kWifiDirectPin)); - offline_frame_2.ParseFromString(std::string(bytes)); + offline_frame_2.ParseFromString(bytes); ret_value = EnsureValidOfflineFrame(offline_frame_2); @@ -769,12 +769,12 @@ TEST(OfflineFramesValidatorTest, std::string wifi_direct_ssid{"DIRECT-A*-0123456789AB"}; std::string wifi_direct_pin_wrong_length = "abc"; - ByteArray bytes = ForBwuWifiDirectPathAvailable( + std::string bytes = ForBwuWifiDirectPathAvailable( wifi_direct_ssid, std::string(kWifiDirectPassword), kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway), std::string(kWifiDirectServiceName), wifi_direct_pin_wrong_length); - offline_frame_1.ParseFromString(std::string(bytes)); + offline_frame_1.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -790,7 +790,7 @@ TEST(OfflineFramesValidatorTest, kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway), wifi_direct_service_name_wrong_length, std::string(kWifiDirectPin)); - offline_frame_2.ParseFromString(std::string(bytes)); + offline_frame_2.ParseFromString(bytes); ret_value = EnsureValidOfflineFrame(offline_frame_2); @@ -804,12 +804,12 @@ TEST(OfflineFramesValidatorTest, std::string short_wifi_direct_password{"Test"}; std::string short_wifi_direct_pin{"abc"}; - ByteArray bytes = ForBwuWifiDirectPathAvailable( + std::string bytes = ForBwuWifiDirectPathAvailable( std::string(kWifiDirectSsid), short_wifi_direct_password, kPort, kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway), std::string(kWifiDirectServiceName), short_wifi_direct_pin); - offline_frame_1.ParseFromString(std::string(bytes)); + offline_frame_1.ParseFromString(bytes); auto ret_value = EnsureValidOfflineFrame(offline_frame_1); @@ -826,7 +826,7 @@ TEST(OfflineFramesValidatorTest, kWifiDirectFrequency, kSupportsDisablingEncryption, std::string(kGateway), std::string(kWifiDirectServiceName), long_wifi_direct_pin); - offline_frame_2.ParseFromString(std::string(bytes)); + offline_frame_2.ParseFromString(bytes); ret_value = EnsureValidOfflineFrame(offline_frame_2); diff --git a/connections/implementation/offline_service_controller.cc b/connections/implementation/offline_service_controller.cc index 4e667773..af10471e 100644 --- a/connections/implementation/offline_service_controller.cc +++ b/connections/implementation/offline_service_controller.cc @@ -90,6 +90,7 @@ OfflineServiceController::StartListeningForIncomingConnections( ClientProxy* client, absl::string_view service_id, v3::ConnectionListener listener, const v3::ConnectionListeningOptions& options) { + if (stop_) return {{Status::kOutOfOrderApiCall}, {}}; LOG(INFO) << "Client " << client->GetClientId() << " requested to start listening for service_id " << service_id; return pcp_manager_.StartListeningForIncomingConnections( @@ -98,6 +99,7 @@ OfflineServiceController::StartListeningForIncomingConnections( void OfflineServiceController::StopListeningForIncomingConnections( ClientProxy* client) { + if (stop_) return; LOG(INFO) << "Client " << client->GetClientId() << " requested to stop listening for service_id " << client->GetListeningForIncomingConnectionsServiceId(); diff --git a/connections/implementation/offline_service_controller_test.cc b/connections/implementation/offline_service_controller_test.cc index d82d1893..59fb79cb 100644 --- a/connections/implementation/offline_service_controller_test.cc +++ b/connections/implementation/offline_service_controller_test.cc @@ -567,6 +567,33 @@ TEST_P(OfflineServiceControllerTest, ShutdownBwuManagerExecutors) { env_.Stop(); } +TEST_P(OfflineServiceControllerTest, TestNoStartListeningAfterStop) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + v3::ConnectionListener listener; + v3::ConnectionListeningOptions options; + + user_a.Stop(); + + auto result = user_a.StartListeningForIncomingConnections( + std::string(kServiceId), listener, options); + EXPECT_EQ(result.first.value, Status::kOutOfOrderApiCall); + + env_.Stop(); +} + +TEST_P(OfflineServiceControllerTest, TestNoStopListeningAfterStop) { + env_.Start(); + OfflineSimulationUser user_a(kDeviceA, GetParam()); + + user_a.Stop(); + + // Verify that calling StopListening after Stop does not crash. + user_a.StopListeningForIncomingConnections(); + + env_.Stop(); +} + INSTANTIATE_TEST_SUITE_P(ParametrisedOfflineServiceControllerTest, OfflineServiceControllerTest, ::testing::ValuesIn(kTestCases)); diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index 73dc47f4..c207e91b 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -29,13 +29,10 @@ #include "absl/strings/string_view.h" #include "connections/advertising_options.h" #include "connections/discovery_options.h" -#include "connections/implementation/awdl_endpoint_channel.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/implementation/base_pcp_handler.h" #include "connections/implementation/ble_advertisement.h" -#include "connections/implementation/ble_endpoint_channel.h" -#include "connections/implementation/ble_l2cap_endpoint_channel.h" #include "connections/implementation/bluetooth_device_name.h" -#include "connections/implementation/bluetooth_endpoint_channel.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel_manager.h" @@ -44,16 +41,20 @@ #include "connections/implementation/injected_bluetooth_device_store.h" #include "connections/implementation/mediums/advertisements/advertisement_util.h" #include "connections/implementation/mediums/advertisements/dct_advertisement.h" +#include "connections/implementation/mediums/awdl_endpoint_channel.h" #include "connections/implementation/mediums/ble.h" #include "connections/implementation/mediums/ble/ble_advertisement_header.h" #include "connections/implementation/mediums/ble/ble_socket.h" +#include "connections/implementation/mediums/ble_endpoint_channel.h" +#include "connections/implementation/mediums/ble_l2cap_endpoint_channel.h" #include "connections/implementation/mediums/bluetooth_classic.h" +#include "connections/implementation/mediums/bluetooth_endpoint_channel.h" #include "connections/implementation/mediums/mediums.h" #include "connections/implementation/mediums/utils.h" +#include "connections/implementation/mediums/wifi_lan_endpoint_channel.h" #include "connections/implementation/pcp.h" #include "connections/implementation/pcp_handler.h" #include "connections/implementation/webrtc_state.h" -#include "connections/implementation/wifi_lan_endpoint_channel.h" #include "connections/implementation/wifi_lan_service_info.h" #include "connections/medium_selector.h" #include "connections/out_of_band_connection_metadata.h" @@ -67,6 +68,7 @@ #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/bluetooth_classic.h" #include "internal/platform/byte_array.h" +#include "internal/platform/cancellation_flag.h" #include "internal/platform/expected.h" #include "internal/platform/implementation/platform.h" #include "internal/platform/logging.h" @@ -81,7 +83,6 @@ namespace nearby { namespace connections { namespace { -using ::location::nearby::analytics::proto::ConnectionsLog; using ::location::nearby::proto::connections::OperationResultCode; using ::location::nearby::proto::connections::Medium::AWDL; using ::location::nearby::proto::connections::Medium::BLE; @@ -89,6 +90,7 @@ using ::location::nearby::proto::connections::Medium::BLUETOOTH; using ::location::nearby::proto::connections::Medium::UNKNOWN_MEDIUM; using ::location::nearby::proto::connections::Medium::WEB_RTC; using ::location::nearby::proto::connections::Medium::WIFI_LAN; +using ::nearby::analytics::OperationResultWithMedium; } // namespace @@ -156,8 +158,7 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( const std::string& local_endpoint_id, const ByteArray& local_endpoint_info, const AdvertisingOptions& advertising_options) { std::vector mediums_started_successfully; - std::vector - operation_result_with_mediums; + std::vector operation_result_with_mediums; WebRtcState web_rtc_state{WebRtcState::kUnconnectable}; @@ -177,13 +178,12 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( VLOG(1) << "P2pClusterPcpHandler::StartAdvertisingImpl: Awdl added"; mediums_started_successfully.push_back(awdl_medium); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, AWDL, /*update_index=*/0, awdl_result.has_error() ? awdl_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } // WifiLan @@ -199,13 +199,12 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( VLOG(1) << "P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added"; mediums_started_successfully.push_back(wifi_lan_medium); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, WIFI_LAN, /*update_index=*/0, wifi_lan_result.has_error() ? wifi_lan_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } if (advertising_options.allowed.bluetooth) { @@ -243,14 +242,13 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( bluetooth_classic_advertiser_client_id_ = client->GetClientId(); } } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, BLUETOOTH, /*update_index=*/0, bluetooth_result.has_error() ? bluetooth_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } if (advertising_options.allowed.ble) { @@ -263,12 +261,12 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( mediums_started_successfully.push_back(ble_result.value()); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, BLE, /*update_index=*/0, ble_result.has_error() ? ble_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); + : OperationResultCode::DETAIL_SUCCESS)); } if (mediums_started_successfully.empty()) { @@ -1042,8 +1040,7 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( } std::vector mediums_started_successfully; - std::vector - operation_result_with_mediums; + std::vector operation_result_with_mediums; // Due to singleton, apple only allow start discovery once. So need to keep // the start discovery order of awdl before the wifi_lan. @@ -1059,14 +1056,13 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( LOG(INFO) << "P2pClusterPcpHandler::StartDiscoveryImpl: AWDL added"; mediums_started_successfully.push_back(awdl_medium); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, AWDL, /*update_index=*/0, awdl_result.has_error() ? awdl_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } // WifiLan @@ -1080,14 +1076,13 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( LOG(INFO) << "P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added"; mediums_started_successfully.push_back(wifi_lan_medium); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, WIFI_LAN, /*update_index=*/0, wifi_lan_result.has_error() ? wifi_lan_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } if (discovery_options.allowed.ble) { @@ -1102,14 +1097,13 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( mediums_started_successfully.push_back(ble_medium); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client, BLE, /*update_index=*/0, ble_result.has_error() ? ble_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } if (discovery_options.allowed.bluetooth) { @@ -1158,8 +1152,7 @@ Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) { ble_medium_.StopScanning(client->GetDiscoveryServiceId()); - paused_bluetooth_clients_discoveries_.erase( - client->GetDiscoveryServiceId()); + paused_bluetooth_clients_discoveries_.erase(client->GetDiscoveryServiceId()); return {Status::kSuccess}; } @@ -1235,8 +1228,7 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( bool refactor_ble_l2cap = NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature::kRefactorBleL2cap); std::vector started_mediums; - std::vector - operation_result_with_mediums; + std::vector operation_result_with_mediums; int update_index = client_proxy->GetAnalyticsRecorder().GetNextAdvertisingUpdateIndex(); if (options.enable_bluetooth_listening && @@ -1254,13 +1246,12 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( } else { started_mediums.push_back(BLUETOOTH); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client_proxy, Medium::BLUETOOTH, update_index, bluetooth_result.has_error() ? bluetooth_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } // ble @@ -1344,13 +1335,12 @@ P2pClusterPcpHandler::StartListeningForIncomingConnectionsImpl( } else { started_mediums.push_back(WIFI_LAN); } - std::unique_ptr - operation_result_with_medium = GetOperationResultWithMediumByResultCode( + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( client_proxy, Medium::BLUETOOTH, update_index, wifi_lan_result.has_error() ? wifi_lan_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + : OperationResultCode::DETAIL_SUCCESS)); } if (started_mediums.empty()) { LOG(WARNING) << absl::StrFormat( @@ -1443,8 +1433,7 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( // restart std::vector restarted_mediums; - std::vector - operation_result_with_mediums; + std::vector operation_result_with_mediums; int update_index = client->GetAnalyticsRecorder().GetNextAdvertisingUpdateIndex(); Status status = {Status::kSuccess}; @@ -1457,12 +1446,9 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( if (new_mediums.ble) { if (old_mediums.ble && !needs_restart) { restarted_mediums.push_back(BLE); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLE, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLE, update_index, OperationResultCode::DETAIL_SUCCESS)); } else { ErrorOr ble_result = {Error(OperationResultCode::DETAIL_UNKNOWN)}; ble_result = StartBleAdvertising( @@ -1475,14 +1461,12 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( status = {Status::kBleError}; } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLE, update_index, - ble_result.has_error() - ? ble_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLE, update_index, + ble_result.has_error() + ? ble_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } // awdl @@ -1491,12 +1475,9 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( new_mediums.awdl && !advertising_options.low_power) { if (old_mediums.awdl && !needs_restart) { restarted_mediums.push_back(AWDL); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, AWDL, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, AWDL, update_index, OperationResultCode::DETAIL_SUCCESS)); } else { ErrorOr awdl_result = StartAwdlAdvertising( client, std::string(service_id), std::string(local_endpoint_id), @@ -1506,26 +1487,22 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( } else { status = {Status::kWifiLanError}; } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, AWDL, update_index, - awdl_result.has_error() - ? awdl_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, AWDL, update_index, + awdl_result.has_error() + ? awdl_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } // wifi lan if (new_mediums.wifi_lan && !advertising_options.low_power) { if (old_mediums.wifi_lan && !needs_restart) { restarted_mediums.push_back(WIFI_LAN); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, WIFI_LAN, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, WIFI_LAN, update_index, + OperationResultCode::DETAIL_SUCCESS)); } else { ErrorOr wifi_lan_result = StartWifiLanAdvertising( client, std::string(service_id), std::string(local_endpoint_id), @@ -1536,26 +1513,22 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( } else { status = {Status::kWifiLanError}; } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, WIFI_LAN, update_index, - wifi_lan_result.has_error() - ? wifi_lan_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, WIFI_LAN, update_index, + wifi_lan_result.has_error() + ? wifi_lan_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } // bluetooth classic if (new_mediums.bluetooth && !advertising_options.low_power) { if (old_mediums.bluetooth && !needs_restart) { restarted_mediums.push_back(BLUETOOTH); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLUETOOTH, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLUETOOTH, update_index, + OperationResultCode::DETAIL_SUCCESS)); } else { const ByteArray bluetooth_hash = GenerateHash( std::string(service_id), BluetoothDeviceName::kServiceIdHashLength); @@ -1589,27 +1562,19 @@ P2pClusterPcpHandler::UpdateAdvertisingOptionsImpl( restarted_mediums.push_back(BLUETOOTH); } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLUETOOTH, update_index, - bluetooth_result.has_error() - ? bluetooth_result.error() - .operation_result_code() - .value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLUETOOTH, update_index, + bluetooth_result.has_error() + ? bluetooth_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } else { - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLUETOOTH, update_index, - bluetooth_result.has_error() - ? bluetooth_result.error() - .operation_result_code() - .value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLUETOOTH, update_index, + bluetooth_result.has_error() + ? bluetooth_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); return StartOperationResult{.status = {Status::kBluetoothError}, .mediums = restarted_mediums, .operation_result_with_mediums = std::move( @@ -1661,8 +1626,7 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( bool should_start_discovery = false; auto new_mediums = discovery_options.allowed; auto old_mediums = old_options.allowed; - std::vector - operation_result_with_mediums; + std::vector operation_result_with_mediums; int update_index = client->GetAnalyticsRecorder().GetNextDiscoveryUpdateIndex(); // ble @@ -1670,12 +1634,9 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( should_start_discovery = true; if (old_mediums.ble) { restarted_mediums.push_back(BLE); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLE, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLE, update_index, OperationResultCode::DETAIL_SUCCESS)); } else { ErrorOr ble_result = {Error(OperationResultCode::DETAIL_UNKNOWN)}; ble_result = @@ -1687,14 +1648,12 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( "restart ble scanning"; } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLE, update_index, - ble_result.has_error() - ? ble_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLE, update_index, + ble_result.has_error() + ? ble_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } // bt classic @@ -1702,12 +1661,10 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( should_start_discovery = true; if (!needs_restart && old_mediums.bluetooth) { restarted_mediums.push_back(BLUETOOTH); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLUETOOTH, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLUETOOTH, update_index, + OperationResultCode::DETAIL_SUCCESS)); } else { StartBluetoothDiscoveryWithPause( client, std::string(service_id), discovery_options, restarted_mediums, @@ -1721,12 +1678,10 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( should_start_discovery = true; if (!needs_restart && old_mediums.awdl) { restarted_mediums.push_back(AWDL); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, AWDL, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, AWDL, update_index, + OperationResultCode::DETAIL_SUCCESS)); } else { ErrorOr awdl_result = StartAwdlDiscovery(client, std::string(service_id)); @@ -1736,14 +1691,12 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( LOG(WARNING) << "UpdateDiscoveryOptionsImpl: unable to restart " "awdl scanning"; } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, AWDL, update_index, - awdl_result.has_error() - ? awdl_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, AWDL, update_index, + awdl_result.has_error() + ? awdl_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } // wifi lan @@ -1751,12 +1704,10 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( should_start_discovery = true; if (!needs_restart && old_mediums.wifi_lan) { restarted_mediums.push_back(WIFI_LAN); - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, WIFI_LAN, update_index, - OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, WIFI_LAN, update_index, + OperationResultCode::DETAIL_SUCCESS)); } else { ErrorOr wifi_lan_result = StartWifiLanDiscovery(client, std::string(service_id)); @@ -1766,14 +1717,12 @@ P2pClusterPcpHandler::UpdateDiscoveryOptionsImpl( LOG(WARNING) << "UpdateDiscoveryOptionsImpl: unable to restart " "wifi lan scanning"; } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, WIFI_LAN, update_index, - wifi_lan_result.has_error() - ? wifi_lan_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, WIFI_LAN, update_index, + wifi_lan_result.has_error() + ? wifi_lan_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } if (restarted_mediums.empty() && should_start_discovery) { @@ -1946,8 +1895,7 @@ void P2pClusterPcpHandler::StartBluetoothDiscoveryWithPause( ClientProxy* client, const std::string& service_id, const DiscoveryOptions& discovery_options, std::vector& mediums_started_successfully, - std::vector& - operation_result_with_mediums, + std::vector& operation_result_with_mediums, int update_index) { if (bluetooth_radio_.IsEnabled()) { if (ble_medium_.IsExtendedAdvertisementsAvailable() && @@ -1965,16 +1913,12 @@ void P2pClusterPcpHandler::StartBluetoothDiscoveryWithPause( bluetooth_classic_client_id_to_service_id_map_.insert( {client->GetClientId(), service_id}); } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLUETOOTH, update_index, - bluetooth_result.has_error() - ? bluetooth_result.error() - .operation_result_code() - .value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLUETOOTH, update_index, + bluetooth_result.has_error() + ? bluetooth_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } else { LOG(INFO) << "Pause bluetooth discovery for service id : " << service_id; @@ -1992,14 +1936,12 @@ void P2pClusterPcpHandler::StartBluetoothDiscoveryWithPause( bluetooth_classic_client_id_to_service_id_map_.insert( {client->GetClientId(), service_id}); } - std::unique_ptr - operation_result_with_medium = - GetOperationResultWithMediumByResultCode( - client, BLUETOOTH, update_index, - bluetooth_result.has_error() - ? bluetooth_result.error().operation_result_code().value() - : OperationResultCode::DETAIL_SUCCESS); - operation_result_with_mediums.push_back(*operation_result_with_medium); + operation_result_with_mediums.push_back( + GetOperationResultWithMediumByResultCode( + client, BLUETOOTH, update_index, + bluetooth_result.has_error() + ? bluetooth_result.error().operation_result_code().value() + : OperationResultCode::DETAIL_SUCCESS)); } } else { LOG(WARNING) << "Ignore to discover on bluetooth for service id: " @@ -2015,9 +1957,10 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl( << endpoint->endpoint_id << ") over Bluetooth Classic."; BluetoothDevice& device = endpoint->bluetooth_device; + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint->endpoint_id); ErrorOr bluetooth_socket_result = bluetooth_medium_.Connect( - device, endpoint->service_id, - client->GetCancellationFlag(endpoint->endpoint_id)); + device, endpoint->service_id, cancellation_flag.get()); if (bluetooth_socket_result.has_error()) { LOG(ERROR) << "In BluetoothConnectImpl(), failed to connect to Bluetooth device " @@ -2386,15 +2329,17 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( << " is attempting to connect to (" << peripheral.ToReadableString() << ") over BLE."; + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint->endpoint_id); + if (NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature::kEnableBleL2cap) && peripheral.GetPsm() != mediums::BleAdvertisementHeader::kDefaultPsmValue) { if (refactor_ble_l2cap) { ErrorOr> ble_l2cap_socket_result = - ble_medium_.ConnectOverL2cap2( - endpoint->service_id, peripheral, - client->GetCancellationFlag(endpoint->endpoint_id)); + ble_medium_.ConnectOverL2cap2(endpoint->service_id, peripheral, + cancellation_flag.get()); if (!ble_l2cap_socket_result.has_error()) { LOG(INFO) << "In BleV2ConnectImpl(), connected to Ble L2CAP device " << absl::BytesToHexString(peripheral.GetId().data()) @@ -2416,9 +2361,8 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( } } else { ErrorOr ble_l2cap_socket_result = - ble_medium_.ConnectOverL2cap( - endpoint->service_id, peripheral, - client->GetCancellationFlag(endpoint->endpoint_id)); + ble_medium_.ConnectOverL2cap(endpoint->service_id, peripheral, + cancellation_flag.get()); if (!ble_l2cap_socket_result.has_error()) { LOG(INFO) << "In BleConnectImpl(), connected to Ble L2CAP device " << absl::BytesToHexString(peripheral.GetId().data()) @@ -2444,9 +2388,8 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( std::unique_ptr channel = nullptr; if (refactor_ble_l2cap) { ErrorOr> ble_socket_result = - ble_medium_.Connect2( - endpoint->service_id, peripheral, - client->GetCancellationFlag(endpoint->endpoint_id)); + ble_medium_.Connect2(endpoint->service_id, peripheral, + cancellation_flag.get()); if (ble_socket_result.has_error()) { LOG(ERROR) << "In BleConnectImpl(), failed to connect to BLE device " << absl::BytesToHexString(peripheral.GetId().data()) @@ -2461,9 +2404,8 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl( endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, std::move(ble_socket_result.value())); } else { - ErrorOr ble_socket_result = - ble_medium_.Connect(endpoint->service_id, peripheral, - client->GetCancellationFlag(endpoint->endpoint_id)); + ErrorOr ble_socket_result = ble_medium_.Connect( + endpoint->service_id, peripheral, cancellation_flag.get()); if (ble_socket_result.has_error()) { LOG(ERROR) << "In BleConnectImpl(), failed to connect to BLE device " << absl::BytesToHexString(peripheral.GetId().data()) @@ -2737,9 +2679,10 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::AwdlConnectImpl( LOG(INFO) << "Client " << client->GetClientId() << " is attempting to connect to endpoint(id=" << endpoint->endpoint_id << ") over Awdl."; - ErrorOr socket_result = - awdl_medium_.Connect(endpoint->service_id, endpoint->service_info, - client->GetCancellationFlag(endpoint->endpoint_id)); + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint->endpoint_id); + ErrorOr socket_result = awdl_medium_.Connect( + endpoint->service_id, endpoint->service_info, cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "In AwdlConnectImpl(), failed to connect to service " << endpoint->service_info.GetServiceName() @@ -2773,9 +2716,10 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( LOG(INFO) << "Client " << client->GetClientId() << " is attempting to connect to endpoint(id=" << endpoint->endpoint_id << ") over WifiLan."; + std::shared_ptr cancellation_flag = + client->GetCancellationFlag(endpoint->endpoint_id); ErrorOr socket_result = wifi_lan_medium_.Connect( - endpoint->service_id, endpoint->service_info, - client->GetCancellationFlag(endpoint->endpoint_id)); + endpoint->service_id, endpoint->service_info, cancellation_flag.get()); if (socket_result.has_error()) { LOG(ERROR) << "In WifiLanConnectImpl(), failed to connect to service " << endpoint->service_info.GetServiceName() diff --git a/connections/implementation/p2p_cluster_pcp_handler.h b/connections/implementation/p2p_cluster_pcp_handler.h index a3ac0891..d5d2c345 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.h +++ b/connections/implementation/p2p_cluster_pcp_handler.h @@ -25,6 +25,7 @@ #include "absl/strings/string_view.h" #include "connections/advertising_options.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/operation_result_with_medium.h" #include "connections/implementation/base_pcp_handler.h" #include "connections/implementation/ble_advertisement.h" #include "connections/implementation/bluetooth_device_name.h" @@ -55,12 +56,7 @@ #include "internal/platform/bluetooth_classic.h" #include "internal/platform/nsd_service_info.h" #include "internal/platform/wifi_lan.h" -#ifdef NO_WEBRTC -#include "connections/implementation/mediums/webrtc_socket_stub.h" -#include "connections/implementation/mediums/webrtc_stub.h" -#else #include "connections/implementation/mediums/webrtc.h" -#endif #include "connections/implementation/pcp.h" #include "connections/implementation/wifi_lan_service_info.h" #include "internal/platform/byte_array.h" @@ -212,8 +208,8 @@ class P2pClusterPcpHandler : public BasePcpHandler { ClientProxy* client, const std::string& service_id, const DiscoveryOptions& discovery_options, std::vector& mediums_started_successfully, - std::vector& operation_result_with_mediums, + std::vector& + operation_result_with_mediums, int update_index); BasePcpHandler::ConnectImplResult BluetoothConnectImpl( ClientProxy* client, BluetoothEndpoint* endpoint); diff --git a/connections/implementation/p2p_cluster_pcp_handler_test.cc b/connections/implementation/p2p_cluster_pcp_handler_test.cc index 956856a7..5f6c813e 100644 --- a/connections/implementation/p2p_cluster_pcp_handler_test.cc +++ b/connections/implementation/p2p_cluster_pcp_handler_test.cc @@ -88,11 +88,15 @@ class P2pClusterPcpHandlerTest : public testing::Test { LOG(INFO) << "SetUp: begin"; NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature::kEnableAwdl, true); - SetBleExtendedAdvertisementsAvailable(true); + SetBleExtendedAdvertisementsAvailable(false); + } + + void TearDown() override { + NearbyFlags::GetInstance().ResetOverridedValues(); } void SetBleExtendedAdvertisementsAvailable(bool available) { - env_.SetBleExtendedAdvertisementsAvailable(false); + env_.SetBleExtendedAdvertisementsAvailable(available); } AdvertisingOptions GetBluetoothOnlyAdvertisingOptions() { @@ -141,6 +145,8 @@ class P2pClusterPcpHandlerTest : public testing::Test { return ByteArray(reinterpret_cast(bytes), 6); } + void RunCanConnectHelper(BooleanMediumSelector selector); + ClientProxy client_a_; ClientProxy client_b_; ClientProxy client_c_; @@ -148,6 +154,130 @@ class P2pClusterPcpHandlerTest : public testing::Test { MediumEnvironment& env_{MediumEnvironment::Instance()}; }; +void P2pClusterPcpHandlerTest::RunCanConnectHelper( + BooleanMediumSelector selector) { + env_.Start(); + std::string endpoint_name_a{"endpoint_name"}; + Mediums mediums_a; + Mediums mediums_b; + BluetoothRadio& radio_a = mediums_a.GetBluetoothRadio(); + BluetoothRadio& radio_b = mediums_b.GetBluetoothRadio(); + radio_a.GetBluetoothAdapter().SetName("BT Device A"); + radio_b.GetBluetoothAdapter().SetName("BT Device B"); + EndpointChannelManager ecm_a; + EndpointChannelManager ecm_b; + EndpointManager em_a(&ecm_a); + EndpointManager em_b(&ecm_b); + BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, + {.allow_upgrade_to = {.bluetooth = true}}); + BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, + {.allow_upgrade_to = {.bluetooth = true}}); + InjectedBluetoothDeviceStore ibds_a; + InjectedBluetoothDeviceStore ibds_b; + P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); + P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b, ibds_b); + CountDownLatch discover_latch(1); + CountDownLatch connect_latch(2); + struct DiscoveredInfo { + std::string endpoint_id; + ByteArray endpoint_info; + std::string service_id; + } discovered; + + // Build options locally using passed selector! + AdvertisingOptions advertising_options = {{Strategy::kP2pCluster, selector}}; + DiscoveryOptions discovery_options = {{Strategy::kP2pCluster, selector}}; + ConnectionOptions connection_options = {{Strategy::kP2pCluster, selector}}; + + EXPECT_EQ( + handler_a.StartAdvertising( + &client_a_, service_id_, advertising_options, + { + .endpoint_info = ByteArray{endpoint_name_a}, + .listener = + { + .initiated_cb = + [&connect_latch](const std::string& endpoint_id, + const ConnectionResponseInfo& info) { + LOG(INFO) + << "StartAdvertising: initiated_cb called"; + connect_latch.CountDown(); + }, + }, + }), + Status{Status::kSuccess}); + EXPECT_EQ(handler_b.StartDiscovery( + &client_b_, service_id_, discovery_options, + { + .endpoint_found_cb = + [&discover_latch, &discovered]( + const std::string& endpoint_id, + const ByteArray& endpoint_info, + const std::string& service_id) { + LOG(INFO) << "Device discovered: id=" << endpoint_id + << ", endpoint_info=" + << std::string{endpoint_info}; + discovered = { + .endpoint_id = endpoint_id, + .endpoint_info = endpoint_info, + .service_id = service_id, + }; + discover_latch.CountDown(); + }, + }), + Status{Status::kSuccess}); + + EXPECT_TRUE(discover_latch.Await(absl::Milliseconds(1000)).result()); + EXPECT_EQ(endpoint_name_a, std::string{discovered.endpoint_info}); + + const std::string kBssid = "34:36:3B:C7:8C:71"; + const std::int32_t kFreq = 5200; + + connection_options.connection_info.supports_5_ghz = true; + connection_options.connection_info.bssid = kBssid; + connection_options.connection_info.ap_frequency = kFreq; + + client_b_.AddCancellationFlag(discovered.endpoint_id); + handler_b.RequestConnection( + &client_b_, discovered.endpoint_id, + {.endpoint_info = discovered.endpoint_info, + .listener = + { + .initiated_cb = + [&connect_latch](const std::string& endpoint_id, + const ConnectionResponseInfo& info) { + LOG(INFO) << "RequestConnection: initiated_cb called"; + connect_latch.CountDown(); + }, + }}, + connection_options); + std::string client_b_local_endpoint = client_b_.GetLocalEndpointId(); + + EXPECT_TRUE(connect_latch.Await(absl::Milliseconds(1000)).result()); + EXPECT_TRUE(client_b_.Is5GHzSupported(discovered.endpoint_id)); + EXPECT_EQ(client_b_.GetBssid(discovered.endpoint_id), kBssid); + EXPECT_EQ(client_b_.GetApFrequency(discovered.endpoint_id), kFreq); + // When connection is established, EndpointManager will setup KeepAliveManager + // loop. When it fails, the connection will be dismantled. Since this a unit + // test, KeepAliveManager won't be really up. The disconnection may happen + // before the following check, which cause the check fail. So we check the + // connection status first. + if (client_b_.IsConnectedToEndpoint(discovered.endpoint_id)) { + EXPECT_EQ(client_a_.Is5GHzSupported(client_b_local_endpoint), + mediums_b.GetWifi().GetCapability().supports_5_ghz); + EXPECT_EQ(client_a_.GetBssid(client_b_local_endpoint), + mediums_b.GetWifi().GetInformation().bssid); + EXPECT_EQ(client_a_.GetApFrequency(client_b_local_endpoint), + mediums_b.GetWifi().GetInformation().ap_frequency); + } + + handler_a.StopAdvertising(&client_a_); + handler_b.StopDiscovery(&client_b_); + bwu_a.Shutdown(); + bwu_b.Shutdown(); + env_.Stop(); +} + TEST_F(P2pClusterPcpHandlerTest, NoBluetoothDiscoveryWhenRadioIsOff) { env_.Start(); Mediums mediums; @@ -231,7 +361,8 @@ TEST_F(P2pClusterPcpHandlerTest, } class P2pClusterPcpHandlerTestWithParam - : public testing::TestWithParam { + : public P2pClusterPcpHandlerTest, + public ::testing::WithParamInterface { protected: void SetUp() override { LOG(INFO) << "SetUp: begin"; @@ -264,9 +395,6 @@ class P2pClusterPcpHandlerTestWithParam LOG(INFO) << "SetUp: end"; } - ClientProxy client_a_; - ClientProxy client_b_; - std::string service_id_{"service"}; ConnectionOptions connection_options_{ { Strategy::kP2pCluster, @@ -285,7 +413,6 @@ class P2pClusterPcpHandlerTestWithParam GetParam(), }, }; - MediumEnvironment& env_{MediumEnvironment::Instance()}; }; TEST_P(P2pClusterPcpHandlerTestWithParam, CanConstructOne) { @@ -900,128 +1027,21 @@ TEST_P(P2pClusterPcpHandlerTestWithParam, } TEST_P(P2pClusterPcpHandlerTestWithParam, CanConnect) { - env_.Start(); - std::string endpoint_name_a{"endpoint_name"}; - Mediums mediums_a; - Mediums mediums_b; - BluetoothRadio& radio_a = mediums_a.GetBluetoothRadio(); - BluetoothRadio& radio_b = mediums_b.GetBluetoothRadio(); - radio_a.GetBluetoothAdapter().SetName("BT Device A"); - radio_b.GetBluetoothAdapter().SetName("BT Device B"); - EndpointChannelManager ecm_a; - EndpointChannelManager ecm_b; - EndpointManager em_a(&ecm_a); - EndpointManager em_b(&ecm_b); - BwuManager bwu_a(mediums_a, em_a, ecm_a, {}, - {.allow_upgrade_to = {.bluetooth = true}}); - BwuManager bwu_b(mediums_b, em_b, ecm_b, {}, - {.allow_upgrade_to = {.bluetooth = true}}); - InjectedBluetoothDeviceStore ibds_a; - InjectedBluetoothDeviceStore ibds_b; - P2pClusterPcpHandler handler_a(&mediums_a, &em_a, &ecm_a, &bwu_a, ibds_a); - P2pClusterPcpHandler handler_b(&mediums_b, &em_b, &ecm_b, &bwu_b, ibds_b); - CountDownLatch discover_latch(1); - CountDownLatch connect_latch(2); - struct DiscoveredInfo { - std::string endpoint_id; - ByteArray endpoint_info; - std::string service_id; - } discovered; - EXPECT_EQ( - handler_a.StartAdvertising( - &client_a_, service_id_, advertising_options_, - { - .endpoint_info = ByteArray{endpoint_name_a}, - .listener = - { - .initiated_cb = - [&connect_latch](const std::string& endpoint_id, - const ConnectionResponseInfo& info) { - LOG(INFO) - << "StartAdvertising: initiated_cb called"; - connect_latch.CountDown(); - }, - }, - }), - Status{Status::kSuccess}); - EXPECT_EQ(handler_b.StartDiscovery( - &client_b_, service_id_, discovery_options_, - { - .endpoint_found_cb = - [&discover_latch, &discovered]( - const std::string& endpoint_id, - const ByteArray& endpoint_info, - const std::string& service_id) { - LOG(INFO) << "Device discovered: id=" << endpoint_id - << ", endpoint_info=" - << std::string{endpoint_info}; - discovered = { - .endpoint_id = endpoint_id, - .endpoint_info = endpoint_info, - .service_id = service_id, - }; - discover_latch.CountDown(); - }, - }), - Status{Status::kSuccess}); - - EXPECT_TRUE(discover_latch.Await(absl::Milliseconds(1000)).result()); - EXPECT_EQ(endpoint_name_a, std::string{discovered.endpoint_info}); - - const std::string kBssid = "34:36:3B:C7:8C:71"; - const std::int32_t kFreq = 5200; - - connection_options_.connection_info.supports_5_ghz = true; - connection_options_.connection_info.bssid = kBssid; - connection_options_.connection_info.ap_frequency = kFreq; - - client_b_.AddCancellationFlag(discovered.endpoint_id); - handler_b.RequestConnection( - &client_b_, discovered.endpoint_id, - {.endpoint_info = discovered.endpoint_info, - .listener = - { - .initiated_cb = - [&connect_latch](const std::string& endpoint_id, - const ConnectionResponseInfo& info) { - LOG(INFO) << "RequestConnection: initiated_cb called"; - connect_latch.CountDown(); - }, - }}, - connection_options_); - std::string client_b_local_endpoint = client_b_.GetLocalEndpointId(); - - EXPECT_TRUE(connect_latch.Await(absl::Milliseconds(1000)).result()); - EXPECT_TRUE(client_b_.Is5GHzSupported(discovered.endpoint_id)); - EXPECT_EQ(client_b_.GetBssid(discovered.endpoint_id), kBssid); - EXPECT_EQ(client_b_.GetApFrequency(discovered.endpoint_id), kFreq); - // When connection is established, EndpointManager will setup KeepAliveManager - // loop. When it fails, the connection will be dismantled. Since this a unit - // test, KeepAliveManager won't be really up. The disconnection may happen - // before the following check, which cause the check fail. So we check the - // connection status first. - if (client_b_.IsConnectedToEndpoint(discovered.endpoint_id)) { - EXPECT_EQ(client_a_.Is5GHzSupported(client_b_local_endpoint), - mediums_b.GetWifi().GetCapability().supports_5_ghz); - EXPECT_EQ(client_a_.GetBssid(client_b_local_endpoint), - mediums_b.GetWifi().GetInformation().bssid); - EXPECT_EQ(client_a_.GetApFrequency(client_b_local_endpoint), - mediums_b.GetWifi().GetInformation().ap_frequency); - } - - handler_a.StopAdvertising(&client_a_); - handler_b.StopDiscovery(&client_b_); - bwu_a.Shutdown(); - bwu_b.Shutdown(); - env_.Stop(); + RunCanConnectHelper(GetParam()); } TEST_P(P2pClusterPcpHandlerTestWithParam, CanConnectWithDctEnabled) { env_.Start(); + // DCT advertisement truncates the device name to 7 bytes. + // "Test device" (11 bytes) -> "Test de" (7 bytes). + // The endpoint info is constructed by advertisements::BuildEndpointInfo which + // adds some overhead. + // For DCT, it seems to be 18 bytes prefix + truncated device name. + // 18 + 7 = 25 bytes. ByteArray endpoint_info_a{ - "\x22\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b" - "\x54\x65\x73\x74\x20\x64\x65\x76\x69\x63\x65", - 29}; + "\x22\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x07" + "Test de", + 25}; ClientProxy client_a; ClientProxy client_b; @@ -1783,5 +1803,47 @@ INSTANTIATE_TEST_SUITE_P(ParametrisedPcpHandlerTest, P2pClusterPcpHandlerTestWithParam, ::testing::ValuesIn(kTestCases)); +TEST_F(P2pClusterPcpHandlerTest, BleConnect_L2cap_Refactor) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableBleL2cap, true); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + true); + + RunCanConnectHelper({.ble = true}); +} + +TEST_F(P2pClusterPcpHandlerTest, BleConnect_NoL2cap_Refactor) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableBleL2cap, + false); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + true); + + RunCanConnectHelper({.ble = true}); +} + +TEST_F(P2pClusterPcpHandlerTest, BleConnect_NoL2cap_NoRefactor) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableBleL2cap, + false); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + false); + + RunCanConnectHelper({.ble = true}); +} + +TEST_F(P2pClusterPcpHandlerTest, BleConnect_L2cap_NoRefactor) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kEnableBleL2cap, true); + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + false); + + RunCanConnectHelper({.ble = true}); +} + } // namespace } // namespace nearby::connections diff --git a/connections/implementation/payload_manager.cc b/connections/implementation/payload_manager.cc index 6864f312..6f652329 100644 --- a/connections/implementation/payload_manager.cc +++ b/connections/implementation/payload_manager.cc @@ -29,15 +29,13 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/time/time.h" -#include "connections/implementation/analytics/packet_meta_data.h" -#include "connections/implementation/analytics/throughput_recorder.h" +#include "connections/implementation/analytics/analytics_recorder.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_channel_manager.h" #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/internal_payload.h" #include "connections/implementation/internal_payload_factory.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" #include "connections/listeners.h" #include "connections/medium_selector.h" #include "connections/payload.h" @@ -53,7 +51,6 @@ #include "internal/platform/logging.h" #include "internal/platform/mutex_lock.h" #include "internal/platform/single_thread_executor.h" -#include "proto/connections_enums.pb.h" namespace nearby { namespace connections { @@ -65,9 +62,7 @@ using ::location::nearby::connections::V1Frame; using ::location::nearby::proto::connections::Medium; using ::location::nearby::proto::connections::OperationResultCode; using ::location::nearby::proto::connections::PayloadStatus; -using PacketMetaData = ::nearby::analytics::PacketMetaData; -using ::nearby::analytics::ThroughputRecorderContainer; -using PayloadDirection = ::nearby::connections::PayloadDirection; +using ::nearby::analytics::AnalyticsRecorder; constexpr absl::Duration kMinTransferUpdateInterval = absl::Milliseconds(50); } // namespace @@ -81,7 +76,6 @@ bool PayloadManager::SendPayloadLoop( const EndpointIds& available_endpoint_ids = EndpointsToEndpointIds(pair.first); const Endpoints& unavailable_endpoints = pair.second; - PacketMetaData packet_meta_data; // First, handle any non-available endpoints. for (const auto& endpoint : unavailable_endpoints) { @@ -143,10 +137,8 @@ bool PayloadManager::SendPayloadLoop( // This will block if there is no data to transfer. // It will resume when new data arrives, or if Close() is called. int chunk_size = GetOptimalChunkSize(available_endpoint_ids); - packet_meta_data.StartFileIo(); ByteArray next_chunk = pending_payload.GetInternalPayload()->DetachNextChunk(chunk_size); - packet_meta_data.StopFileIo(); if (shutdown_.Get()) return false; // Save chunk size. We'll need it after we move next_chunk. auto next_chunk_size = next_chunk.size(); @@ -169,7 +161,7 @@ bool PayloadManager::SendPayloadLoop( PayloadTransferFrame::PayloadChunk payload_chunk(CreatePayloadChunk( next_chunk_offset - resume_offset, std::move(next_chunk), index)); const EndpointIds& failed_endpoint_ids = endpoint_manager_->SendPayloadChunk( - payload_header, payload_chunk, available_endpoint_ids, packet_meta_data); + payload_header, payload_chunk, available_endpoint_ids); // Check whether at least one endpoint failed. if (!failed_endpoint_ids.empty()) { VLOG(1) << "Payload xfer: endpoints failed: payload_id=" @@ -213,10 +205,6 @@ bool PayloadManager::SendPayloadLoop( VLOG(1) << "Payload xfer done: payload_id=" << pending_payload.GetInternalPayload()->GetId() << "; size=" << next_chunk_offset; - ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(pending_payload.GetInternalPayload()->GetId(), - PayloadDirection::OUTGOING_PAYLOAD) - ->MarkAsSuccess(); return false; } } @@ -368,7 +356,6 @@ void PayloadManager::DisconnectFromEndpointManager() { PayloadManager::~PayloadManager() { VLOG(1) << "PayloadManager: going down; self=" << this; - ThroughputRecorderContainer::GetInstance().Shutdown(); DisconnectFromEndpointManager(); CancelAllPayloads(); VLOG(1) << "PayloadManager: turn down payload executors; self=" << this; @@ -485,9 +472,6 @@ void PayloadManager::SendPayload(ClientProxy* client, std::int64_t next_chunk_offset = 0; int index = 0; - ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(payload_id, PayloadDirection::OUTGOING_PAYLOAD) - ->Start(payload_type, PayloadDirection::OUTGOING_PAYLOAD); while (should_continue && !shutdown_.Get()) { should_continue = SendPayloadLoop(client, *pending_payload, payload_header, @@ -535,8 +519,7 @@ Status PayloadManager::CancelPayload(ClientProxy* client, void PayloadManager::OnIncomingFrame(OfflineFrame& offline_frame, const std::string& from_endpoint_id, ClientProxy* to_client, - Medium current_medium, - PacketMetaData& packet_meta_data) { + Medium current_medium) { PayloadTransferFrame& frame = *offline_frame.mutable_v1()->mutable_payload_transfer(); @@ -567,8 +550,7 @@ void PayloadManager::OnIncomingFrame(OfflineFrame& offline_frame, ProcessControlPacket(to_client, from_endpoint_id, frame); break; case PayloadTransferFrame::DATA: - ProcessDataPacket(to_client, from_endpoint_id, frame, current_medium, - packet_meta_data); + ProcessDataPacket(to_client, from_endpoint_id, frame, current_medium); break; case PayloadTransferFrame::PAYLOAD_ACK: VLOG(1) << "[safe-to-disconnect][PAYLOAD_RECEIVED_ACK] sender " @@ -641,9 +623,8 @@ void PayloadManager::OnEndpointDisconnect(ClientProxy* client, default: payload_status = PayloadStatus::ENDPOINT_IO_ERROR; operation_result_code = - client->GetAnalyticsRecorder() - .GetChannelIoErrorResultCodeFromMedium( - client->GetConnectedMedium(endpoint_id)); + AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium( + client->GetConnectedMedium(endpoint_id)); break; } @@ -819,10 +800,6 @@ PayloadManager::CreateIncomingPayload(const PayloadTransferFrame& frame, void PayloadManager::OnPendingPayloadDestroy(const PendingPayload* payload) { VLOG(1) << "PayloadManager: destroying " << payload->ToString() << " self=" << this; - ThroughputRecorderContainer::GetInstance().StopTPRecorder( - payload->GetId(), payload->IsIncoming() - ? PayloadDirection::INCOMING_PAYLOAD - : PayloadDirection::OUTGOING_PAYLOAD); if (payload->IsIncoming()) return; RunOnStatusUpdateThread( "~PendingPayload", @@ -864,9 +841,8 @@ void PayloadManager::SendClientCallbacksForFinishedOutgoingPayload( endpoint_id, payload_header.id(), status, (operation_result_code == OperationResultCode::DETAIL_UNKNOWN && status == PayloadStatus::ENDPOINT_IO_ERROR) - ? client->GetAnalyticsRecorder() - .GetChannelIoErrorResultCodeFromMedium( - client->GetConnectedMedium(endpoint_id)) + ? AnalyticsRecorder::GetChannelIoErrorResultCodeFromMedium( + client->GetConnectedMedium(endpoint_id)) : operation_result_code); } @@ -1127,9 +1103,7 @@ void PayloadManager::HandleSuccessfulOutgoingChunk( const PayloadTransferFrame::PayloadHeader& payload_header, std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, std::int64_t payload_chunk_body_size) { - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnablePayloadManagerToSkipChunkUpdate)) { + { MutexLock lock(&chunk_update_mutex_); ++outgoing_chunk_update_count_; } @@ -1144,9 +1118,7 @@ void PayloadManager::HandleSuccessfulOutgoingChunk( (payload_chunk_flags & PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnablePayloadManagerToSkipChunkUpdate)) { + { MutexLock lock(&chunk_update_mutex_); --outgoing_chunk_update_count_; if (payload_header.has_type() && @@ -1226,9 +1198,7 @@ void PayloadManager::HandleSuccessfulIncomingChunk( const PayloadTransferFrame::PayloadHeader& payload_header, std::int32_t payload_chunk_flags, std::int64_t payload_chunk_offset, std::int64_t payload_chunk_body_size) { - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnablePayloadManagerToSkipChunkUpdate)) { + { MutexLock lock(&chunk_update_mutex_); ++incoming_chunk_update_count_; } @@ -1242,9 +1212,7 @@ void PayloadManager::HandleSuccessfulIncomingChunk( (payload_chunk_flags & PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; - if (NearbyFlags::GetInstance().GetBoolFlag( - config_package_nearby::nearby_connections_feature:: - kEnablePayloadManagerToSkipChunkUpdate)) { + { MutexLock lock(&chunk_update_mutex_); --incoming_chunk_update_count_; if (payload_header.has_type() && @@ -1308,8 +1276,7 @@ void PayloadManager::HandleSuccessfulIncomingChunk( // @EndpointManagerDataPool void PayloadManager::ProcessDataPacket( ClientProxy* to_client, const std::string& from_endpoint_id, - PayloadTransferFrame& payload_transfer_frame, Medium medium, - PacketMetaData& packet_meta_data) { + PayloadTransferFrame& payload_transfer_frame, Medium medium) { PayloadTransferFrame::PayloadHeader& payload_header = *payload_transfer_frame.mutable_payload_header(); PayloadTransferFrame::PayloadChunk& payload_chunk = @@ -1330,11 +1297,6 @@ void PayloadManager::ProcessDataPacket( Payload::Id payload_id = payload_header.id(); PendingPayloadHandle pending_payload; if (payload_chunk.offset() == 0) { - ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(payload_id, PayloadDirection::INCOMING_PAYLOAD) - ->Start((PayloadType)payload_header.type(), - PayloadDirection::INCOMING_PAYLOAD); - packet_meta_data.Reset(); RunOnStatusUpdateThread( "process-data-packet", [to_client, from_endpoint_id, payload_header, this]() RUN_ON_PAYLOAD_STATUS_UPDATE_THREAD() { @@ -1421,7 +1383,6 @@ void PayloadManager::ProcessDataPacket( // Save size of packet before we move it. std::int64_t payload_body_size = payload_chunk.body().size(); - packet_meta_data.StartFileIo(); if (pending_payload->GetInternalPayload() ->AttachNextChunk(payload_chunk.body()) .Raised()) { @@ -1433,7 +1394,6 @@ void PayloadManager::ProcessDataPacket( PayloadStatus::LOCAL_ERROR, OperationResultCode::IO_FILE_WRITING_ERROR); return; } - packet_meta_data.StopFileIo(); bool is_last_chunk = (payload_chunk.flags() & PayloadTransferFrame::PayloadChunk::LAST_CHUNK) != 0; SendPayloadReceivedAck(to_client, *pending_payload, from_endpoint_id, @@ -1442,15 +1402,6 @@ void PayloadManager::ProcessDataPacket( HandleSuccessfulIncomingChunk(to_client, from_endpoint_id, payload_header, payload_chunk.flags(), payload_chunk.offset(), payload_body_size); - - ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(payload_header.id(), PayloadDirection::INCOMING_PAYLOAD) - ->OnFrameReceived(medium, packet_meta_data); - if (is_last_chunk) { - ThroughputRecorderContainer::GetInstance() - .GetTPRecorder(payload_header.id(), PayloadDirection::INCOMING_PAYLOAD) - ->MarkAsSuccess(); - } } // @EndpointManagerDataPool diff --git a/connections/implementation/payload_manager.h b/connections/implementation/payload_manager.h index 4ba438c5..533ee79d 100644 --- a/connections/implementation/payload_manager.h +++ b/connections/implementation/payload_manager.h @@ -26,7 +26,6 @@ #include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" #include "absl/time/time.h" -#include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/endpoint_manager.h" #include "connections/implementation/internal_payload.h" @@ -67,8 +66,7 @@ class PayloadManager : public EndpointManager::FrameProcessor { void OnIncomingFrame( location::nearby::connections::OfflineFrame& offline_frame, const std::string& from_endpoint_id, ClientProxy* to_client, - location::nearby::proto::connections::Medium current_medium, - analytics::PacketMetaData& packet_meta_data) override; + location::nearby::proto::connections::Medium current_medium) override; // @EndpointManagerThread void OnEndpointDisconnect( @@ -412,8 +410,7 @@ class PayloadManager : public EndpointManager::FrameProcessor { const std::string& from_endpoint_id, location::nearby::connections::PayloadTransferFrame& payload_transfer_frame, - location::nearby::proto::connections::Medium medium, - analytics::PacketMetaData& packet_meta_data); + location::nearby::proto::connections::Medium medium); void ProcessControlPacket(ClientProxy* to_client, const std::string& from_endpoint_id, location::nearby::connections::PayloadTransferFrame& diff --git a/connections/implementation/payload_manager_test.cc b/connections/implementation/payload_manager_test.cc index 6605112c..bcffb773 100644 --- a/connections/implementation/payload_manager_test.cc +++ b/connections/implementation/payload_manager_test.cc @@ -21,7 +21,6 @@ #include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "connections/implementation/analytics/packet_meta_data.h" #include "connections/implementation/offline_frames.h" #include "connections/implementation/simulation_user.h" #include "connections/listeners.h" @@ -43,7 +42,6 @@ namespace { using ::location::nearby::connections::OfflineFrame; using ::location::nearby::connections::PayloadTransferFrame; using ::location::nearby::proto::connections::Medium; -using ::nearby::analytics::PacketMetaData; constexpr size_t kChunkSize = 64 * 1024; constexpr absl::string_view kServiceId = "service-id"; @@ -113,13 +111,11 @@ class PayloadSimulationUser : public SimulationUser { OfflineFrame offline_frame; - ByteArray bytes = parser::ForDataPayloadTransfer(header, chunk); - offline_frame.ParseFromString(std::string(bytes)); - - PacketMetaData packet_meta_data; + std::string bytes = parser::ForDataPayloadTransfer(header, chunk); + offline_frame.ParseFromString(bytes); pm_.OnIncomingFrame(offline_frame, from_payload_id, &client_, - Medium::WIFI_HOTSPOT, packet_meta_data); + Medium::WIFI_HOTSPOT); } Status CancelPayload() { diff --git a/connections/implementation/pcp_manager.cc b/connections/implementation/pcp_manager.cc index eb35652a..b99dec20 100644 --- a/connections/implementation/pcp_manager.cc +++ b/connections/implementation/pcp_manager.cc @@ -122,6 +122,7 @@ PcpManager::StartListeningForIncomingConnections( ClientProxy* client, absl::string_view service_id, v3::ConnectionListener listener, const v3::ConnectionListeningOptions& options) { + if (shutdown_) return {{Status::kOutOfOrderApiCall}, {}}; if (!SetCurrentPcpHandler(options.strategy)) { return {{Status::kError}, {}}; } diff --git a/connections/implementation/service_controller_router.cc b/connections/implementation/service_controller_router.cc index 250296cd..c79ec237 100644 --- a/connections/implementation/service_controller_router.cc +++ b/connections/implementation/service_controller_router.cc @@ -15,30 +15,43 @@ #include "connections/implementation/service_controller_router.h" #include +#include #include #include #include #include +#include #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" +#include "absl/types/span.h" #include "connections/advertising_options.h" +#include "connections/connection_options.h" #include "connections/discovery_options.h" #include "connections/implementation/bwu_manager.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "connections/implementation/offline_service_controller.h" +#include "connections/implementation/service_controller.h" #include "connections/listeners.h" #include "connections/medium_selector.h" +#include "connections/out_of_band_connection_metadata.h" #include "connections/params.h" #include "connections/payload.h" +#include "connections/status.h" #include "connections/v3/bandwidth_info.h" +#include "connections/v3/connection_listening_options.h" #include "connections/v3/connection_result.h" #include "connections/v3/connections_device.h" +#include "connections/v3/listeners.h" #include "connections/v3/listening_result.h" +#include "connections/v3/params.h" #include "internal/flags/nearby_flags.h" +#include "internal/interop/device.h" +#include "internal/platform/byte_array.h" #include "internal/platform/feature_flags.h" #include "internal/platform/logging.h" +#include "internal/platform/runnable.h" namespace nearby { namespace connections { @@ -413,30 +426,35 @@ void ServiceControllerRouter::RequestConnectionV3( // CancellationListener as soon as possible. client->AddCancellationFlag(remote_device.GetEndpointId()); + // v3_info must outlive the serializer task: the v1 ConnectionListener we + // build below is COPIED into ClientProxy::connections_ and its + // disconnected_cb / bandwidth_changed_cb fire long after this task returns. + auto v3_shared = + std::make_shared(std::move(info.listener)); + std::string remote_endpoint_id = remote_device.GetEndpointId(); + RouteToServiceController( "scr-request-connection-v3", - [this, client, &remote_device, v3_info = std::move(info), + [this, client, remote_endpoint_id, v3_shared, + local_endpoint_info = + (info.local_device.GetType() == + NearbyDevice::Type::kConnectionsDevice) + ? reinterpret_cast(info.local_device) + .GetEndpointInfo() + : "", connection_options, callback = std::move(callback)]() mutable { - std::string endpoint_id = remote_device.GetEndpointId(); + const std::string& endpoint_id = remote_endpoint_id; if (client->HasPendingConnectionToEndpoint(endpoint_id) || client->IsConnectedToEndpoint(endpoint_id)) { callback({Status::kAlreadyConnectedToEndpoint}); return; } - std::string endpoint_info; - if (v3_info.local_device.GetType() == - NearbyDevice::Type::kConnectionsDevice) { - endpoint_info = - reinterpret_cast(v3_info.local_device) - .GetEndpointInfo(); - } - ConnectionListener listener = { .initiated_cb = - [&v3_info, &remote_device]( - const std::string& endpoint_id, - const ConnectionResponseInfo& response_info) mutable { + [v3_shared, endpoint_id]( + const std::string& /*endpoint_id*/, + const ConnectionResponseInfo& response_info) { v3::InitialConnectionInfo new_info = { .authentication_digits = response_info.authentication_token, @@ -447,18 +465,19 @@ void ServiceControllerRouter::RequestConnectionV3( .authentication_status = response_info.authentication_status, }; - v3_info.listener.initiated_cb(remote_device, new_info); + v3_shared->initiated_cb( + v3::ConnectionsDevice(endpoint_id, "", {}), new_info); }, .accepted_cb = - [result_cb = v3_info.listener.result_cb]( - const std::string& endpoint_id) { + [result_cb = + v3_shared->result_cb](const std::string& endpoint_id) { v3::ConnectionResult result = { .status = {Status::kSuccess}, }; result_cb(v3::ConnectionsDevice(endpoint_id, "", {}), result); }, .rejected_cb = - [result_cb = v3_info.listener.result_cb]( + [result_cb = v3_shared->result_cb]( const std::string& endpoint_id, Status status) { v3::ConnectionResult result = { .status = status, @@ -466,28 +485,29 @@ void ServiceControllerRouter::RequestConnectionV3( result_cb(v3::ConnectionsDevice(endpoint_id, "", {}), result); }, .disconnected_cb = - [&v3_info](const std::string& endpoint_id) mutable { + [v3_shared](const std::string& endpoint_id) { auto device = v3::ConnectionsDevice(endpoint_id, "", {}); - v3_info.listener.disconnected_cb(device); + v3_shared->disconnected_cb(device); }, .bandwidth_changed_cb = - [this, &v3_info](const std::string& endpoint_id, - Medium medium) mutable { + [this, v3_shared](const std::string& endpoint_id, + Medium medium) mutable { v3::BandwidthInfo bandwidth_info = { .quality = GetMediumQuality(medium), .medium = medium, }; - v3_info.listener.bandwidth_changed_cb( + v3_shared->bandwidth_changed_cb( v3::ConnectionsDevice(endpoint_id, "", {}), bandwidth_info); }, }; ConnectionRequestInfo old_info = { - .endpoint_info = ByteArray(endpoint_info), + .endpoint_info = ByteArray(local_endpoint_info), .listener = std::move(listener), }; Status status = GetServiceController()->RequestConnectionV3( - client, remote_device, std::move(old_info), connection_options); + client, v3::ConnectionsDevice(endpoint_id, "", {}), + std::move(old_info), connection_options); if (!status.Ok()) { LOG(WARNING) << "Unable to request connection to endpoint " << endpoint_id << ": " << status.ToString(); diff --git a/connections/implementation/simulation_user.h b/connections/implementation/simulation_user.h index 417ab2f8..b257dc0b 100644 --- a/connections/implementation/simulation_user.h +++ b/connections/implementation/simulation_user.h @@ -46,16 +46,13 @@ namespace connections { class SetSafeToDisconnect { public: - explicit SetSafeToDisconnect(bool safe_to_disconnect, bool auto_reconnect, + explicit SetSafeToDisconnect(bool safe_to_disconnect, bool payload_received_ack, std::int32_t safe_to_disconnect_version) { NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnableSafeToDisconnect, safe_to_disconnect); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - config_package_nearby::nearby_connections_feature::kEnableAutoReconnect, - auto_reconnect); NearbyFlags::GetInstance().OverrideBoolFlagValue( config_package_nearby::nearby_connections_feature:: kEnablePayloadReceivedAck, @@ -81,7 +78,7 @@ class SimulationUser { SimulationUser(const std::string& device_name, BooleanMediumSelector allowed = BooleanMediumSelector(), SetSafeToDisconnect set_safe_to_disconnect = - SetSafeToDisconnect(true, false, true, 5)) + SetSafeToDisconnect(true, true, 5)) : info_{ByteArray{device_name}}, advertising_options_{ { diff --git a/connections/implementation/webrtc_bwu_handler.cc b/connections/implementation/webrtc_bwu_handler.cc deleted file mode 100644 index 6f1d07ce..00000000 --- a/connections/implementation/webrtc_bwu_handler.cc +++ /dev/null @@ -1,183 +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 NO_WEBRTC - -#include "connections/implementation/webrtc_bwu_handler.h" - -#include -#include -#include - -#include "absl/functional/bind_front.h" -#include "connections/implementation/base_bwu_handler.h" -#include "connections/implementation/client_proxy.h" -#include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" -#include "connections/implementation/mediums/webrtc_peer_id.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "connections/implementation/offline_frames.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" -#include "connections/implementation/webrtc_endpoint_channel.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/expected.h" -#include "internal/platform/logging.h" - -namespace nearby { -namespace connections { - -namespace { -using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; -using ::location::nearby::connections::LocationHint; -using ::location::nearby::connections::LocationStandard; -using ::location::nearby::proto::connections::OperationResultCode; - -LocationHint BuildLocationHint(const std::string& location) { - LocationHint location_hint; - location_hint.set_format(LocationStandard::UNKNOWN); - - if (!location.empty()) { - location_hint.set_location(location); - if (location.at(0) == '+') { - location_hint.set_format(LocationStandard::E164_CALLING); - } else { - location_hint.set_format(LocationStandard::ISO_3166_1_ALPHA_2); - } - } - return location_hint; -} - -} // namespace - -WebrtcBwuHandler::WebrtcIncomingSocket::WebrtcIncomingSocket( - const std::string& name, mediums::WebRtcSocketWrapper socket) - : name_(name), socket_(socket) {} - -void WebrtcBwuHandler::WebrtcIncomingSocket::Close() { socket_.Close(); } - -std::string WebrtcBwuHandler::WebrtcIncomingSocket::ToString() { return name_; } - -WebrtcBwuHandler::WebrtcBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) - : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} - -// Called by BWU target. Retrieves a new medium info from incoming message, -// and establishes connection over WebRTC using this info. -ErrorOr> -WebrtcBwuHandler::CreateUpgradedEndpointChannel( - ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id, - const BandwidthUpgradeNegotiationFrame::UpgradePathInfo& - upgrade_path_info) { - const BandwidthUpgradeNegotiationFrame::UpgradePathInfo::WebRtcCredentials& - web_rtc_credentials = upgrade_path_info.web_rtc_credentials(); - mediums::WebrtcPeerId peer_id(web_rtc_credentials.peer_id()); - - LocationHint location_hint; - location_hint.set_format(LocationStandard::UNKNOWN); - if (web_rtc_credentials.has_location_hint()) { - location_hint = web_rtc_credentials.location_hint(); - } - LOG(INFO) << "WebRtcBwuHandler is attempting to connect to remote peer " - << peer_id.GetId() << ", location hint " - << location_hint.location(); - - ErrorOr socket_result = webrtc_.Connect( - service_id, peer_id, location_hint, - client->GetCancellationFlag(endpoint_id), client->GetWebRtcNonCellular()); - if (socket_result.has_error()) { - LOG(ERROR) << "WebRtcBwuHandler failed to connect to remote peer (" - << peer_id.GetId() << ") on endpoint " << endpoint_id - << ", aborting upgrade."; - return {Error(socket_result.error().operation_result_code().value())}; - } - - LOG(INFO) << "WebRtcBwuHandler successfully connected to remote " - "peer (" - << peer_id.GetId() << ") while upgrading endpoint " << endpoint_id; - - // Create a new WebRtcEndpointChannel. - auto channel = std::make_unique( - service_id, /*channel_name=*/service_id, socket_result.value()); - if (channel == nullptr) { - socket_result.value().Close(); - LOG(ERROR) << "WebRtcBwuHandler failed to create new EndpointChannel for " - "outgoing socket, aborting upgrade."; - return {Error( - OperationResultCode::NEARBY_WEB_RTC_ENDPOINT_CHANNEL_CREATION_FAILURE)}; - } - - return {std::move(channel)}; -} - -void WebrtcBwuHandler::HandleRevertInitiatorStateForService( - const std::string& upgrade_service_id) { - webrtc_.StopAcceptingConnections(upgrade_service_id); - LOG(INFO) << "WebrtcBwuHandler successfully reverted state for service " - << upgrade_service_id; -} - -// Called by BWU initiator. Set up WebRTC upgraded medium for this endpoint, -// and returns a upgrade path info (PeerId, LocationHint) for remote party to -// perform discovery. -ByteArray WebrtcBwuHandler::HandleInitializeUpgradedMediumForEndpoint( - ClientProxy* client, const std::string& upgrade_service_id, - const std::string& endpoint_id) { - LocationHint location_hint = - BuildLocationHint(webrtc_.GetDefaultCountryCode()); - - mediums::WebrtcPeerId self_id{mediums::WebrtcPeerId::FromRandom()}; - if (!webrtc_.IsAcceptingConnections(upgrade_service_id)) { - if (!webrtc_.StartAcceptingConnections( - upgrade_service_id, self_id, location_hint, - absl::bind_front(&WebrtcBwuHandler::OnIncomingWebrtcConnection, - this, client), - client->GetWebRtcNonCellular())) { - LOG(ERROR) << "WebRtcBwuHandler couldn't initiate the WEB_RTC " - "upgrade for endpoint " - << endpoint_id - << " because it failed to start listening for " - "incoming WebRTC connections."; - return {}; - } - LOG(INFO) << "WebRtcBwuHandler successfully started listening for " - "incoming WebRTC connections while upgrading endpoint " - << endpoint_id; - } - - return parser::ForBwuWebrtcPathAvailable(self_id.GetId(), location_hint); -} - -// Accept Connection Callback. -// Notifies that the remote party called WebRtc::Connect() -// for this socket. -void WebrtcBwuHandler::OnIncomingWebrtcConnection( - ClientProxy* client, const std::string& upgrade_service_id, - mediums::WebRtcSocketWrapper socket) { - auto channel = std::make_unique( - upgrade_service_id, /*channel_name=*/upgrade_service_id, socket); - auto webrtc_socket = - std::make_unique(upgrade_service_id, socket); - std::unique_ptr connection( - new IncomingSocketConnection{std::move(webrtc_socket), - std::move(channel)}); - - NotifyOnIncomingConnection(client, std::move(connection)); -} - -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/webrtc_bwu_handler.h b/connections/implementation/webrtc_bwu_handler.h deleted file mode 100644 index c865420e..00000000 --- a/connections/implementation/webrtc_bwu_handler.h +++ /dev/null @@ -1,91 +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 CORE_INTERNAL_WEBRTC_BWU_HANDLER_H_ -#define CORE_INTERNAL_WEBRTC_BWU_HANDLER_H_ - -#ifndef NO_WEBRTC - -#include -#include - -#include "connections/implementation/base_bwu_handler.h" -#include "connections/implementation/bwu_handler.h" -#include "connections/implementation/client_proxy.h" -#include "connections/implementation/endpoint_channel.h" -#include "connections/implementation/mediums/mediums.h" -#include "connections/implementation/mediums/webrtc.h" -#include "connections/implementation/mediums/webrtc_socket.h" -#include "connections/medium_selector.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/expected.h" - -namespace nearby { -namespace connections { - -// Defines the set of methods that need to be implemented to handle the -// per-Medium-specific operations needed to upgrade an EndpointChannel. -class WebrtcBwuHandler : public BaseBwuHandler { - public: - explicit WebrtcBwuHandler( - Mediums& mediums, - IncomingConnectionCallback incoming_connection_callback); - - private: - class WebrtcIncomingSocket : public BwuHandler::IncomingSocket { - public: - explicit WebrtcIncomingSocket(const std::string& name, - mediums::WebRtcSocketWrapper socket); - - std::string ToString() override; - void Close() override; - - private: - std::string name_; - mediums::WebRtcSocketWrapper socket_; - }; - - // BwuHandler implementation: - ErrorOr> CreateUpgradedEndpointChannel( - ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id, - const location::nearby::connections::BandwidthUpgradeNegotiationFrame:: - UpgradePathInfo& upgrade_path_info) final; - location::nearby::proto::connections::Medium GetUpgradeMedium() const final { - return Medium::WEB_RTC; - } - void OnEndpointDisconnect(ClientProxy* client, - const std::string& endpoint_id) final {} - - // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( - ClientProxy* client, const std::string& upgrade_service_id, - const std::string& endpoint_id) final; - void HandleRevertInitiatorStateForService( - const std::string& upgrade_service_id) final; - - void OnIncomingWebrtcConnection(ClientProxy* client, - const std::string& upgrade_service_id, - mediums::WebRtcSocketWrapper socket); - - Mediums& mediums_; - mediums::WebRtc& webrtc_{mediums_.GetWebRtc()}; -}; - -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_WEBRTC_BWU_HANDLER_H_ diff --git a/connections/implementation/webrtc_bwu_handler_stub.cc b/connections/implementation/webrtc_bwu_handler_stub.cc deleted file mode 100644 index 1b37f9e3..00000000 --- a/connections/implementation/webrtc_bwu_handler_stub.cc +++ /dev/null @@ -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. - -#ifdef NO_WEBRTC - -#include "connections/implementation/webrtc_bwu_handler_stub.h" - -#include -#include - -#include "absl/functional/bind_front.h" -#include "connections/implementation/client_proxy.h" -#include "connections/implementation/mediums/utils.h" -#include "connections/implementation/mediums/webrtc_peer_id_stub.h" -#include "connections/implementation/offline_frames.h" -#include "connections/implementation/webrtc_endpoint_channel.h" -#include "internal/platform/expected.h" - -namespace nearby { -namespace connections { - -namespace { -using ::location::nearby::connections::BandwidthUpgradeNegotiationFrame; -using ::location::nearby::proto::connections::OperationResultCode; -} // namespace - -WebrtcBwuHandler::WebrtcIncomingSocket::WebrtcIncomingSocket( - const std::string& name, mediums::WebRtcSocketWrapper socket) - : name_(name), socket_(socket) {} - -void WebrtcBwuHandler::WebrtcIncomingSocket::Close() {} - -std::string WebrtcBwuHandler::WebrtcIncomingSocket::ToString() { return ""; } - -WebrtcBwuHandler::WebrtcBwuHandler( - Mediums& mediums, IncomingConnectionCallback incoming_connection_callback) - : BaseBwuHandler(std::move(incoming_connection_callback)), - mediums_(mediums) {} - -// Called by BWU target. Retrieves a new medium info from incoming message, -// and establishes connection over WebRTC using this info. -ErrorOr> -WebrtcBwuHandler::CreateUpgradedEndpointChannel( - ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id, - const BandwidthUpgradeNegotiationFrame::UpgradePathInfo& - upgrade_path_info) { - return {Error(OperationResultCode::DETAIL_UNKNOWN)}; -} - -void WebrtcBwuHandler::HandleRevertInitiatorStateForService( - const std::string& upgrade_service_id) {} - -// Called by BWU initiator. Set up WebRTC upgraded medium for this endpoint, -// and returns a upgrade path info (PeerId, LocationHint) for remote party to -// perform discovery. -ByteArray WebrtcBwuHandler::HandleInitializeUpgradedMediumForEndpoint( - ClientProxy* client, const std::string& upgrade_service_id, - const std::string& endpoint_id) { - return {}; -} - -// Accept Connection Callback. -// Notifies that the remote party called WebRtc::Connect() -// for this socket. -void WebrtcBwuHandler::OnIncomingWebrtcConnection( - ClientProxy* client, const std::string& upgrade_service_id, - mediums::WebRtcSocketWrapper socket) {} - -} // namespace connections -} // namespace nearby - -#endif diff --git a/connections/implementation/webrtc_bwu_handler_stub.h b/connections/implementation/webrtc_bwu_handler_stub.h deleted file mode 100644 index f20b4898..00000000 --- a/connections/implementation/webrtc_bwu_handler_stub.h +++ /dev/null @@ -1,90 +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 CORE_INTERNAL_WEBRTC_BWU_HANDLER_STUB_H_ -#define CORE_INTERNAL_WEBRTC_BWU_HANDLER_STUB_H_ - -#ifdef NO_WEBRTC - -#include - -#include "connections/implementation/base_bwu_handler.h" -#include "connections/implementation/client_proxy.h" -#include "connections/implementation/endpoint_channel_manager.h" -#include "connections/implementation/mediums/mediums.h" -#ifdef NO_WEBRTC -#include "connections/implementation/mediums/webrtc_socket_stub.h" -#else -#include "connections/implementation/mediums/webrtc_socket.h" -#endif -#include "internal/platform/expected.h" - -namespace nearby { -namespace connections { - -// Defines the set of methods that need to be implemented to handle the -// per-Medium-specific operations needed to upgrade an EndpointChannel. -class WebrtcBwuHandler : public BaseBwuHandler { - public: - explicit WebrtcBwuHandler( - Mediums& mediums, - IncomingConnectionCallback incoming_connection_callback); - - private: - class WebrtcIncomingSocket : public BwuHandler::IncomingSocket { - public: - explicit WebrtcIncomingSocket(const std::string& name, - mediums::WebRtcSocketWrapper socket); - - std::string ToString() override; - void Close() override; - - private: - std::string name_; - mediums::WebRtcSocketWrapper socket_; - }; - - // BwuHandler implementation: - ErrorOr> CreateUpgradedEndpointChannel( - ClientProxy* client, const std::string& service_id, - const std::string& endpoint_id, - const location::nearby::connections::BandwidthUpgradeNegotiationFrame:: - UpgradePathInfo& upgrade_path_info) final; - location::nearby::proto::connections::Medium GetUpgradeMedium() const final { - return Medium::WEB_RTC; - } - void OnEndpointDisconnect(ClientProxy* client, - const std::string& endpoint_id) final {} - - // BaseBwuHandler implementation: - ByteArray HandleInitializeUpgradedMediumForEndpoint( - ClientProxy* client, const std::string& upgrade_service_id, - const std::string& endpoint_id) final; - void HandleRevertInitiatorStateForService( - const std::string& upgrade_service_id) final; - - void OnIncomingWebrtcConnection(ClientProxy* client, - const std::string& upgrade_service_id, - mediums::WebRtcSocketWrapper socket); - - Mediums& mediums_; - mediums::WebRtc& webrtc_{mediums_.GetWebRtc()}; -}; - -} // namespace connections -} // namespace nearby - -#endif - -#endif // CORE_INTERNAL_WEBRTC_BWU_HANDLER_STUB_H_ diff --git a/connections/implementation/webrtc_endpoint_channel.cc b/connections/implementation/webrtc_endpoint_channel.cc deleted file mode 100644 index b22501bf..00000000 --- a/connections/implementation/webrtc_endpoint_channel.cc +++ /dev/null @@ -1,37 +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 "connections/implementation/webrtc_endpoint_channel.h" - -#include - -namespace nearby { -namespace connections { - -WebRtcEndpointChannel::WebRtcEndpointChannel( - const std::string& service_id, const std::string& channel_name, - mediums::WebRtcSocketWrapper socket) - : BaseEndpointChannel(service_id, channel_name, &socket.GetInputStream(), - &socket.GetOutputStream()), - webrtc_socket_(std::move(socket)) {} - -location::nearby::proto::connections::Medium WebRtcEndpointChannel::GetMedium() - const { - return location::nearby::proto::connections::Medium::WEB_RTC; -} - -void WebRtcEndpointChannel::CloseImpl() { webrtc_socket_.Close(); } - -} // namespace connections -} // namespace nearby diff --git a/connections/implementation/webrtc_endpoint_channel.h b/connections/implementation/webrtc_endpoint_channel.h deleted file mode 100644 index ae0eb551..00000000 --- a/connections/implementation/webrtc_endpoint_channel.h +++ /dev/null @@ -1,47 +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 CORE_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ -#define CORE_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ - -#include - -#include "connections/implementation/base_endpoint_channel.h" -#ifdef NO_WEBRTC -#include "connections/implementation/mediums/webrtc_socket_stub.h" -#else -#include "connections/implementation/mediums/webrtc_socket.h" -#endif - -namespace nearby { -namespace connections { - -class WebRtcEndpointChannel final : public BaseEndpointChannel { - public: - WebRtcEndpointChannel(const std::string& service_id, - const std::string& channel_name, - mediums::WebRtcSocketWrapper webrtc_socket); - - location::nearby::proto::connections::Medium GetMedium() const override; - - private: - void CloseImpl() override; - - mediums::WebRtcSocketWrapper webrtc_socket_; -}; - -} // namespace connections -} // namespace nearby - -#endif // CORE_INTERNAL_WEBRTC_ENDPOINT_CHANNEL_H_ diff --git a/connections/v3/connections_device.cc b/connections/v3/connections_device.cc index 402f5a0a..e32202e6 100644 --- a/connections/v3/connections_device.cc +++ b/connections/v3/connections_device.cc @@ -31,7 +31,7 @@ std::string ConnectionsDevice::ToProtoBytes() const { // Bytes holding the connection info data elements. std::string connection_info_string; for (const auto& connection_info : connection_infos_) { - if (absl::holds_alternative(connection_info)) { + if (absl::holds_alternative(connection_info)) { continue; } if (absl::holds_alternative(connection_info)) { diff --git a/internal/analytics/BUILD b/internal/analytics/BUILD deleted file mode 100644 index 39427317..00000000 --- a/internal/analytics/BUILD +++ /dev/null @@ -1,49 +0,0 @@ -load("@rules_cc//cc:cc_library.bzl", "cc_library") - -licenses(["notice"]) -# 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. - -cc_library( - name = "event_logger", - hdrs = [ - "event_logger.h", - ], - visibility = [ - "//connections:__subpackages__", - "//location/nearby/analytics/cpp:__subpackages__", - "//location/nearby/cpp/experiments:__subpackages__", - "//sharing:__subpackages__", - ], - deps = [ - "//internal/proto/analytics:connections_log_cc_proto", - "//sharing/proto/analytics:sharing_log_cc_proto", - ], -) - -cc_library( - name = "mock_event_logger", - testonly = True, - hdrs = [ - "mock_event_logger.h", - "sharing_log_matchers.h", - ], - compatible_with = ["//buildenv/target:non_prod"], - visibility = ["//visibility:public"], - deps = [ - ":event_logger", - "@com_google_googletest//:gtest_for_library_testonly", - "@com_google_protobuf//:protobuf_lite", - ], -) diff --git a/internal/analytics/event_logger.h b/internal/analytics/event_logger.h deleted file mode 100644 index b360c659..00000000 --- a/internal/analytics/event_logger.h +++ /dev/null @@ -1,41 +0,0 @@ -// 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 NEARBY_ANALYTICS_EVENT_LOGGER_H_ -#define NEARBY_ANALYTICS_EVENT_LOGGER_H_ - -#include "internal/proto/analytics/connections_log.pb.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" - -namespace nearby { -namespace analytics { - -// Allows callers to log the proto collected at the client (e.g. Nearby -// Connections, Nearby Sharing, etc). Callers need to implement the API -// if they want to collect this log. -class EventLogger { - public: - virtual ~EventLogger() = default; - - // Logs the proto details. Might block to do I/O, e.g. upload - // synchronously to some metrics server. - virtual void Log( - const location::nearby::analytics::proto::ConnectionsLog& message) = 0; - virtual void Log(const sharing::analytics::proto::SharingLog& message) = 0; -}; - -} // namespace analytics -} // namespace nearby - -#endif // NEARBY_ANALYTICS_EVENT_LOGGER_H_ diff --git a/internal/analytics/mock_event_logger.h b/internal/analytics/mock_event_logger.h deleted file mode 100644 index 2a6b5774..00000000 --- a/internal/analytics/mock_event_logger.h +++ /dev/null @@ -1,38 +0,0 @@ -// 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_ANALYTICS_MOCK_EVENT_LOGGER_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_ANALYTICS_MOCK_EVENT_LOGGER_H_ - -#include "gmock/gmock.h" -#include "internal/analytics/event_logger.h" - -namespace nearby::analytics { - -class MockEventLogger : public ::nearby::analytics::EventLogger { - public: - MockEventLogger() = default; - ~MockEventLogger() override = default; - - MOCK_METHOD( - void, Log, - (const location::nearby::analytics::proto::ConnectionsLog& message), - (override)); - MOCK_METHOD(void, Log, (const sharing::analytics::proto::SharingLog& message), - (override)); -}; - -} // namespace nearby::analytics - -#endif // THIRD_PARTY_NEARBY_INTERNAL_ANALYTICS_MOCK_EVENT_LOGGER_H_ diff --git a/internal/analytics/sharing_log_matchers.h b/internal/analytics/sharing_log_matchers.h deleted file mode 100644 index ce01eb84..00000000 --- a/internal/analytics/sharing_log_matchers.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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_ANALYTICS_SHARING_LOG_MATCHERS_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_ANALYTICS_SHARING_LOG_MATCHERS_H_ - -#include "gmock/gmock.h" - -namespace nearby::analytics { - -MATCHER_P(HasCategory, category, "has category") { - return arg.event_category() == category; -} - -MATCHER_P(HasEventType, event_type, "has event type") { - return arg.event_type() == event_type; -} - -MATCHER_P(HasAction, action, "has action") { - return arg.action() == action; -} - -MATCHER_P(HasSessionId, session_id, "has session id") { - return arg.session_id() == session_id; -} - -MATCHER_P(HasDurationMillis, duration_millis, "has duration millis") { - return arg.duration_millis() == duration_millis; -} - -MATCHER_P(SharingLogHasStatus, status, "has status") { - return arg.status() == status; -} - -MATCHER_P(HasRpcName, rpc_name, "has rpc_name") { - return arg.rpc_name() == rpc_name; -} - -MATCHER_P(HasDirection, direction, "has direction") { - return arg.direction() == direction; -} - -MATCHER_P(HasErrorCode, error_code, "has error_code") { - return arg.error_code() == error_code; -} - -MATCHER_P(HasLatencyMillis, latency_millis, "has latency_millis") { - return arg.latency_millis() == latency_millis; -} - -} // namespace nearby::analytics - -#endif // THIRD_PARTY_NEARBY_INTERNAL_ANALYTICS_SHARING_LOG_MATCHERS_H_ diff --git a/internal/base/BUILD b/internal/base/BUILD index 7f8ae71f..771eeecc 100644 --- a/internal/base/BUILD +++ b/internal/base/BUILD @@ -19,8 +19,6 @@ licenses(["notice"]) cc_library( name = "base", - srcs = [ - ], hdrs = [ "observer_list.h", ], @@ -28,6 +26,7 @@ cc_library( "//internal/account:__subpackages__", "//internal/platform:__subpackages__", "//internal/test:__pkg__", + "//location/nearby/sharing/lib:__subpackages__", "//sharing:__subpackages__", ], deps = [ @@ -51,8 +50,6 @@ cc_library( ], deps = [ "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", - "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:span", ], ) diff --git a/internal/base/bluetooth_address.cc b/internal/base/bluetooth_address.cc index ac1de37d..913a863d 100644 --- a/internal/base/bluetooth_address.cc +++ b/internal/base/bluetooth_address.cc @@ -15,18 +15,19 @@ #include "internal/base/bluetooth_address.h" #include +#include +#include +#include #include "absl/strings/string_view.h" -#include "absl/types/optional.h" +#include "absl/types/span.h" namespace nearby { namespace device { namespace { template -// Note that some of the methods return absl::optional instead -// of std::optional, because iOS platform is still in C++14. -absl::optional CharToDigit(CHAR c) { +std::optional CharToDigit(CHAR c) { static_assert(1 <= BASE && BASE <= 36, "BASE needs to be in [1, 36]"); if (c >= '0' && c < '0' + std::min(BASE, 10)) return c - '0'; @@ -34,7 +35,7 @@ absl::optional CharToDigit(CHAR c) { if (c >= 'A' && c < 'A' + BASE - 10) return c - 'A' + 10; - return absl::nullopt; + return std::nullopt; } template @@ -43,9 +44,9 @@ static bool HexStringToByteContainer(absl::string_view input, OutIter output) { if (count == 0 || (count % 2) != 0) return false; for (uintptr_t i = 0; i < count / 2; ++i) { // most significant 4 bits - absl::optional msb = CharToDigit<16>(input[i * 2]); + std::optional msb = CharToDigit<16>(input[i * 2]); // least significant 4 bits - absl::optional lsb = CharToDigit<16>(input[i * 2 + 1]); + std::optional lsb = CharToDigit<16>(input[i * 2 + 1]); if (!msb.has_value() || !lsb.has_value()) { return false; } diff --git a/internal/crypto/BUILD b/internal/crypto/BUILD index 68558128..2f96db1a 100644 --- a/internal/crypto/BUILD +++ b/internal/crypto/BUILD @@ -44,8 +44,6 @@ cc_test( srcs = ["ed25519_unittest.cc"], copts = [ "-DUNIT_TEST", - "-Wno-inconsistent-missing-override", - "-Wno-non-virtual-dtor", "-Ithird_party", ], deps = [ diff --git a/internal/crypto_cros/BUILD b/internal/crypto_cros/BUILD index 3f61a913..d1a06ea1 100644 --- a/internal/crypto_cros/BUILD +++ b/internal/crypto_cros/BUILD @@ -99,8 +99,6 @@ cc_test( ], copts = [ "-DUNIT_TEST", - "-Wno-inconsistent-missing-override", - "-Wno-non-virtual-dtor", "-Ithird_party", ], deps = [ diff --git a/internal/crypto_cros/aead.cc b/internal/crypto_cros/aead.cc index f25699ee..451d9d5f 100644 --- a/internal/crypto_cros/aead.cc +++ b/internal/crypto_cros/aead.cc @@ -104,7 +104,7 @@ bool Aead::Seal(absl::string_view plaintext, absl::string_view nonce, return true; } -absl::optional> Aead::Open( +std::optional> Aead::Open( absl::Span ciphertext, absl::Span nonce, absl::Span additional_data) const { const size_t max_output_length = ciphertext.size(); diff --git a/internal/crypto_cros/aead_unittest.cc b/internal/crypto_cros/aead_unittest.cc index df1c4750..6699c47f 100644 --- a/internal/crypto_cros/aead_unittest.cc +++ b/internal/crypto_cros/aead_unittest.cc @@ -64,7 +64,7 @@ TEST_P(AeadTest, SealOpenSpan) { aead.Seal(kPlaintext, nonce, kAdditionalData); EXPECT_LT(sizeof(kPlaintext), ciphertext.size()); - absl::optional> decrypted = + std::optional> decrypted = aead.Open(ciphertext, nonce, kAdditionalData); ASSERT_TRUE(decrypted); ASSERT_EQ(decrypted->size(), sizeof(kPlaintext)); diff --git a/internal/crypto_cros/encryptor.cc b/internal/crypto_cros/encryptor.cc index 2eaede2c..2081091e 100644 --- a/internal/crypto_cros/encryptor.cc +++ b/internal/crypto_cros/encryptor.cc @@ -127,7 +127,7 @@ bool Encryptor::CryptString(bool do_encrypt, absl::string_view input, uint8_t* out_ptr = reinterpret_cast(nearbybase::WriteInto(&result, out_size + 1)); - absl::optional len = + std::optional len = (mode_ == CTR) ? CryptCTR(do_encrypt, nearbybase::as_bytes(absl::MakeSpan(input)), absl::MakeSpan(out_ptr, out_size)) @@ -143,7 +143,7 @@ bool Encryptor::CryptString(bool do_encrypt, absl::string_view input, bool Encryptor::CryptBytes(bool do_encrypt, absl::Span input, std::vector* output) { std::vector result(MaxOutput(do_encrypt, input.size())); - absl::optional len = + std::optional len = (mode_ == CTR) ? CryptCTR(do_encrypt, input, absl::MakeSpan(result)) : Crypt(do_encrypt, input, absl::MakeSpan(result)); if (!len) return false; @@ -159,9 +159,9 @@ size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) { return result; } -absl::optional Encryptor::Crypt(bool do_encrypt, - absl::Span input, - absl::Span output) { +std::optional Encryptor::Crypt(bool do_encrypt, + absl::Span input, + absl::Span output) { DCHECK(key_); // Must call Init() before En/De-crypt. const EVP_CIPHER* cipher = GetCipherForKey(key_); @@ -197,9 +197,9 @@ absl::optional Encryptor::Crypt(bool do_encrypt, return out_len; } -absl::optional Encryptor::CryptCTR(bool do_encrypt, - absl::Span input, - absl::Span output) { +std::optional Encryptor::CryptCTR(bool do_encrypt, + absl::Span input, + absl::Span output) { if (iv_.size() != AES_BLOCK_SIZE) { LOG(ERROR) << "Counter value not set in CTR mode."; return absl::nullopt; diff --git a/internal/interop/BUILD b/internal/interop/BUILD index ee6deda7..f90f8936 100644 --- a/internal/interop/BUILD +++ b/internal/interop/BUILD @@ -35,7 +35,7 @@ cc_library( ], visibility = [ "//connections:__subpackages__", - "//presence:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":authentication_status", @@ -54,8 +54,8 @@ cc_library( ], visibility = [ "//connections:__subpackages__", - "//presence:__subpackages__", "//sharing:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], ) @@ -70,7 +70,7 @@ cc_library( ], compatible_with = ["//buildenv/target:non_prod"], visibility = [ - "//presence:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":authentication_status", diff --git a/internal/platform/BUILD b/internal/platform/BUILD index 67f362f5..e9efd49e 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -164,7 +164,7 @@ cc_library( visibility = [ "//connections/implementation:__subpackages__", "//internal/platform/implementation:__subpackages__", - "//presence:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":base", @@ -191,7 +191,7 @@ cc_library( "//connections/implementation:__pkg__", "//connections/v3:__pkg__", "//internal/interop:__pkg__", - "//presence:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":logging", @@ -210,7 +210,6 @@ cc_library( srcs = [ "blocking_queue_stream.cc", "clock_impl.cc", - "device_info_impl.cc", "monitored_runnable.cc", "pending_job_registry.cc", "pipe.cc", @@ -231,10 +230,7 @@ cc_library( "condition_variable.h", "count_down_latch.h", "crypto.h", - "device_info.h", - "device_info_impl.h", "direct_executor.h", - "file.h", "future.h", "lockable.h", "monitored_runnable.h", @@ -306,21 +302,18 @@ cc_library( "bluetooth_adapter.h", "bluetooth_classic.h", "credential_storage_impl.h", - "webrtc.h", + "file.h", "wifi.h", "wifi_direct.h", "wifi_hotspot.h", "wifi_lan.h", ], - copts = [ - "-DCORE_ADAPTER_DLL", - "-DNO_WEBRTC", - ], + copts = ["-DCORE_ADAPTER_DLL"], visibility = [ "//connections:__subpackages__", "//internal/platform/implementation:__subpackages__", "//internal/test:__subpackages__", - "//presence:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":base", @@ -332,11 +325,10 @@ cc_library( "//connections/implementation/flags:connections_flags", "//internal/base", "//internal/flags:nearby_flags", - "//internal/platform/implementation:account_manager", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", + "//internal/platform/implementation:types", "//internal/platform/implementation:wifi_utils", - # TODO: Support WebRTC "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", @@ -344,9 +336,7 @@ cc_library( "@com_google_absl//absl/status", "@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:optional", ], ) @@ -376,7 +366,7 @@ cc_library( visibility = [ "//connections:__subpackages__", "//internal/platform/implementation:__subpackages__", - "//presence:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":base", @@ -386,6 +376,7 @@ cc_library( ":uuid", "//internal/base", "//internal/platform/implementation:comm", + "//internal/platform/implementation:webrtc_platform", "//internal/platform/implementation:wifi_utils", "//internal/test", "@com_google_absl//absl/base:core_headers", @@ -581,6 +572,7 @@ cc_test( shard_count = 16, deps = [ ":base", + ":comm", ":connection_info", ":logging", ":mac_address", @@ -592,7 +584,6 @@ cc_test( "//internal/crypto_cros", "//internal/platform/implementation:platform_impl", "//internal/platform/implementation:types", - "//internal/test", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/status", diff --git a/internal/platform/awdl.h b/internal/platform/awdl.h index 66dc63f4..7ff1d36a 100644 --- a/internal/platform/awdl.h +++ b/internal/platform/awdl.h @@ -16,6 +16,7 @@ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_AWDL_H_ #include #include +#include #include #include @@ -23,7 +24,6 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/functional/any_invocable.h" -#include "absl/types/optional.h" #include "internal/platform/blocking_queue_stream.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" @@ -261,7 +261,7 @@ class AwdlMedium { } // Returns the port range as a pair of min and max port. - absl::optional> GetDynamicPortRange() { + std::optional> GetDynamicPortRange() { return impl_->GetDynamicPortRange(); } diff --git a/internal/platform/ble.h b/internal/platform/ble.h index 7aafbce6..4117ea9c 100644 --- a/internal/platform/ble.h +++ b/internal/platform/ble.h @@ -27,7 +27,6 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" @@ -223,7 +222,7 @@ class GattServer final { ~GattServer() { Stop(); } // NOLINTNEXTLINE(google3-legacy-absl-backports) - absl::optional CreateCharacteristic( + std::optional CreateCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid, const api::ble::GattCharacteristic::Permission permission, const api::ble::GattCharacteristic::Property property) { @@ -277,13 +276,13 @@ class GattClient final { } // NOLINTNEXTLINE(google3-legacy-absl-backports) - absl::optional GetCharacteristic( + std::optional GetCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid) { return impl_->GetCharacteristic(service_uuid, characteristic_uuid); } // NOLINTNEXTLINE(google3-legacy-absl-backports) - absl::optional ReadCharacteristic( + std::optional ReadCharacteristic( const api::ble::GattCharacteristic& characteristic) { return impl_->ReadCharacteristic(characteristic); } @@ -295,17 +294,6 @@ class GattClient final { return impl_->WriteCharacteristic(characteristic, value, write_type); } - // TODO(qinwangz): We should not need `on_characteristic_changed_cb` when - // unsubscribing. - // NOLINTNEXTLINE(google3-legacy-absl-backports) - bool SetCharacteristicSubscription( - const api::ble::GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable - on_characteristic_changed_cb) { - return impl_->SetCharacteristicSubscription( - characteristic, enable, std::move(on_characteristic_changed_cb)); - } - void Disconnect() { impl_->Disconnect(); } // Returns true if a client_gatt_connection is usable. If this method diff --git a/internal/platform/ble_test.cc b/internal/platform/ble_test.cc index 9b43629d..6c7ee843 100644 --- a/internal/platform/ble_test.cc +++ b/internal/platform/ble_test.cc @@ -55,7 +55,6 @@ using ::nearby::api::ble::BleAdvertisementData; using ::nearby::api::ble::GattCharacteristic; using ::nearby::api::ble::TxPowerLevel; using ::testing::Optional; -using ::testing::status::StatusIs; constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); constexpr absl::string_view kAdvertisementString = "\x0a\x0b\x0c\x0d"; @@ -771,83 +770,5 @@ TEST_F(BleMediumTest, GattClientOperatiosOnCharacteristic) { env_.Stop(); } -TEST_F(BleMediumTest, GattClientSubscribeNotificationGattServerCanNotify) { - env_.Start(); - BluetoothAdapter adapter_a; - BluetoothAdapter adapter_b; - BleMedium ble_a(adapter_a); - BleMedium ble_b(adapter_b); - Uuid service_uuid(1234, 5678); - Uuid characteristic_uuid(5678, 1234); - GattCharacteristic::Permission permissions = - GattCharacteristic::Permission::kRead; - GattCharacteristic::Property properties = - GattCharacteristic::Property::kRead | - GattCharacteristic::Property::kNotify; - - // Start GattServer - std::unique_ptr gatt_server = - ble_a.StartGattServer(/*ServerGattConnectionCallback=*/{}); - - ASSERT_NE(gatt_server, nullptr); - // Add characteristic and its value. - // NOLINTNEXTLINE(google3-legacy-absl-backports) - std::optional server_characteristic = - gatt_server->CreateCharacteristic(service_uuid, characteristic_uuid, - permissions, properties); - EXPECT_TRUE(gatt_server->UpdateCharacteristic(server_characteristic.value(), - ByteArray("any"))); - - // Start GattClient - MacAddress mac_address = adapter_a.GetAddress(); - std::unique_ptr gatt_client = ble_b.ConnectToGattServer( - BlePeripheral(ble_b, mac_address.address()), kTxPowerLevel, - /*ClientGattConnectionCallback=*/{}); - ASSERT_NE(gatt_client, nullptr); - - EXPECT_TRUE(gatt_client->DiscoverServiceAndCharacteristics( - service_uuid, {characteristic_uuid})); - - // Subscribes notification - EXPECT_TRUE(gatt_client->SetCharacteristicSubscription( - server_characteristic.value(), true, - [](absl::string_view value) { EXPECT_EQ(value, "hello"); })); - - // Sends notification - EXPECT_EQ(gatt_server->NotifyCharacteristicChanged( - server_characteristic.value(), false, ByteArray("hello")), - absl::OkStatus()); - - std::string notified_value; - CountDownLatch latch(1); - // Subscribes notification - EXPECT_TRUE(gatt_client->SetCharacteristicSubscription( - server_characteristic.value(), true, [&](absl::string_view value) { - notified_value = value; - latch.CountDown(); - })); - // Sends indication - EXPECT_EQ(gatt_server->NotifyCharacteristicChanged( - server_characteristic.value(), true, ByteArray("any")), - absl::OkStatus()); - latch.Await(); - EXPECT_EQ(notified_value, "any"); - - // Unsubscribes notification - EXPECT_TRUE(gatt_client->SetCharacteristicSubscription( - server_characteristic.value(), false, - [&](absl::string_view value) { GTEST_FAIL(); })); - EXPECT_THAT(gatt_server->NotifyCharacteristicChanged( - server_characteristic.value(), true, ByteArray("any")), - StatusIs(absl::StatusCode::kNotFound)); - - gatt_client->Disconnect(); - // Failed to subscribe characteristic notification as gatt is disconnected. - EXPECT_FALSE(gatt_client->SetCharacteristicSubscription( - server_characteristic.value(), true, [](absl::string_view value) {})); - gatt_server->Stop(); - env_.Stop(); -} - } // namespace } // namespace nearby diff --git a/internal/platform/blocking_queue_stream.h b/internal/platform/blocking_queue_stream.h index 79030bc9..f898ce04 100644 --- a/internal/platform/blocking_queue_stream.h +++ b/internal/platform/blocking_queue_stream.h @@ -41,9 +41,7 @@ class BlockingQueueStream : public InputStream { private: mutable Mutex mutex_; - bool is_multiplex_enabled_ = NearbyFlags::GetInstance().GetBoolFlag( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex); + bool is_multiplex_enabled_ = false; ArrayBlockingQueue blocking_queue_{ FeatureFlags::GetInstance() .GetFlags() diff --git a/internal/platform/blocking_queue_stream_test.cc b/internal/platform/blocking_queue_stream_test.cc index bf1d73ef..3064c002 100644 --- a/internal/platform/blocking_queue_stream_test.cc +++ b/internal/platform/blocking_queue_stream_test.cc @@ -24,47 +24,21 @@ namespace nearby { namespace { TEST(BlockingQueueStreamTest, ReadSuccess) { - bool is_multiplex_enabled = NearbyFlags::GetInstance().GetBoolFlag( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex, true); - - BlockingQueueStream stream; - ByteArray bytes = ByteArray("test1test2test3"); - stream.Write(bytes); - ExceptionOr result = stream.Read(5); - EXPECT_EQ(result.result(), ByteArray("test1")); - result = stream.Read(5); - EXPECT_EQ(result.result(), ByteArray("test2")); - result = stream.Read(5); - EXPECT_EQ(result.result(), ByteArray("test3")); - stream.Close(); - - NearbyFlags::GetInstance().OverrideBoolFlagValue( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex, is_multiplex_enabled); -} - -TEST(BlockingQueueStreamTest, MultiplexDisabled) { - bool is_multiplex_enabled = NearbyFlags::GetInstance().GetBoolFlag( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex); - NearbyFlags::GetInstance().OverrideBoolFlagValue( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex, false); - BlockingQueueStream stream; ByteArray bytes = ByteArray("test1test2test3"); stream.Write(bytes); ExceptionOr result = stream.Read(5); EXPECT_EQ(result, ExceptionOr(Exception::kExecution)); stream.Close(); +} - NearbyFlags::GetInstance().OverrideBoolFlagValue( - connections::config_package_nearby::nearby_connections_feature:: - kEnableMultiplex, is_multiplex_enabled); +TEST(BlockingQueueStreamTest, MultiplexDisabled) { + BlockingQueueStream stream; + ByteArray bytes = ByteArray("test1test2test3"); + stream.Write(bytes); + ExceptionOr result = stream.Read(5); + EXPECT_EQ(result, ExceptionOr(Exception::kExecution)); + stream.Close(); } } // namespace diff --git a/internal/platform/connection_info.cc b/internal/platform/connection_info.cc index eaa745cc..24d4c082 100644 --- a/internal/platform/connection_info.cc +++ b/internal/platform/connection_info.cc @@ -42,6 +42,6 @@ ConnectionInfoVariant ConnectionInfo::FromDataElementBytes( return result.value(); } } - return absl::monostate(); + return std::monostate(); } } // namespace nearby diff --git a/internal/platform/connection_info_test.cc b/internal/platform/connection_info_test.cc index 972456c7..2272f15a 100644 --- a/internal/platform/connection_info_test.cc +++ b/internal/platform/connection_info_test.cc @@ -104,7 +104,7 @@ TEST(ConnectionInfoTest, TestMonostate) { auto serialized = info->ToDataElementBytes(); auto connection_info = ConnectionInfo::FromDataElementBytes(serialized.substr(0, 10)); - EXPECT_TRUE(absl::holds_alternative(connection_info)); + EXPECT_TRUE(absl::holds_alternative(connection_info)); } } diff --git a/internal/platform/device_info.h b/internal/platform/device_info.h deleted file mode 100644 index 159d2d74..00000000 --- a/internal/platform/device_info.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2021 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_DEVICE_INFO_H_ -#define PLATFORM_PUBLIC_DEVICE_INFO_H_ - -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/base/file_path.h" -#include "internal/platform/implementation/device_info.h" - -namespace nearby { - -class DeviceInfo { - public: - virtual ~DeviceInfo() = default; - - // All strings are UTF-8 encoded. - virtual std::string GetOsDeviceName() const = 0; - virtual api::DeviceInfo::DeviceType GetDeviceType() const = 0; - virtual api::DeviceInfo::OsType GetOsType() const = 0; - - virtual FilePath GetDownloadPath() const = 0; - virtual FilePath GetAppDataPath() const = 0; - virtual FilePath GetTemporaryPath() const = 0; - virtual FilePath GetLogPath() const = 0; - - virtual std::optional GetAvailableDiskSpaceInBytes( - const FilePath& path) const = 0; - - virtual bool IsScreenLocked() const = 0; - virtual void RegisterScreenLockedListener( - absl::string_view listener_name, - std::function callback) = 0; - virtual void UnregisterScreenLockedListener( - absl::string_view listener_name) = 0; - - virtual bool PreventSleep() = 0; - virtual bool AllowSleep() = 0; - - // Returns UTF-8 encoded localized device name depending on device type. - std::string GetDeviceTypeName() const { - // TODO(b/230132370): return localized device name. - switch (GetDeviceType()) { - case api::DeviceInfo::DeviceType::kPhone: - return "Phone"; - case api::DeviceInfo::DeviceType::kTablet: - return "Tablet"; - case api::DeviceInfo::DeviceType::kLaptop: - return "PC"; - default: - return "Unknown"; - } - } -}; - -} // namespace nearby - -#endif // PLATFORM_PUBLIC_DEVICE_INFO_H_ diff --git a/internal/platform/device_info_impl.cc b/internal/platform/device_info_impl.cc deleted file mode 100644 index 79d5be7f..00000000 --- a/internal/platform/device_info_impl.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2021 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/device_info_impl.h" - -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/base/file_path.h" -#include "internal/base/files.h" -#include "internal/platform/implementation/device_info.h" - -namespace nearby { - -std::string DeviceInfoImpl::GetOsDeviceName() const { - std::optional device_name = device_info_impl_->GetOsDeviceName(); - if (device_name.has_value()) { - return *device_name; - } - - return "unknown"; -} - -api::DeviceInfo::DeviceType DeviceInfoImpl::GetDeviceType() const { - return device_info_impl_->GetDeviceType(); -} - -api::DeviceInfo::OsType DeviceInfoImpl::GetOsType() const { - return device_info_impl_->GetOsType(); -} - -FilePath DeviceInfoImpl::GetDownloadPath() const { - std::optional path = device_info_impl_->GetDownloadPath(); - if (path.has_value()) { - return *path; - } - return Files::GetTemporaryDirectory(); -} - -FilePath DeviceInfoImpl::GetAppDataPath() const { - std::optional path = device_info_impl_->GetLocalAppDataPath(); - if (path.has_value()) { - return *path; - } - return Files::GetTemporaryDirectory(); -} - -FilePath DeviceInfoImpl::GetTemporaryPath() const { - std::optional path = device_info_impl_->GetTemporaryPath(); - if (path.has_value()) { - return *path; - } - return Files::GetTemporaryDirectory(); -} - -FilePath DeviceInfoImpl::GetLogPath() const { - std::optional path = device_info_impl_->GetLogPath(); - return path.value_or(GetTemporaryPath()); -} - -std::optional DeviceInfoImpl::GetAvailableDiskSpaceInBytes( - const FilePath& path) const { - return Files::GetAvailableDiskSpaceInBytes(path); -} - -bool DeviceInfoImpl::IsScreenLocked() const { - return device_info_impl_->IsScreenLocked(); -} - -void DeviceInfoImpl::RegisterScreenLockedListener( - absl::string_view listener_name, - std::function callback) { - device_info_impl_->RegisterScreenLockedListener(listener_name, callback); -} - -void DeviceInfoImpl::UnregisterScreenLockedListener( - absl::string_view listener_name) { - device_info_impl_->UnregisterScreenLockedListener(listener_name); -} - -bool DeviceInfoImpl::PreventSleep() { - return device_info_impl_->PreventSleep(); -} - -bool DeviceInfoImpl::AllowSleep() { return device_info_impl_->AllowSleep(); } - -} // namespace nearby diff --git a/internal/platform/device_info_impl.h b/internal/platform/device_info_impl.h deleted file mode 100644 index fc5ba6fe..00000000 --- a/internal/platform/device_info_impl.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2021 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_DEVICE_INFO_IMPL_H_ -#define PLATFORM_PUBLIC_DEVICE_INFO_IMPL_H_ - -#include -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/base/file_path.h" -#include "internal/platform/device_info.h" -#include "internal/platform/implementation/device_info.h" -#include "internal/platform/implementation/platform.h" - -namespace nearby { - -class DeviceInfoImpl : public DeviceInfo { - public: - DeviceInfoImpl() - : device_info_impl_(api::ImplementationPlatform::CreateDeviceInfo()) {} - - std::string GetOsDeviceName() const override; - api::DeviceInfo::DeviceType GetDeviceType() const override; - api::DeviceInfo::OsType GetOsType() const override; - - FilePath GetDownloadPath() const override; - FilePath GetAppDataPath() const override; - FilePath GetTemporaryPath() const override; - FilePath GetLogPath() const override; - - std::optional GetAvailableDiskSpaceInBytes( - const FilePath& path) const override; - - bool IsScreenLocked() const override; - void RegisterScreenLockedListener( - absl::string_view listener_name, - std::function callback) override; - void UnregisterScreenLockedListener(absl::string_view listener_name) override; - - bool PreventSleep() override; - bool AllowSleep() override; - - private: - std::unique_ptr device_info_impl_; -}; -} // namespace nearby - -#endif // PLATFORM_PUBLIC_DEVICE_INFO_IMPL_H_ diff --git a/internal/platform/exception.h b/internal/platform/exception.h index 08345971..07dbfaac 100644 --- a/internal/platform/exception.h +++ b/internal/platform/exception.h @@ -15,6 +15,7 @@ #ifndef PLATFORM_BASE_EXCEPTION_H_ #define PLATFORM_BASE_EXCEPTION_H_ +#include #include #include "absl/meta/type_traits.h" @@ -82,7 +83,7 @@ class ExceptionOr { ExceptionOr(Exception exception) : exception_{exception} {} // NOLINT // If there exists explicit conversion from U to T, // then allow explicit conversion from ExceptionOr to ExceptionOr. - template ()})>> + template ()})>> explicit ExceptionOr(ExceptionOr value) { if (!value.ok()) { exception_ = value.GetException(); diff --git a/internal/platform/feature_flags.h b/internal/platform/feature_flags.h index cad1ba6a..a4483839 100644 --- a/internal/platform/feature_flags.h +++ b/internal/platform/feature_flags.h @@ -75,14 +75,6 @@ class FeatureFlags { // auto-resume 5. non-distance-constraint-recovery 6. payload_ack std::int32_t min_nc_version_supports_safe_to_disconnect = 1; std::int32_t min_nc_version_supports_auto_reconnect = 3; - absl::Duration safe_to_disconnect_reconnect_retry_delay_millis = - absl::Milliseconds(4000); - absl::Duration safe_to_disconnect_reconnect_timeout_millis = - absl::Milliseconds(15000); - std::int32_t safe_to_disconnect_reconnect_retry_attempts = 3; - absl::Duration - safe_to_disconnect_reconnect_skip_duplicated_endpoint_duration = - absl::Milliseconds(2000); // Android code won't be able to launch "payload_received_ack" feature for // in near future, so change "payload_received_ack" version from "2" to "5" // after auto-reconnect and auto-resume. diff --git a/internal/platform/flags/BUILD b/internal/platform/flags/BUILD index e0e875a0..334caa90 100644 --- a/internal/platform/flags/BUILD +++ b/internal/platform/flags/BUILD @@ -22,7 +22,6 @@ cc_library( ], visibility = [ "//connections:__subpackages__", - "//connections:partners", "//internal:__subpackages__", "//location/nearby/cpp:__subpackages__", "//location/nearby/testing:__subpackages__", diff --git a/internal/platform/flags/nearby_platform_feature_flags.h b/internal/platform/flags/nearby_platform_feature_flags.h index 924d80f7..0deadf4b 100644 --- a/internal/platform/flags/nearby_platform_feature_flags.h +++ b/internal/platform/flags/nearby_platform_feature_flags.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Mendel flags, auto-generated. DO NOT EDIT. #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_FLAGS_NEARBY_PLATFORM_FEATURE_FLAGS_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_FLAGS_NEARBY_PLATFORM_FEATURE_FLAGS_H_ @@ -28,50 +29,45 @@ constexpr absl::string_view kConfigPackage = "nearby"; // The Nearby Platform features. namespace nearby_platform_feature { - -// The maximum scanning times for available hotspots. -constexpr auto kWifiHotspotScanMaxRetries = - flags::Flag(kConfigPackage, "45415883", 3); - -// The maximum IP check times during Wi-Fi hotspot connection. -constexpr auto kWifiHotspotCheckIpMaxRetries = - flags::Flag(kConfigPackage, "45415884", 20); - -// The interval between 2 IP check attempts. -constexpr auto kWifiHotspotCheckIpIntervalMillis = - flags::Flag(kConfigPackage, "45415885", 500); - -// The maximum connection times to remote Wi-Fi hotspot. -constexpr auto kWifiHotspotConnectionMaxRetries = - flags::Flag(kConfigPackage, "45415886", 3); - -// The interval between 2 connectin attempts. -constexpr auto kWifiHotspotConnectionIntervalMillis = - flags::Flag(kConfigPackage, "45415887", 2000); - -// The connection timeout to remote Wi-Fi hotspot. -constexpr auto kWifiHotspotConnectionTimeoutMillis = - flags::Flag(kConfigPackage, "45415888", 10000); - -// Enable/Disable use of address candidates for hotspot upgrade in Windows. -constexpr auto kEnableHotspotAddressCandidates = - flags::Flag(kConfigPackage, "45739567", false); - +// Disable/Enable GATT feature in BLE v2. +constexpr auto kEnableBleV2Gatt = + flags::Flag(kConfigPackage, "45415180", true); +// Disable/Enable GATT feature on devices without BLE extended feature. +constexpr auto kEnableBleV2GattOnNonExtendedDevice = + flags::Flag(kConfigPackage, "45415267", true); // Enable/Disable Intel PIe SDK to query/set WIFI feature. constexpr auto kEnableIntelPieSdk = flags::Flag(kConfigPackage, "45428547", false); - -// Enable/Disable new Bluetooth refactor -constexpr auto kEnableNewBluetoothRefactor = - flags::Flag(kConfigPackage, "45615156", false); - -// The send buffer size of blocking socket +// Replace std::async with platform thread +constexpr auto kEnablePlatformThreadToNetwork = + flags::Flag(kConfigPackage, "45412711", true); +// Enable/Disable task scheduler for ScheduledExecutor and timer. +constexpr auto kEnableTaskScheduler = + flags::Flag(kConfigPackage, "45643835", true); +// Enable/Disable Wi-Fi hotspot native. +constexpr auto kEnableWifiHotspotNative = + flags::Flag(kConfigPackage, "45667396", true); +// The send buffer size of blocking socket. constexpr auto kSocketSendBufferSize = flags::Flag(kConfigPackage, "45673785", 524288); - -// Run scheduled executor callback on executor thread. -constexpr auto kRunScheduledExecutorCallbackOnExecutorThread = - flags::Flag(kConfigPackage, "45686494", false); +// The interval between 2 IP check attempts. +constexpr auto kWifiHotspotCheckIpIntervalMillis = + flags::Flag(kConfigPackage, "45415885", 500); +// The maximum IP check times during Wi-Fi hotspot connection. +constexpr auto kWifiHotspotCheckIpMaxRetries = + flags::Flag(kConfigPackage, "45415884", 10); +// The interval between 2 connectin attempts. +constexpr auto kWifiHotspotConnectionIntervalMillis = + flags::Flag(kConfigPackage, "45415887", 2000); +// The maximum connection times to remote WiFi hotspot. +constexpr auto kWifiHotspotConnectionMaxRetries = + flags::Flag(kConfigPackage, "45415886", 3); +// The connection timeout to remote Wi-Fi hotspot. +constexpr auto kWifiHotspotConnectionTimeoutMillis = + flags::Flag(kConfigPackage, "45415888", 10000); +// The max retry times to scan WiFi hotspots. +constexpr auto kWifiHotspotScanMaxRetries = + flags::Flag(kConfigPackage, "45415883", 3); } // namespace nearby_platform_feature } // namespace config_package_nearby diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index cf3879bb..39e35617 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -17,69 +17,6 @@ load("@rules_cc//cc:cc_test.bzl", "cc_test") licenses(["notice"]) -cc_library( - name = "auth_status", - hdrs = ["auth_status.h"], - visibility = [ - "//internal/auth:__pkg__", - "//internal/platform/implementation:__subpackages__", - "//location/nearby/cpp/sharing/clients/cpp:__subpackages__", - ], -) - -cc_library( - name = "account_info", - hdrs = ["account_info.h"], - visibility = [ - "//internal/auth:__pkg__", - "//internal/platform/implementation:__subpackages__", - "//location/nearby/cpp/sharing/clients/cpp:__subpackages__", - ], -) - -cc_library( - name = "account_manager", - hdrs = ["account_manager.h"], - visibility = [ - "//internal/account:__pkg__", - "//internal/platform:__pkg__", - "//internal/platform/implementation:__subpackages__", - "//internal/test:__subpackages__", - "//location/nearby/cpp/sharing/clients/cpp:__subpackages__", - "//location/nearby/sharing/lib:__subpackages__", - "//location/nearby/sharing/sdk/quick_share_server:__pkg__", - "//sharing:__subpackages__", - ], - deps = [ - ":account_info", - ":signin_attempt", - "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/status", - "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings:string_view", - ], -) - -cc_library( - name = "signin_attempt", - hdrs = ["signin_attempt.h"], - visibility = [ - "//internal/account:__pkg__", - "//internal/auth:__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 = [ - ":account_info", - ":auth_status", - "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/strings:string_view", - ], -) - cc_library( name = "types", hdrs = [ @@ -112,11 +49,12 @@ cc_library( "//internal/test:__subpackages__", "//location/nearby/analytics/cpp:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//presence:__subpackages__", "//sharing:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ "//internal/base:file_path", + "//internal/base:files", "//internal/crypto_cros", "//internal/platform:base", "//internal/platform:mac_address", @@ -149,6 +87,26 @@ cc_library( ], ) +cc_library( + name = "webrtc_platform", + hdrs = [ + "webrtc.h", + "webrtc_platform.h", + ], + compatible_with = ["//buildenv/target:non_prod"], + visibility = [ + "//:__subpackages__", + ], + deps = [ + "//connections/implementation/proto:offline_wire_formats_cc_proto", + "//internal/platform:base", + "//third_party/webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", + "//third_party/webrtc/files/stable/webrtc/api:scoped_refptr", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/strings:string_view", + ], +) + cc_library( name = "comm", hdrs = [ @@ -162,30 +120,26 @@ cc_library( "http_loader.h", "psk_info.h", "upgrade_address_info.h", - "webrtc.h", "wifi.h", "wifi_direct.h", "wifi_hotspot.h", "wifi_lan.h", ], - copts = ["-DNO_WEBRTC"], visibility = [ "//connections/implementation:__subpackages__", "//internal/network:__subpackages__", "//internal/platform:__pkg__", "//internal/platform/implementation:__subpackages__", - "//presence:__subpackages__", - "//presence/implementation:__subpackages__", + "//third_party/nearby/presence:__subpackages__", + "//third_party/nearby/presence/implementation:__subpackages__", ], deps = [ - "//connections/implementation/proto:offline_wire_formats_cc_proto", "//internal/platform:base", "//internal/platform:cancellation_flag", "//internal/platform:mac_address", "//internal/platform:uuid", "//internal/proto:credential_cc_proto", "//internal/proto:local_credential_cc_proto", - # TODO: Support WebRTC "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/functional:any_invocable", @@ -194,7 +148,6 @@ cc_library( "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/time", - "@com_google_absl//absl/types:optional", ], ) @@ -203,7 +156,6 @@ cc_library( hdrs = [ "platform.h", ], - defines = ["NO_WEBRTC"], visibility = [ "//connections/implementation:__subpackages__", "//internal:__subpackages__", @@ -213,6 +165,7 @@ cc_library( "//location/nearby/analytics/cpp:__subpackages__", "//location/nearby/apps/better_together/plugins/preferences_native:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", + "//sharing/internal/impl/common:__subpackages__", ], deps = [ ":comm", @@ -229,6 +182,8 @@ cc_library( tags = ["keep_dep"], # Prevent build_cleaner from removing the dependency. visibility = [ "//:__subpackages__", + "//location/nearby/analytics/cpp:__subpackages__", + "//location/nearby/cpp:__subpackages__", "//location/nearby/sharing/lib:__subpackages__", ], deps = [ @@ -259,3 +214,16 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "device_info_test", + size = "small", + timeout = "moderate", + srcs = ["device_info_test.cc"], + deps = [ + ":types", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/internal/platform/implementation/account_info.h b/internal/platform/implementation/account_info.h deleted file mode 100644 index 2cb48535..00000000 --- a/internal/platform/implementation/account_info.h +++ /dev/null @@ -1,35 +0,0 @@ -// 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_ACCOUNT_INFO_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_ACCOUNT_INFO_H_ - -#include - -namespace nearby { - -// Describes a Nearby account. The account class will have more properties -// and methods in the future based on the new feature added. -struct AccountInfo { - 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; -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_ACCOUNT_INFO_H_ diff --git a/internal/platform/implementation/account_manager.h b/internal/platform/implementation/account_manager.h deleted file mode 100644 index 3ab62731..00000000 --- a/internal/platform/implementation/account_manager.h +++ /dev/null @@ -1,89 +0,0 @@ -// 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 -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/account_info.h" -#include "internal/platform/implementation/signin_attempt.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: - using Account = AccountInfo; - - // 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 GetCurrentAccount() = 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 - // Returns a SigninAttempt object that can be used to complete the login - // process. - virtual std::unique_ptr Login( - absl::string_view client_id, absl::string_view client_secret) = 0; - - // Logs out current active account. |logout_callback| is called when logout is - // completed. - virtual void Logout( - absl::AnyInvocable logout_callback) = 0; - - // Gets access token for the active account. - // |callback| is called with the access token or error status. - // - // Returns false if callback is null. - virtual bool GetAccessToken( - absl::AnyInvocable)> 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 GetOAuthClientCredential() = 0; - - virtual void AddObserver(Observer* observer) = 0; - virtual void RemoveObserver(Observer* observer) = 0; - - virtual void SaveAccountPrefs(absl::string_view user_id, - absl::string_view client_id, - absl::string_view client_secret) = 0; -}; - -} // namespace nearby - -#endif // PLATFORM_API_ACCOUNT_MANAGER_H_ diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index 5a292734..f850bd13 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -51,6 +51,18 @@ objc_library( ], ) +objc_library( + name = "apple_webrtc", + srcs = [ + "webrtc_platform.mm", + ], + deps = [ + "//connections/implementation/mediums/webrtc:webrtc_medium_impl", + "//internal/platform/implementation:webrtc_platform", + "//third_party/apple_frameworks:Foundation", + ], +) + objc_library( name = "apple", srcs = [ @@ -61,7 +73,6 @@ objc_library( "preferences_manager.mm", "scheduled_executor.mm", "timer.mm", - "webrtc.mm", "wifi_hotspot.mm", "wifi_lan.mm", ], @@ -70,7 +81,6 @@ objc_library( "device_info.h", "preferences_manager.h", "timer.h", - "webrtc.h", "wifi.h", "wifi_hotspot.h", "wifi_lan.h", @@ -102,6 +112,7 @@ objc_library( "//internal/base:file_path", "//internal/base:files", "//internal/base:masker", + "//internal/platform/implementation/apple/Flags", "//internal/platform/implementation/apple/Mediums/Hotspot", "//internal/account", "//internal/crypto_cros", @@ -109,10 +120,6 @@ objc_library( "//internal/platform:logging", "//internal/platform:types", "//internal/proto:tachyon_cc_proto", - "//third_party/webrtc/files/stable/webrtc/api/task_queue:default_task_queue_factory", - "//third_party/webrtc/files/stable/webrtc/api:create_modular_peer_connection_factory", - "//third_party/webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", - "//third_party/webrtc/files/stable/webrtc/rtc_base:checks", "//internal/platform:base", "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", @@ -345,11 +352,11 @@ cc_test( deps = [ ":Platform_cc", "//internal/platform/implementation/g3:crypto", + "//third_party/gloop/thread/fiber", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", - "@com_google_nisaba//nisaba/port:thread_pool/fiber", ], ) diff --git a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h index 7d75da5d..52c59b64 100644 --- a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h +++ b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.h @@ -29,4 +29,13 @@ /** Checks whether BLE L2CAP refactor is enabled in the Nearby Connections SDK. */ @property(nonatomic, class, readonly) BOOL refactorBleL2capEnabled; +/** Checks whether shared peripheral manager is enabled in the Nearby Connections SDK. */ +@property(nonatomic, class, readonly) BOOL sharedPeripheralManagerEnabled; + +/** Checks whether single copy read/write is enabled in the Nearby Connections SDK. */ +@property(nonatomic, class, readonly) BOOL singleCopyEnabled; + +/** Checks whether BLE server socket deadlock is fixed in the Nearby Connections SDK. */ +@property(nonatomic, class, readonly) BOOL fixBleServerSocketDeadlockEnabled; + @end diff --git a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm index 548518e8..e00328c3 100644 --- a/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm +++ b/internal/platform/implementation/apple/Flags/GNCFeatureFlags.mm @@ -42,4 +42,21 @@ kRefactorBleL2cap); } ++ (BOOL)sharedPeripheralManagerEnabled { + return nearby::NearbyFlags::GetInstance().GetBoolFlag( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager); +} + ++ (BOOL)singleCopyEnabled { + return nearby::NearbyFlags::GetInstance().GetBoolFlag( + nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy); +} + ++ (BOOL)fixBleServerSocketDeadlockEnabled { + return nearby::NearbyFlags::GetInstance().GetBoolFlag( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kFixBleServerSocketDeadlock); +} + @end diff --git a/internal/platform/implementation/apple/Flags/Tests/GNCFeatureFlagsTest.mm b/internal/platform/implementation/apple/Flags/Tests/GNCFeatureFlagsTest.mm index 767eebfb..59784339 100644 --- a/internal/platform/implementation/apple/Flags/Tests/GNCFeatureFlagsTest.mm +++ b/internal/platform/implementation/apple/Flags/Tests/GNCFeatureFlagsTest.mm @@ -34,6 +34,13 @@ nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( nearby::connections::config_package_nearby::nearby_connections_feature::kEnableBleL2cap, false); + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + false); + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + false); [super tearDown]; } @@ -78,4 +85,34 @@ XCTAssertFalse([GNCFeatureFlags bleL2capEnabled]); } +- (void)testRefactorBleL2capEnabled_WhenFlagIsTrue { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + YES); + XCTAssertTrue([GNCFeatureFlags refactorBleL2capEnabled]); +} + +- (void)testRefactorBleL2capEnabled_WhenFlagIsFalse { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature::kRefactorBleL2cap, + NO); + XCTAssertFalse([GNCFeatureFlags refactorBleL2capEnabled]); +} + +- (void)testSharedPeripheralManagerEnabled_WhenFlagIsTrue { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + YES); + XCTAssertTrue([GNCFeatureFlags sharedPeripheralManagerEnabled]); +} + +- (void)testSharedPeripheralManagerEnabled_WhenFlagIsFalse { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + NO); + XCTAssertFalse([GNCFeatureFlags sharedPeripheralManagerEnabled]); +} + @end diff --git a/internal/platform/implementation/apple/Mediums/BLE/BUILD b/internal/platform/implementation/apple/Mediums/BLE/BUILD index 2a7a19f8..8f43a4e3 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/BUILD +++ b/internal/platform/implementation/apple/Mediums/BLE/BUILD @@ -39,6 +39,7 @@ objc_library( "GNCMConnection.m", "GNCPeripheral.m", "GNCPeripheralManager.m", + "GNCPeripheralManagerMultiplexer.m", "NSData+GNCBase85.mm", "NSData+GNCWebSafeBase64.m", ], @@ -59,6 +60,7 @@ objc_library( "GNCMConnection.h", "GNCPeripheral.h", "GNCPeripheralManager.h", + "GNCPeripheralManagerMultiplexer.h", "NSData+GNCBase85.h", "NSData+GNCWebSafeBase64.h", ], diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h index 1b94731a..5ee0cad3 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h @@ -15,6 +15,8 @@ #import #import +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h" + @class GNCBLEGATTCharacteristic; NS_ASSUME_NONNULL_BEGIN @@ -57,7 +59,18 @@ typedef void (^GNCStopAdvertisingCompletionHandler)(NSError *_Nullable error); * * @note The public APIs of this class are thread safe. */ -@interface GNCBLEGATTServer : NSObject +@interface GNCBLEGATTServer : NSObject + +/** + * Initializes the GATT server. + * + * @param peripheralManager The peripheral manager to use. + * @param queue The queue to use for delegate callbacks and internal operations. + */ +- (instancetype)initWithPeripheralManager:(nullable id)peripheralManager + queue:(nullable dispatch_queue_t)queue; + +- (instancetype)init NS_UNAVAILABLE; /** * Creates a characteristic and adds it to the GATT server. diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.m b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.m index 6193a7ad..edf95082 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.m +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.m @@ -59,34 +59,37 @@ static const int kMaxAdvertisementLengthOnIOS = 23; NSDictionary *_advertisementData; } -- (instancetype)init { +- (instancetype)initWithPeripheralManager:(nullable id)peripheralManager + queue:(nullable dispatch_queue_t)queue { self = [super init]; if (self) { - _queue = dispatch_queue_create(kGNCBLEGATTServerQueueLabel, DISPATCH_QUEUE_SERIAL); - _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil queue:_queue]; - // Set for @c GNCPeripheralManager to be able to forward callbacks. - _peripheralManager.peripheralDelegate = self; + _queue = queue ?: dispatch_queue_create(kGNCBLEGATTServerQueueLabel, DISPATCH_QUEUE_SERIAL); _services = [[NSMutableDictionary alloc] init]; _pendingCharacteristics = [[NSMutableDictionary alloc] init]; _characteristicValues = [[NSMutableDictionary alloc] init]; _advertisementData = nil; - } - return self; -} -// This is private and should only be used for tests. The provided peripheral manager must call -// delegate methods on the main queue. -- (instancetype)initWithPeripheralManager:(nullable id)peripheralManager { - self = [super init]; - if (self) { - _queue = dispatch_get_main_queue(); - _peripheralManager = peripheralManager; - // Set for @c GNCPeripheralManager to be able to forward callbacks. - _peripheralManager.peripheralDelegate = self; - _services = [[NSMutableDictionary alloc] init]; - _pendingCharacteristics = [[NSMutableDictionary alloc] init]; - _characteristicValues = [[NSMutableDictionary alloc] init]; - _advertisementData = nil; + if (GNCFeatureFlags.sharedPeripheralManagerEnabled) { + if (!peripheralManager) { + // In shared mode, the peripheral manager must be injected. + [NSException raise:NSInvalidArgumentException + format:@"Peripheral manager cannot be nil when shared manager is enabled."]; + } + _peripheralManager = peripheralManager; + // In shared mode, do NOT set the delegate. The Multiplexer handles callbacks. + } else { + // Legacy mode: Create a new manager if one isn't provided. + if (!peripheralManager) { + peripheralManager = [[CBPeripheralManager alloc] + initWithDelegate:nil + queue:_queue + options:@{CBPeripheralManagerOptionShowPowerAlertKey : @NO}]; + } + _peripheralManager = peripheralManager; + // In legacy mode, we own the manager (or use the injected one as if we own it) and set the + // delegate. + _peripheralManager.peripheralDelegate = self; + } } return self; } @@ -342,6 +345,12 @@ static const int kMaxAdvertisementLengthOnIOS = 23; - (void)gnc_peripheralManager:(id)peripheral didReceiveReadRequest:(CBATTRequest *)request { dispatch_assert_queue(_queue); + if (!_services[request.characteristic.service.UUID]) { + // This server does not own the requested service. Ignore the request to allow other listeners + // (or future listeners) to handle it. + return; + } + NSData *value = _characteristicValues[request.characteristic.service.UUID][request.characteristic.UUID]; if (!value) { diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h index be602889..285bb0ce 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h @@ -15,6 +15,8 @@ #import #import +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h" + @class GNCBLEL2CAPStream; @protocol GNCPeripheralManager; @@ -42,7 +44,7 @@ typedef void (^GNCOpenL2CAPServerChannelOpendCompletionHandler)(GNCBLEL2CAPStrea * * @note The public APIs of this class are thread safe. */ -@interface GNCBLEL2CAPServer : NSObject +@interface GNCBLEL2CAPServer : NSObject // Represents a PSM (Protocol/Service Multiplexer) value for an L2CAP channel. @property(atomic, readonly) CBL2CAPPSM PSM; @@ -57,6 +59,8 @@ typedef void (^GNCOpenL2CAPServerChannelOpendCompletionHandler)(GNCBLEL2CAPStrea - (instancetype)initWithPeripheralManager:(nullable id)peripheralManager queue:(nullable dispatch_queue_t)queue; +- (instancetype)init NS_UNAVAILABLE; + /** * Starts listening for an L2CAP channel. * diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.m b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.m index e33f458a..31065d9f 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.m +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.m @@ -17,6 +17,7 @@ #import #import +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEError.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPStream.h" @@ -43,21 +44,25 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP BOOL _alreadyStartedWhenPeripheralPoweredOff; } -- (instancetype)init { - return [self initWithPeripheralManager:nil queue:nil]; -} - -// This is private and should only be used for tests. The provided peripheral manager must call -// delegate methods on the main queue. - (instancetype)initWithPeripheralManager:(nullable id)peripheralManager queue:(nullable dispatch_queue_t)queue { self = [super init]; if (self) { _queue = queue ?: dispatch_queue_create(kGNCBLEL2CAPServerQueueLabel, DISPATCH_QUEUE_SERIAL); - if (peripheralManager) { + if (GNCFeatureFlags.sharedPeripheralManagerEnabled) { + if (!peripheralManager) { + // In shared mode, the peripheral manager must be injected. + [NSException raise:NSInvalidArgumentException + format:@"Peripheral manager cannot be nil when shared manager is enabled."]; + } _peripheralManager = peripheralManager; - // Set for @c GNCPeripheralManager to be able to forward callbacks. - _peripheralManager.peripheralDelegate = self; + // In shared mode, do NOT set the delegate. The Multiplexer handles callbacks. + } else { + if (peripheralManager) { + _peripheralManager = peripheralManager; + // Set for @c GNCPeripheralManager to be able to forward callbacks. + _peripheralManager.peripheralDelegate = self; + } } } return self; @@ -70,22 +75,42 @@ static char *const kGNCBLEL2CAPServerQueueLabel = "com.google.nearby.GNCBLEL2CAP channelOpenedCompletionHandler { _psmPublishedCompletionHandler = [psmPublishedCompletionHandler copy]; _channelOpenedCompletionHandler = [channelOpenedCompletionHandler copy]; - if (!_queue) { - _psmPublishedCompletionHandler(0, [NSError errorWithDomain:GNCBLEErrorDomain - code:GNCBLEErrorL2CAPListeningOnQueueNil - userInfo:nil]); - return; - } - if (!_peripheralManager) { - // Lazy initialization to avoid system dialog on app startup before pairing. - _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil - queue:_queue - options:nil]; + if (GNCFeatureFlags.sharedPeripheralManagerEnabled) { + if (!_queue) { + if (_psmPublishedCompletionHandler) { + _psmPublishedCompletionHandler(0, + [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorL2CAPListeningOnQueueNil + userInfo:nil]); + } + return; + } + if (!_peripheralManager) { + GNCLoggerError(@"[NEARBY] Peripheral manager must not be nil."); + return; + } + } else { + if (!_queue) { + _psmPublishedCompletionHandler(0, [NSError errorWithDomain:GNCBLEErrorDomain + code:GNCBLEErrorL2CAPListeningOnQueueNil + userInfo:nil]); + return; + } + if (!_peripheralManager) { + // Lazy initialization to avoid system dialog on app startup before pairing. + _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil + queue:_queue + options:nil]; - // Set for @c GNCPeripheralManager to be able to forward callbacks. - _peripheralManager.peripheralDelegate = self; + // Set for @c GNCPeripheralManager to be able to forward callbacks. + _peripheralManager.peripheralDelegate = self; + } } + if (_PSM > 0) { + GNCLoggerInfo((@"[NEARBY] Unpublish L2CAP channel with PSM: %@"), @(_PSM)); + [_peripheralManager unpublishL2CAPChannel:_PSM]; + } if (_peripheralManager.state == CBManagerStatePoweredOn) { // Bluetooth link is already encrypted, however encryption is not required here to avoid getting // insufficient authentication errors due to initialization order. diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h index 893fd32f..8e0df1fe 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h @@ -106,15 +106,6 @@ typedef void (^GNCGATTConnectionCompletionHandler)(GNCBLEGATTClient *_Nullable c */ - (instancetype)init; -/** - * Initializes the BLE medium with a custom central manager. - * - * @param centralManager The central manager to use for BLE operations. - * @param queue The queue to use for all internal operations. - */ -- (instancetype)initWithCentralManager:(id)centralManager - queue:(nullable dispatch_queue_t)queue; - /** The hardware supports BOTH advertising extensions and extended scans. */ @property(nonatomic, readonly) BOOL supportsExtendedAdvertisements; diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.m b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.m index a6276c3c..0fe0caca 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.m +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.m @@ -22,10 +22,10 @@ #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEError.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTClient.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h" -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPClient.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCCentralManager.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheral.h" +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h" #import "internal/platform/implementation/apple/Mediums/BLE/NSData+GNCBase85.h" #import "internal/platform/implementation/apple/Mediums/BLE/NSData+GNCWebSafeBase64.h" @@ -40,22 +40,17 @@ static NSError *AlreadyScanningError() { return [NSError errorWithDomain:GNCBLEErrorDomain code:GNCBLEErrorAlreadyScanning userInfo:nil]; } -static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( - id _Nullable peripheralManager) { - if (!peripheralManager) { - return [[GNCBLEL2CAPServer alloc] init]; - } else { - return [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:peripheralManager - queue:dispatch_get_main_queue()]; - } -} - @interface GNCBLEMedium () +- (instancetype)initWithCentralManager:(id)centralManager + peripheralManager:(nullable id)peripheralManager + queue:(dispatch_queue_t)queue; @end @implementation GNCBLEMedium { dispatch_queue_t _queue; id _centralManager; + id _peripheralManager; + GNCPeripheralManagerMultiplexer *_multiplexer; // The active GATT server, or @nil if one hasn't been started yet. GNCBLEGATTServer *_server; @@ -99,21 +94,31 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( - (instancetype)init { dispatch_queue_t queue = dispatch_queue_create(kBLEMediumQueueLabel, DISPATCH_QUEUE_SERIAL); CBCentralManager *centralManager = - [[CBCentralManager alloc] initWithDelegate:self + [[CBCentralManager alloc] initWithDelegate:nil queue:queue options:@{CBCentralManagerOptionShowPowerAlertKey : @NO}]; - return [self initWithCentralManager:centralManager queue:queue]; + CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:nil + queue:queue]; + return [self initWithCentralManager:centralManager + peripheralManager:peripheralManager + queue:queue]; } // This is private and should only be used for tests. The provided central manager must call // delegate methods on the main queue. - (instancetype)initWithCentralManager:(id)centralManager - queue:(nullable dispatch_queue_t)queue { + peripheralManager:(nullable id)peripheralManager + queue:(dispatch_queue_t)queue { self = [super init]; if (self) { - _queue = queue ?: dispatch_get_main_queue(); + _queue = queue; _centralManager = centralManager; _centralManager.centralDelegate = self; + _peripheralManager = peripheralManager; + if (GNCFeatureFlags.sharedPeripheralManagerEnabled && _peripheralManager) { + _multiplexer = [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:_queue]; + _peripheralManager.peripheralDelegate = _multiplexer; + } _gattConnectionCompletionHandlers = [NSMutableDictionary dictionary]; _gattDisconnectionHandlers = [NSMutableDictionary dictionary]; _scanningServiceUUIDs = [NSMutableArray array]; @@ -160,11 +165,27 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( return NO; } +- (void)dealloc { + [_centralManager stopScan]; + _centralManager.centralDelegate = nil; + + [_peripheralManager stopAdvertising]; + _peripheralManager.peripheralDelegate = nil; +} + - (void)startAdvertisingData:(NSDictionary *)serviceData completionHandler:(nullable GNCStartAdvertisingCompletionHandler)completionHandler { dispatch_async(_queue, ^{ if (!_server) { - _server = [[GNCBLEGATTServer alloc] init]; + if (GNCFeatureFlags.sharedPeripheralManagerEnabled) { + _server = [[GNCBLEGATTServer alloc] initWithPeripheralManager:_peripheralManager + queue:_queue]; + [_multiplexer addListener:_server]; + } else { + // In legacy mode, we pass nil (or a separate manager) and do NOT add to multiplexer. + // GNCBLEGATTServer will create its own internal manager. + _server = [[GNCBLEGATTServer alloc] initWithPeripheralManager:nil queue:nil]; + } } [_server startAdvertisingData:serviceData completionHandler:completionHandler]; }); @@ -206,7 +227,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( [_scanningServiceUUIDs addObjectsFromArray:serviceUUIDs]; _advertisementFoundHandler = advertisementFoundHandler; - [self internalStartScanningIfPoweredOn]; + [self updateScanningState]; if (completionHandler) { completionHandler(nil); } @@ -227,7 +248,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( - (void)resumeMediumScanning:(nullable GNCStartScanningCompletionHandler)completionHandler { dispatch_async(_queue, ^{ - [self internalStartScanningIfPoweredOn]; + [self updateScanningState]; if (completionHandler) { completionHandler(nil); } @@ -238,7 +259,13 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( (nullable GNCGATTServerCompletionHandler)completionHandler { dispatch_async(_queue, ^{ if (!_server) { - _server = [[GNCBLEGATTServer alloc] init]; + if (GNCFeatureFlags.sharedPeripheralManagerEnabled) { + _server = [[GNCBLEGATTServer alloc] initWithPeripheralManager:_peripheralManager + queue:_queue]; + [_multiplexer addListener:_server]; + } else { + _server = [[GNCBLEGATTServer alloc] initWithPeripheralManager:nil queue:nil]; + } } if (completionHandler) { completionHandler(_server, nil); @@ -284,7 +311,22 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( (nullable id)peripheralManager { dispatch_async(_queue, ^{ if (!_l2capServer) { - _l2capServer = CreateL2CapServer(peripheralManager); + if (GNCFeatureFlags.sharedPeripheralManagerEnabled) { + _l2capServer = [[GNCBLEL2CAPServer alloc] + initWithPeripheralManager:peripheralManager ?: _peripheralManager + queue:peripheralManager ? dispatch_get_main_queue() : _queue]; + // Only add to multiplexer if we are using the internal shared manager. + // If a specific manager was passed in (e.g. for testing?), we might still need logic here. + // But typically `peripheralManager` is nil in prod. + if (peripheralManager == nil || peripheralManager == _peripheralManager) { + [_multiplexer addListener:_l2capServer]; + } + } else { + // Legacy mode + _l2capServer = [[GNCBLEL2CAPServer alloc] + initWithPeripheralManager:peripheralManager // Likely nil, so Server creates new one + queue:peripheralManager ? dispatch_get_main_queue() : nil]; + } } [_l2capServer startListeningChannelWithPSMPublishedCompletionHandler:psmPublishedCompletionHandler @@ -335,7 +377,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( #pragma mark - Internal -- (void)internalStartScanningIfPoweredOn { +- (void)updateScanningState { dispatch_assert_queue(_queue); // Scanning can only be done when powered on and must be restarted if bluetooth is turned off // then back on. This will be called anytime the central manager's state changes, so @@ -463,7 +505,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( return; } dispatch_assert_queue(_queue); - [self internalStartScanningIfPoweredOn]; + [self updateScanningState]; } - (void)gnc_centralManager:(id)central @@ -480,6 +522,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( didConnectPeripheral:(id)peripheral { dispatch_assert_queue(_queue); [self cancelConnectionTimeout]; + if (_l2capPSM > 0) { [self internalOpenL2CAPChannel:peripheral]; return; @@ -525,6 +568,7 @@ static GNCBLEL2CAPServer *_Nonnull CreateL2CapServer( didDisconnectPeripheral:(id)peripheral error:(nullable NSError *)error { dispatch_assert_queue(_queue); + GNCGATTDisconnectionHandler handler = _gattDisconnectionHandlers[peripheral.identifier]; _gattDisconnectionHandlers[peripheral.identifier] = nil; if (handler) { diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCCentralManager.m b/internal/platform/implementation/apple/Mediums/BLE/GNCCentralManager.m index a86bfee6..7b642fce 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCCentralManager.m +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCCentralManager.m @@ -22,8 +22,10 @@ NS_ASSUME_NONNULL_BEGIN @implementation CBCentralManager (GNCCentralManagerAdditions) - (void)setCentralDelegate:(nullable id)centralDelegate { - NSAssert([centralDelegate conformsToProtocol:@protocol(CBCentralManagerDelegate)], - @"centralDelegate must conform to protocol CBCentralManagerDelegate"); + if (centralDelegate) { + NSAssert([centralDelegate conformsToProtocol:@protocol(CBCentralManagerDelegate)], + @"centralDelegate must conform to protocol CBCentralManagerDelegate"); + } self.delegate = (id)centralDelegate; } diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.h b/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.h index d5bc59d6..38bba6e2 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.h +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.h @@ -90,9 +90,11 @@ NSData *_Nullable GNCMGenerateBLEL2CAPPacket(GNCMBLEL2CAPCommand command, NSData /** * Calls the completion handler with (a) YES if the GNSSocket connected, or (b) NO if it failed to - * connect for any reason. The completion handler is called on the main queue. + * connect for any reason. The completion handler is called on the given queue. If the queue is nil, + * the completion handler is called on the main queue. */ -void GNCMWaitForConnection(GNSSocket *socket, GNCMBoolHandler completion); +void GNCMWaitForConnection(GNSSocket *socket, dispatch_queue_t _Nullable queue, + GNCMBoolHandler completion); #ifdef __cplusplus } // extern "C" diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.mm b/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.mm index 6c1c518d..c582ff11 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.mm +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCMBleUtils.mm @@ -235,18 +235,20 @@ NSData *_Nullable GNCMGenerateBLEL2CAPPacket(GNCMBLEL2CAPCommand command, NSData @end -void GNCMWaitForConnection(GNSSocket *socket, GNCMBoolHandler completion) { +void GNCMWaitForConnection(GNSSocket *socket, dispatch_queue_t _Nullable queue, + GNCMBoolHandler completion) { // This function passes YES to the completion when the socket has successfully connected, and // otherwise passes NO to the completion after a timeout of several seconds. We shouldn't retain // the completion after it's been called, so store it in a __block variable and nil it out once // the socket has connected. __block GNCMBoolHandler completionRef = completion; + dispatch_queue_t targetQueue = queue ?: dispatch_get_main_queue(); // The delegate listens for the socket connection callbacks. It's retained by the block passed to // dispatch_after below, so it will live long enough to do its job. GNCMBleSocketDelegate *delegate = [GNCMBleSocketDelegate delegateWithConnectedHandler:^(BOOL didConnect) { - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(targetQueue, ^{ if (completionRef) completionRef(didConnect); completionRef = nil; }); @@ -254,9 +256,10 @@ void GNCMWaitForConnection(GNSSocket *socket, GNCMBoolHandler completion) { socket.delegate = delegate; dispatch_after( dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kBleSocketConnectionTimeout * NSEC_PER_SEC)), - dispatch_get_main_queue(), ^{ + targetQueue, ^{ (void)delegate; // make sure it's retained until the timeout if (completionRef) completionRef(NO); + completionRef = nil; }); } diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h b/internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h new file mode 100644 index 00000000..74129d02 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h @@ -0,0 +1,49 @@ +// Copyright 2026 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. + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A multiplexer that forwards @c CBPeripheralManagerDelegate and @c GNCPeripheralManagerDelegate + */ +@interface GNCPeripheralManagerMultiplexer : NSObject + +/** + * Initializes the multiplexer. + * + * @param callbackQueue The queue to use for forwarding delegate callbacks. + */ +- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Adds a listener to the multiplexer. Listeners are held weakly. + * + * @param listener The listener to add. + */ +- (void)addListener:(id)listener; + +/** + * Removes a listener from the multiplexer. + * + * @param listener The listener to remove. + */ +- (void)removeListener:(id)listener; + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.m b/internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.m new file mode 100644 index 00000000..56d69774 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.m @@ -0,0 +1,194 @@ +// Copyright 2026 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. + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h" + +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation GNCPeripheralManagerMultiplexer { + NSHashTable> *_listeners; + dispatch_queue_t _callbackQueue; + dispatch_queue_t _syncQueue; +} + +- (instancetype)initWithCallbackQueue:(dispatch_queue_t)callbackQueue { + self = [super init]; + if (self) { + _listeners = [NSHashTable weakObjectsHashTable]; + _callbackQueue = callbackQueue; + _syncQueue = dispatch_queue_create("com.google.nearby.GNCPeripheralManagerMultiplexerSync", + DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (instancetype)init { + return [self initWithCallbackQueue:dispatch_get_main_queue()]; +} + +- (void)addListener:(id)listener { + dispatch_async(_syncQueue, ^{ + [self->_listeners addObject:listener]; + }); +} + +- (void)removeListener:(id)listener { + dispatch_async(_syncQueue, ^{ + [self->_listeners removeObject:listener]; + }); +} + +- (NSArray> *)allListeners { + __block NSArray> *listeners; + dispatch_sync(_syncQueue, ^{ + listeners = [self->_listeners allObjects]; + }); + return listeners; +} + +#pragma mark - GNCPeripheralManagerDelegate + +- (void)gnc_peripheralManagerDidUpdateState:(id)peripheral { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + [listener gnc_peripheralManagerDidUpdateState:peripheral]; + } + }); +} + +- (void)gnc_peripheralManagerDidStartAdvertising:(id)peripheral + error:(nullable NSError *)error { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + if ([listener respondsToSelector:@selector(gnc_peripheralManagerDidStartAdvertising:error:)]) { + [listener gnc_peripheralManagerDidStartAdvertising:peripheral error:error]; + } + } + }); +} + +- (void)gnc_peripheralManager:(id)peripheral + didAddService:(CBService *)service + error:(nullable NSError *)error { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + if ([listener respondsToSelector:@selector(gnc_peripheralManager:didAddService:error:)]) { + [listener gnc_peripheralManager:peripheral didAddService:service error:error]; + } + } + }); +} + +- (void)gnc_peripheralManager:(id)peripheral + didReceiveReadRequest:(CBATTRequest *)request { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + if ([listener respondsToSelector:@selector(gnc_peripheralManager:didReceiveReadRequest:)]) { + [listener gnc_peripheralManager:peripheral didReceiveReadRequest:request]; + } + } + }); +} + +- (void)gnc_peripheralManager:(id)peripheral + didPublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(nullable NSError *)error { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + if ([listener respondsToSelector:@selector(gnc_peripheralManager:didPublishL2CAPChannel:error:)]) { + [listener gnc_peripheralManager:peripheral didPublishL2CAPChannel:PSM error:error]; + } + } + }); +} + +- (void)gnc_peripheralManager:(id)peripheral + didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(NSError *)error { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + if ([listener respondsToSelector:@selector(gnc_peripheralManager:didUnpublishL2CAPChannel:error:)]) { + [listener gnc_peripheralManager:peripheral didUnpublishL2CAPChannel:PSM error:error]; + } + } + }); +} + +- (void)gnc_peripheralManager:(id)peripheral + didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel + error:(nullable NSError *)error { + NSArray> *listeners = [self allListeners]; + dispatch_async(_callbackQueue, ^{ + for (id listener in listeners) { + if ([listener respondsToSelector:@selector(gnc_peripheralManager:didOpenL2CAPChannel:error:)]) { + [listener gnc_peripheralManager:peripheral didOpenL2CAPChannel:channel error:error]; + } + } + }); +} + +#pragma mark - CBPeripheralManagerDelegate + +- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral { + [self gnc_peripheralManagerDidUpdateState:peripheral]; +} + +- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral + error:(nullable NSError *)error { + [self gnc_peripheralManagerDidStartAdvertising:peripheral error:error]; +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didAddService:(CBService *)service + error:(nullable NSError *)error { + [self gnc_peripheralManager:peripheral didAddService:service error:error]; +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didReceiveReadRequest:(CBATTRequest *)request { + [self gnc_peripheralManager:peripheral didReceiveReadRequest:request]; +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didPublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(nullable NSError *)error { + [self gnc_peripheralManager:peripheral didPublishL2CAPChannel:PSM error:error]; +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(nullable NSError *)error { + [self gnc_peripheralManager:peripheral didUnpublishL2CAPChannel:PSM error:error]; +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel + error:(nullable NSError *)error { + [self gnc_peripheralManager:peripheral didOpenL2CAPChannel:channel error:error]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/internal/platform/implementation/apple/Mediums/BLE/Sockets/BUILD b/internal/platform/implementation/apple/Mediums/BLE/Sockets/BUILD index 97954b96..0146d5a8 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Sockets/BUILD +++ b/internal/platform/implementation/apple/Mediums/BLE/Sockets/BUILD @@ -30,9 +30,6 @@ objc_library( ]) + [ "Source/GNSCentral.h", ], - copts = [ - "-Wno-enum-compare", # TODO(b/418286948): Remove this when the error is fixed. - ], deps = [ ":Shared", "//internal/platform/implementation/apple/Log:GNCLogger", @@ -51,9 +48,6 @@ objc_library( ]) + [ "Source/GNSPeripheral.h", ], - copts = [ - "-Wno-enum-compare", # TODO(b/418286948): Remove this when the error is fixed. - ], deps = [ ":Shared", "//internal/platform/implementation/apple/Log:GNCLogger", diff --git a/internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralManager.m b/internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralManager.m index d58d1759..af6e7e8b 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralManager.m +++ b/internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralManager.m @@ -371,7 +371,7 @@ static NSTimeInterval gKBTCrashLoopMaxTimeBetweenResetting = 15.f; } - (void)updateBTCrashLoopHeuristic { - NSAssert(_cbPeripheralManager.state == CBCentralManagerStateResetting, @"Unexpected CB state %@", + NSAssert(_cbPeripheralManager.state == CBManagerStateResetting, @"Unexpected CB state %@", CBManagerStateString(_cbPeripheralManager.state)); NSDate *now = [NSDate date]; if ([now timeIntervalSinceDate:_btCrashLastResettingDate] > diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/BUILD b/internal/platform/implementation/apple/Mediums/BLE/Tests/BUILD index 86e1be56..520b9014 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/BUILD +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/BUILD @@ -26,13 +26,13 @@ objc_library( srcs = [ "GNCBLEGATTCharacteristicTest.mm", "GNCBLEGATTClientTest.m", - "GNCBLEGATTServerTest.m", + "GNCBLEGATTServerTest.mm", "GNCBLEL2CAPClientTest.m", "GNCBLEL2CAPConnectionTest.m", "GNCBLEL2CAPFakeInputOutputStream.m", - "GNCBLEL2CAPServerTest.m", + "GNCBLEL2CAPServerTest.mm", "GNCBLEL2CAPStreamTest.m", - "GNCBLEMediumTest.m", + "GNCBLEMediumTest.mm", "GNCFakeBLEGATTServer.m", "GNCFakeBLEMedium.m", "GNCFakeCBL2CAPChannel.m", @@ -44,6 +44,7 @@ objc_library( "GNCMBleUtilsTest.m", "GNCMConnectionsTest.m", "GNCMFakeConnection.mm", + "GNCPeripheralManagerMultiplexerTest.m", "GNCPeripheralManagerTest.m", "GNCPeripheralTest.m", "NSData+GNCBase85Test.m", @@ -66,6 +67,8 @@ objc_library( "GNCMFakeConnection.h", ], deps = [ + "//connections/implementation/flags:connections_flags", + "//internal/flags:nearby_flags", "//internal/platform/implementation/apple", # buildcleaner: keep "//internal/platform/implementation/apple/Mediums/BLE", "//internal/platform/implementation/apple/Mediums/BLE/Sockets:Shared", diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServerTest.m b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServerTest.mm similarity index 60% rename from internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServerTest.m rename to internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServerTest.mm index f6bfac51..8e4882fd 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServerTest.m +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServerTest.mm @@ -22,6 +22,9 @@ #import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEGATTServer+Testing.h" #import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "internal/flags/nearby_flags.h" + static NSString *const kServiceUUID1 = @"0000FEF3-0000-1000-8000-00805F9B34FB"; static NSString *const kServiceUUID2 = @"0000FEF4-0000-1000-8000-00805F9B34FB"; static NSString *const kCharacteristicUUID1 = @"00000000-0000-3000-8000-000000000000"; @@ -34,11 +37,60 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 #pragma mark - Create Characteristic -- (void)testCreateCharacteristic { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; +- (void)tearDown { + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); + [super tearDown]; +} - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; +- (void)testInit_setsDelegateCorrectlyBasedOnFlag { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEGATTServer *server = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + + if (enabled.boolValue) { + // In shared mode, functionality is delegated to the multiplexer, so the server should NOT + // self-assign as delegate. + XCTAssertNil(fakePeripheralManager.peripheralDelegate); + } else { + // In legacy mode, the server owns the manager and sets itself as delegate. + XCTAssertEqual(fakePeripheralManager.peripheralDelegate, server); + } + } +} + +- (void)testInit_throwsWithNilManagerWhenFlagEnabled { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + true); + + XCTAssertThrowsSpecificNamed( + [[GNCBLEGATTServer alloc] initWithPeripheralManager:(id)nil + queue:dispatch_get_main_queue()], + NSException, NSInvalidArgumentException); +} + +- (void)testCreateCharacteristic { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -62,13 +114,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testCreateMultipleCharacteristicsForOneService { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -105,13 +167,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [self waitForExpectations:@[ expectation1, expectation2 ] timeout:3]; XCTAssertEqual(fakePeripheralManager.services.count, 1); XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 2); + } } - (void)testCreateDuplicateCharacteristics { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -140,13 +212,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [self waitForExpectations:@[ expectation ] timeout:3]; XCTAssertEqual(fakePeripheralManager.services.count, 1); XCTAssertEqual(fakePeripheralManager.services[0].characteristics.count, 1); + } } - (void)testCreateDuplicatePendingCharacteristics { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; @@ -171,13 +253,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testCreateCharacteristicNotPoweredOn { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; @@ -198,13 +290,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testCreateCharacteristicServiceFailure { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } fakePeripheralManager.didAddServiceError = [NSError errorWithDomain:@"fake" code:0 userInfo:nil]; [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -228,15 +330,25 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } #pragma mark - Read Request - (void)testReadRequest { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -265,14 +377,24 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 characteristic:characteristicUUID]; [self waitForExpectations:@[ fakePeripheralManager.respondToRequestSuccessExpectation ] - timeout:0]; + timeout:3]; + } } -- (void)testReadRequestInvalidService { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; +- (void)testReadRequestInvalidCharacteristic { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -296,73 +418,106 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 [self waitForExpectations:@[ expectation ] timeout:3]; + CBUUID *invalidCharacteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID2]; + + [fakePeripheralManager + simulatePeripheralManagerDidReceiveReadRequestForService:serviceUUID + characteristic:invalidCharacteristicUUID]; + + [self waitForExpectations:@[ fakePeripheralManager.respondToRequestErrorExpectation ] timeout:3]; + } +} + +- (void)testReadRequestInvalidService { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Create characteristic."]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; + CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; + [gattServer createCharacteristicWithServiceID:serviceUUID + characteristicUUID:characteristicUUID + permissions:CBAttributePermissionsReadable + properties:CBCharacteristicPropertyRead + completionHandler:^(GNCBLEGATTCharacteristic *characteristic, + NSError *error) { + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + CBUUID *invalidServiceUUID = [CBUUID UUIDWithString:kServiceUUID2]; + // Expectation that we *should not* receive a response. + fakePeripheralManager.respondToRequestSuccessExpectation.inverted = YES; + fakePeripheralManager.respondToRequestErrorExpectation.inverted = YES; + [fakePeripheralManager simulatePeripheralManagerDidReceiveReadRequestForService:invalidServiceUUID characteristic:characteristicUUID]; - [self waitForExpectations:@[ fakePeripheralManager.respondToRequestErrorExpectation ] timeout:0]; -} - -- (void)testReadRequestInvalidCharacteristic { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Create and update characteristic."]; - - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID1]; - CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID1]; - [gattServer createCharacteristicWithServiceID:serviceUUID - characteristicUUID:characteristicUUID - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyRead - completionHandler:^(GNCBLEGATTCharacteristic *characteristic, - NSError *error) { - [gattServer updateCharacteristic:characteristic - value:[NSData data] - completionHandler:^(NSError *error) { - [expectation fulfill]; - }]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; - - CBUUID *invalidCharacteristicUUID = - [CBUUID UUIDWithString:kCharacteristicUUID2]; - - [fakePeripheralManager - simulatePeripheralManagerDidReceiveReadRequestForService:serviceUUID - characteristic:invalidCharacteristicUUID]; - - [self waitForExpectations:@[ fakePeripheralManager.respondToRequestErrorExpectation ] timeout:0]; + [self waitForExpectations:@[ + fakePeripheralManager.respondToRequestSuccessExpectation, + fakePeripheralManager.respondToRequestErrorExpectation + ] + timeout:3]; + } } #pragma mark - Stop - (void)testStop { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } - [gattServer stop]; + [gattServer stop]; - XCTAssertEqual(fakePeripheralManager.services.count, 0); + XCTAssertEqual(fakePeripheralManager.services.count, 0); + } } #pragma mark - Start Advertising - (void)testStartAdvertisingNoServiceData { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -377,13 +532,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingEmptyServiceData { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -402,13 +567,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingShortServiceData { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -429,13 +604,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertising20ByteServiceData { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -457,13 +642,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingLongServiceData { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -482,13 +677,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingWithEmojiServiceData { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -510,13 +715,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingMultipleServices { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -536,13 +751,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingNotPoweredOn { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; @@ -556,13 +781,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingStartFailure { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } fakePeripheralManager.didStartAdvertisingError = [NSError errorWithDomain:@"fake" code:0 @@ -581,13 +816,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartAdvertisingAlreadyAdvertising { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } fakePeripheralManager.didStartAdvertisingError = [NSError errorWithDomain:@"fake" code:0 @@ -608,13 +853,23 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } - (void)testStartStopStartAdvertising { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEGATTServer *gattServer = - [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager]; + GNCBLEGATTServer *gattServer = + [[GNCBLEGATTServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = gattServer; + } [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; @@ -648,6 +903,9 @@ static NSString *const kCharacteristicUUID2 = @"00000000-0000-3000-8000-00000000 }]; [self waitForExpectations:@[ expectation ] timeout:3]; + } } @end + + diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServerTest.m b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServerTest.m deleted file mode 100644 index 2380d287..00000000 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServerTest.m +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2025 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. - -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h" - -#import -#import -#import - -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServer+Testing.h" -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" - -static const NSTimeInterval kTestTimeout = 1.0; - -@interface GNCBLEL2CAPServerTest : XCTestCase -@end - -@implementation GNCBLEL2CAPServerTest - -#pragma mark Tests - -- (void)testInit { - GNCBLEL2CAPServer *l2capServer = [[GNCBLEL2CAPServer alloc] init]; - XCTAssertNotNil(l2capServer); - XCTAssertNil([l2capServer valueForKey:@"_peripheralManager"]); -} - -- (void)testPublishL2CAPChannelAndOpenChannelWhenStartListeningChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *psmPublishedExpectation = - [[XCTestExpectation alloc] initWithDescription:@"PSM published."]; - XCTestExpectation *channelOpenedexpectation = - [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, nil); - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - [psmPublishedExpectation fulfill]; - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error) { - XCTAssertNil(error); - XCTAssertNotNil(stream); - [channelOpenedexpectation fulfill]; - }]; - [self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ] - timeout:kTestTimeout]; - XCTAssertNotNil([l2capServer valueForKey:@"l2CAPChannel"]); - XCTAssertNotNil([l2capServer valueForKey:@"l2CAPStream"]); -} - -- (void)testFailedToPublishL2CAPChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - fakePeripheralManager.didPublishL2CAPChannelError = [NSError errorWithDomain:@"fake" - code:0 - userInfo:nil]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *psmPublishedExpectation = - [[XCTestExpectation alloc] initWithDescription:@"PSM published with error."]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, fakePeripheralManager.didPublishL2CAPChannelError); - XCTAssertEqual(PSM, 0); - [psmPublishedExpectation fulfill]; - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - [self waitForExpectations:@[ psmPublishedExpectation ] timeout:kTestTimeout]; -} - -- (void)testPoweredOffUnpublishesChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, nil); - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOff]; - - [self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout]; -} - -- (void)testPeripheralManagerDidUpdateStatePoweredOffUnpublishesChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - fakePeripheralManager.state = CBManagerStatePoweredOn; - [(id)l2capServer - peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, nil); - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - - fakePeripheralManager.state = CBManagerStatePoweredOff; - [(id)l2capServer - peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager]; - - [self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout]; -} - -- (void)testStartPeripheralManagerInitiallyOff { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *psmPublishedExpectation = - [[XCTestExpectation alloc] initWithDescription:@"PSM published."]; - XCTestExpectation *channelOpenedexpectation = - [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, nil); - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - [psmPublishedExpectation fulfill]; - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error) { - [channelOpenedexpectation fulfill]; - }]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - [self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ] - timeout:kTestTimeout]; -} - -- (void)testClose { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, nil); - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - - [l2capServer close]; - - XCTAssertEqual([l2capServer PSM], 0); -} - -- (void)testCloseDoesNotUnpublishesChannelIfNotConnected { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - fakePeripheralManager.unpublishExpectation.inverted = YES; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - - [l2capServer close]; - - [self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout]; -} - -- (void)testFailedToOpenL2CAPChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - fakePeripheralManager.didOpenL2CAPChannelError = [NSError errorWithDomain:@"fake" - code:0 - userInfo:nil]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *channelOpenedexpectation = - [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(error, nil); - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error) { - XCTAssertNil(stream); - XCTAssertEqual(error, fakePeripheralManager.didOpenL2CAPChannelError); - [channelOpenedexpectation fulfill]; - }]; - [self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout]; - XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]); - XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]); -} - -- (void)testPeripheralManagerDidUnpublishL2CAPChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - - [(id)l2capServer - peripheralManager:(CBPeripheralManager *)fakePeripheralManager - didUnpublishL2CAPChannel:l2capServer.PSM - error:[NSError errorWithDomain:@"fake" code:0 userInfo:nil]]; - - XCTAssertEqual(l2capServer.PSM, 0); -} - -- (void)testCloseL2CAPChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *channelOpenedexpectation = - [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error) { - [channelOpenedexpectation fulfill]; - }]; - [self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout]; - - [l2capServer closeL2CAPChannel]; - - XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]); - XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]); -} - -- (void)testPeripheralManagerDidPublishL2CAPChannel { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"completion called"]; - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(PSM, 1); - XCTAssertNil(error); - [expectation fulfill]; - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - [(id)l2capServer - peripheralManager:(CBPeripheralManager *)fakePeripheralManager - didPublishL2CAPChannel:1 - error:nil]; - [self waitForExpectations:@[ expectation ] timeout:kTestTimeout]; - XCTAssertEqual(l2capServer.PSM, 1); -} - -- (void)testPeripheralManagerDidPublishL2CAPChannelWithError { - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEL2CAPServer *l2capServer = - [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager - queue:dispatch_get_main_queue()]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"completion called"]; - NSError *publishError = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; - [l2capServer - startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, - NSError *_Nullable error) { - XCTAssertEqual(PSM, 0); - XCTAssertEqualObjects(error, publishError); - [expectation fulfill]; - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, - NSError *_Nullable error){ - }]; - [(id)l2capServer - peripheralManager:(CBPeripheralManager *)fakePeripheralManager - didPublishL2CAPChannel:0 - error:publishError]; - [self waitForExpectations:@[ expectation ] timeout:kTestTimeout]; - XCTAssertEqual(l2capServer.PSM, 0); -} - -@end diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServerTest.mm b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServerTest.mm new file mode 100644 index 00000000..2d2fabda --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServerTest.mm @@ -0,0 +1,485 @@ +// Copyright 2025 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. + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPServer.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPServer+Testing.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" + +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "internal/flags/nearby_flags.h" + +static const NSTimeInterval kTestTimeout = 1.0; + +@interface GNCBLEL2CAPServerTest : XCTestCase +@end + +@implementation GNCBLEL2CAPServerTest + +#pragma mark Tests + +- (void)tearDown { + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); + [super tearDown]; +} + +- (void)testInit_setsDelegateCorrectlyBasedOnFlag { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *server = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + + if (enabled.boolValue) { + // In shared mode, functionality is delegated to the multiplexer, so the server should NOT + // self-assign as delegate. + XCTAssertNil(fakePeripheralManager.peripheralDelegate); + } else { + // In legacy mode, the server owns the manager and sets itself as delegate. + XCTAssertEqual(fakePeripheralManager.peripheralDelegate, server); + } + } +} + +- (void)testInit_throwsWithNilManagerWhenFlagEnabled { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + true); + + XCTAssertThrowsSpecificNamed( + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:(id)nil + queue:dispatch_get_main_queue()], + NSException, NSInvalidArgumentException); +} + +- (void)testPublishL2CAPChannelAndOpenChannelWhenStartListeningChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *psmPublishedExpectation = + [[XCTestExpectation alloc] initWithDescription:@"PSM published."]; + XCTestExpectation *channelOpenedexpectation = + [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, nil); + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + [psmPublishedExpectation fulfill]; + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error) { + XCTAssertNil(error); + XCTAssertNotNil(stream); + [channelOpenedexpectation fulfill]; + }]; + [self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ] + timeout:kTestTimeout]; + XCTAssertNotNil([l2capServer valueForKey:@"l2CAPChannel"]); + XCTAssertNotNil([l2capServer valueForKey:@"l2CAPStream"]); + } +} + +- (void)testFailedToPublishL2CAPChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + fakePeripheralManager.didPublishL2CAPChannelError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *psmPublishedExpectation = + [[XCTestExpectation alloc] initWithDescription:@"PSM published with error."]; + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, fakePeripheralManager.didPublishL2CAPChannelError); + XCTAssertEqual(PSM, 0); + [psmPublishedExpectation fulfill]; + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + [self waitForExpectations:@[ psmPublishedExpectation ] timeout:kTestTimeout]; + } +} + +- (void)testPoweredOffUnpublishesChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, nil); + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOff]; + + [self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout]; + } +} + +- (void)testPeripheralManagerDidUpdateStatePoweredOffUnpublishesChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + fakePeripheralManager.state = CBManagerStatePoweredOn; + [(id)l2capServer + peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, nil); + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + + fakePeripheralManager.state = CBManagerStatePoweredOff; + [(id)l2capServer + peripheralManagerDidUpdateState:(CBPeripheralManager *)fakePeripheralManager]; + + [self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout]; + } +} + +- (void)testStartPeripheralManagerInitiallyOff { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *psmPublishedExpectation = + [[XCTestExpectation alloc] initWithDescription:@"PSM published."]; + XCTestExpectation *channelOpenedexpectation = + [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, nil); + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + [psmPublishedExpectation fulfill]; + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error) { + [channelOpenedexpectation fulfill]; + }]; + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + [self waitForExpectations:@[ psmPublishedExpectation, channelOpenedexpectation ] + timeout:kTestTimeout]; + } +} + +- (void)testClose { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, nil); + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + + [l2capServer close]; + + XCTAssertEqual([l2capServer PSM], 0); + } +} + +- (void)testCloseDoesNotUnpublishesChannelIfNotConnected { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + fakePeripheralManager.unpublishExpectation.inverted = YES; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + [l2capServer close]; + + [self waitForExpectations:@[ fakePeripheralManager.unpublishExpectation ] timeout:kTestTimeout]; + } +} + +- (void)testFailedToOpenL2CAPChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + fakePeripheralManager.didOpenL2CAPChannelError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *channelOpenedexpectation = + [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(error, nil); + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error) { + XCTAssertNil(stream); + XCTAssertEqual(error, fakePeripheralManager.didOpenL2CAPChannelError); + [channelOpenedexpectation fulfill]; + }]; + [self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout]; + XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]); + XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]); + } +} + +- (void)testPeripheralManagerDidUnpublishL2CAPChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + + [(id)l2capServer + peripheralManager:(CBPeripheralManager *)fakePeripheralManager + didUnpublishL2CAPChannel:l2capServer.PSM + error:[NSError errorWithDomain:@"fake" code:0 userInfo:nil]]; + + XCTAssertEqual(l2capServer.PSM, 0); + } +} + +- (void)testCloseL2CAPChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *channelOpenedexpectation = + [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error) { + [channelOpenedexpectation fulfill]; + }]; + [self waitForExpectations:@[ channelOpenedexpectation ] timeout:kTestTimeout]; + + [l2capServer closeL2CAPChannel]; + + XCTAssertNil([l2capServer valueForKey:@"l2CAPChannel"]); + XCTAssertNil([l2capServer valueForKey:@"l2CAPStream"]); + } +} + +- (void)testPeripheralManagerDidPublishL2CAPChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"completion called"]; + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(PSM, 1); + XCTAssertNil(error); + [expectation fulfill]; + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + [(id)l2capServer + peripheralManager:(CBPeripheralManager *)fakePeripheralManager + didPublishL2CAPChannel:1 + error:nil]; + [self waitForExpectations:@[ expectation ] timeout:kTestTimeout]; + XCTAssertEqual(l2capServer.PSM, 1); + } +} + +- (void)testPeripheralManagerDidPublishL2CAPChannelWithError { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEL2CAPServer *l2capServer = + [[GNCBLEL2CAPServer alloc] initWithPeripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + if (enabled.boolValue) { + fakePeripheralManager.peripheralDelegate = l2capServer; + } + + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"completion called"]; + NSError *publishError = [NSError errorWithDomain:@"test" code:0 userInfo:nil]; + [l2capServer + startListeningChannelWithPSMPublishedCompletionHandler:^(uint16_t PSM, + NSError *_Nullable error) { + XCTAssertEqual(PSM, 0); + XCTAssertEqualObjects(error, publishError); + [expectation fulfill]; + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *_Nullable stream, + NSError *_Nullable error){ + }]; + [(id)l2capServer + peripheralManager:(CBPeripheralManager *)fakePeripheralManager + didPublishL2CAPChannel:0 + error:publishError]; + [self waitForExpectations:@[ expectation ] timeout:kTestTimeout]; + XCTAssertEqual(l2capServer.PSM, 0); + } +} + +@end + diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h index 5da28b57..9761a796 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h @@ -24,16 +24,19 @@ NS_ASSUME_NONNULL_BEGIN @interface GNCBLEMedium (Testing) /** - * Creates a BLE Medium with a provided central manager. + * Creates a BLE Medium with a provided central manager and peripheral manager. * - * This is only exposed for testing and can be used to inject a fake central manager. + * This is only exposed for tests and can be used to inject a fake central manager and + * peripheral manager. * * @param centralManager The central manager instance. + * @param peripheralManager The peripheral manager instance. * @param queue The queue to run on, this must match the queue that the central manager's delegate - * is running on. Defaults to the main queue when @c nil. + * is running on. */ - (instancetype)initWithCentralManager:(id)centralManager - queue:(nullable dispatch_queue_t)queue; + peripheralManager:(nullable id)peripheralManager + queue:(dispatch_queue_t)queue; - (NSDictionary *)decodeAdvertisementData: (NSDictionary *)advertisementData; diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMediumTest.m b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMediumTest.m deleted file mode 100644 index 10b623d9..00000000 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMediumTest.m +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 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. -// 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. - -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h" - -#import -#import -#import - -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTClient.h" -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h" -#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheral.h" -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPClient+Testing.h" -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h" -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCentralManager.h" -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheral.h" -#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" - -static NSString *const kServiceUUID = @"0000FEF3-0000-1000-8000-00805F9B34FB"; - -@interface GNCBLEMediumTest : XCTestCase -@end - -@implementation GNCBLEMediumTest - -#pragma mark - Supports Extended Advertisements - -- (void)testSupportsExtendedAdvertisements { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - - XCTAssertFalse([medium supportsExtendedAdvertisements]); -} - -#pragma mark - Start Scanning - -- (void)testStartScanning { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *startScanningExpectation = - [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; - XCTestExpectation *advertisementFoundExpectation = - [[XCTestExpectation alloc] initWithDescription:@"Advertisement found."]; - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; - - [fakeCentralManager simulateCentralManagerDidUpdateState:CBManagerStatePoweredOn]; - - [medium startScanningForService:serviceUUID - advertisementFoundHandler:^(id peripheral, - NSDictionary *data) { - NSDictionary *expected = @{ - serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], - }; - XCTAssertEqualObjects(expected, data); - [advertisementFoundExpectation fulfill]; - } - completionHandler:^(NSError *error) { - XCTAssertNil(error); - [startScanningExpectation fulfill]; - }]; - - [self waitForExpectations:@[ startScanningExpectation ] timeout:3]; - - XCTAssertEqualObjects(@[ serviceUUID ], fakeCentralManager.serviceUUIDs); - - [fakeCentralManager - simulateCentralManagerDidDiscoverPeripheral:[[GNCFakePeripheral alloc] init] - advertisementData:@{ - CBAdvertisementDataLocalNameKey : @"dGVzdA", - CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], - }]; - - [self waitForExpectations:@[ advertisementFoundExpectation ] timeout:3]; -} - -- (void)testAlreadyScanning { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; - - [medium startScanningForService:[CBUUID UUIDWithString:kServiceUUID] - advertisementFoundHandler:^(id peripheral, - NSDictionary *data) { - } - completionHandler:nil]; - - [medium startScanningForService:[CBUUID UUIDWithString:kServiceUUID] - advertisementFoundHandler:^(id peripheral, - NSDictionary *data) { - } - completionHandler:^(NSError *error) { - XCTAssertNotNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -- (void)testStartStopStartScanning { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; - - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; - - [medium startScanningForService:serviceUUID - advertisementFoundHandler:^(id peripheral, - NSDictionary *data) { - } - completionHandler:^(NSError *error) { - XCTAssertNil(error); - [medium stopScanningWithCompletionHandler:^(NSError *error) { - XCTAssertNil(error); - [medium startScanningForService:serviceUUID - advertisementFoundHandler:^(id peripheral, - NSDictionary *data) { - } - completionHandler:^(NSError *error) { - XCTAssertNil(error); - [expectation fulfill]; - }]; - }]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -#pragma mark - Decode Advertisement Data - -- (void)testDecodeAndroidStyleAdvertisementData { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; - - NSDictionary *expected = @{ - serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], - }; - - NSDictionary *data = @{ - CBAdvertisementDataServiceDataKey : @{ - serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], - }, - }; - NSDictionary *actual = [medium decodeAdvertisementData:data]; - - XCTAssertEqualObjects(expected, actual); -} - -- (void)testDecodeAndroidStyleAdvertisementDataWithLocalName { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; - - NSDictionary *expected = @{ - serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], - }; - - NSDictionary *data = @{ - CBAdvertisementDataLocalNameKey : @"Nearby", // Just happens to be base64 decodable. - CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], - CBAdvertisementDataServiceDataKey : @{ - serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], - }, - }; - NSDictionary *actual = [medium decodeAdvertisementData:data]; - - XCTAssertEqualObjects(expected, actual); -} - -- (void)testDecodeAppleStyleAdvertisementData { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; - - NSDictionary *expected = @{ - serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], - }; - - NSDictionary *data = @{ - CBAdvertisementDataLocalNameKey : @"dGVzdA", - CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], - }; - NSDictionary *actual = [medium decodeAdvertisementData:data]; - - XCTAssertEqualObjects(expected, actual); -} - -- (void)testDecodeInvalidAdvertisementData { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; - - NSDictionary *data = @{ - CBAdvertisementDataLocalNameKey : @"!@#$", - CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], - }; - NSDictionary *actual = [medium decodeAdvertisementData:data]; - - XCTAssertEqualObjects(@{}, actual); -} - -- (void)testDecodeEmptyAdvertisementData { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - - NSDictionary *actual = [medium decodeAdvertisementData:@{}]; - - XCTAssertEqualObjects(@{}, actual); -} - -#pragma mark - Start GATT Server - -- (void)testStartGATTServer { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Start GATT server."]; - - [medium startGATTServerWithCompletionHandler:^(GNCBLEGATTServer *server, NSError *error) { - XCTAssertNotNil(server); - XCTAssertNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -#pragma mark - Start Advertising - -- (void)testStartAdvertising { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; - - // Start advertising is fully covered with @c GNCBLEGATTServer tests. We are passing invalid - // advertising data here so we can test code paths relevant to @c GNCBLEMedium, but bail early - // enough to avoid making actual CoreBluetooth calls. - [medium startAdvertisingData:@{} - completionHandler:^(NSError *error) { - XCTAssertNotNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -- (void)testStopAdvertising { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Stop advertising."]; - - // Stop advertising is fully covered with @c GNCBLEGATTServer tests. We are only testing stopping - // without having started which tests the code paths relevant to @c GNCBLEMedium. - [medium stopAdvertisingWithCompletionHandler:^(NSError *error) { - XCTAssertNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -#pragma mark - Open L2CAP Channel - -- (void)testOpenL2CAPServerSocket { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *psmPublishedexpectation = - [[XCTestExpectation alloc] initWithDescription:@"PSM published."]; - XCTestExpectation *channelOpenedexpectation = - [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; - - [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; - - // Open L2CAP server is fully covered with @c GNCBLEL2CAPServer tests. - [medium - openL2CAPServerWithPSMPublishedCompletionHandler:^(uint16_t PSM, NSError *error) { - XCTAssertEqual(PSM, fakePeripheralManager.PSM); - XCTAssertNil(error); - [psmPublishedexpectation fulfill]; - } - channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *stream, NSError *error) { - XCTAssertNil(error); - [channelOpenedexpectation fulfill]; - } - peripheralManager:fakePeripheralManager]; - - [self waitForExpectations:@[ psmPublishedexpectation ] timeout:0.1]; - [self waitForExpectations:@[ channelOpenedexpectation ] timeout:0.5]; -} - -- (void)testSuccessfulOpenL2CAPChannel { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = - [[XCTestExpectation alloc] initWithDescription:@"Open L2CAP channel."]; - - GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; - GNCBLEL2CAPClient *l2capClient = - [[GNCBLEL2CAPClient alloc] initWithQueue:nil - requestDisconnectionHandler:^(id _Nonnull peripheral){ - }]; - [medium setL2CAPClient:l2capClient]; - [medium openL2CAPChannelWithPSM:123 - peripheral:fakePeripheral - completionHandler:^(GNCBLEL2CAPStream *_Nullable stream, NSError *_Nullable error) { - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -#pragma mark - Connect - -- (void)testSuccessfulConnect { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Connect."]; - - [medium connectToGATTServerForPeripheral:[[GNCFakePeripheral alloc] init] - disconnectionHandler:nil - completionHandler:^(GNCBLEGATTClient *client, NSError *error) { - XCTAssertNotNil(client); - XCTAssertNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -- (void)testFailedConnect { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Connect."]; - - fakeCentralManager.didFailToConnectPeripheralError = [NSError errorWithDomain:@"fake" - code:0 - userInfo:nil]; - - [medium connectToGATTServerForPeripheral:[[GNCFakePeripheral alloc] init] - disconnectionHandler:nil - completionHandler:^(GNCBLEGATTClient *client, NSError *error) { - XCTAssertNil(client); - XCTAssertNotNil(error); - [expectation fulfill]; - }]; - - [self waitForExpectations:@[ expectation ] timeout:3]; -} - -- (void)testDisconnect { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTestExpectation *disconnectExpectation = - [[XCTestExpectation alloc] initWithDescription:@"Disconnect."]; - - GNCFakePeripheral *peripheral = [[GNCFakePeripheral alloc] init]; - - [medium connectToGATTServerForPeripheral:peripheral - disconnectionHandler:^() { - [disconnectExpectation fulfill]; - } - completionHandler:^(GNCBLEGATTClient *client, NSError *error) { - XCTAssertNotNil(client); - XCTAssertNil(error); - [client disconnect]; - }]; - - [self waitForExpectations:@[ disconnectExpectation ] timeout:3]; -} - -- (void)testRetrievePeripheralWithIdentifier_exists { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTAssertNotNil( - [medium retrievePeripheralWithIdentifier: - [[NSUUID alloc] initWithUUIDString:@"11111111-1111-1111-1111-111111111111"]]); -} - -- (void)testRetrievePeripheralWithIdentifier_doesNotExist { - GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; - GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager queue:nil]; - XCTAssertNil( - [medium retrievePeripheralWithIdentifier: - [[NSUUID alloc] initWithUUIDString:@"11111111-1111-1111-1111-111111111112"]]); -} - -@end diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMediumTest.mm b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMediumTest.mm new file mode 100644 index 00000000..49e0a462 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMediumTest.mm @@ -0,0 +1,621 @@ +// Copyright 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. +// 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. + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTClient.h" +#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h" +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheral.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEL2CAPClient+Testing.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCentralManager.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheral.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" + +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "internal/flags/nearby_flags.h" + +static NSString *const kServiceUUID = @"0000FEF3-0000-1000-8000-00805F9B34FB"; + +@interface GNCBLEMediumTest : XCTestCase +@end + +@implementation GNCBLEMediumTest + +- (void)tearDown { + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); + [super tearDown]; +} + +- (void)testInit_allocatesMultiplexerWhenFlagEnabled { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + + id multiplexer = [medium valueForKey:@"_multiplexer"]; + if (enabled.boolValue) { + XCTAssertNotNil(multiplexer); + XCTAssertEqual(fakePeripheralManager.peripheralDelegate, multiplexer); + } else { + XCTAssertNil(multiplexer); + XCTAssertNil(fakePeripheralManager.peripheralDelegate); + } + } +} + +#pragma mark - Supports Extended Advertisements + +- (void)testSupportsExtendedAdvertisements { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + + XCTAssertFalse([medium supportsExtendedAdvertisements]); + } +} + +#pragma mark - Start Scanning + +- (void)testStartScanning { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *startScanningExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; + XCTestExpectation *advertisementFoundExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Advertisement found."]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + [fakeCentralManager simulateCentralManagerDidUpdateState:CBManagerStatePoweredOn]; + + [medium startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + XCTAssertEqualObjects(expected, data); + [advertisementFoundExpectation fulfill]; + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [startScanningExpectation fulfill]; + }]; + + [self waitForExpectations:@[ startScanningExpectation ] timeout:3]; + + XCTAssertEqualObjects(@[ serviceUUID ], fakeCentralManager.serviceUUIDs); + + [fakeCentralManager + simulateCentralManagerDidDiscoverPeripheral:[[GNCFakePeripheral alloc] init] + advertisementData:@{ + CBAdvertisementDataLocalNameKey : @"dGVzdA", + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + }]; + + [self waitForExpectations:@[ advertisementFoundExpectation ] timeout:3]; + } +} + +- (void)testAlreadyScanning { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; + + [medium startScanningForService:[CBUUID UUIDWithString:kServiceUUID] + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:nil]; + + [medium startScanningForService:[CBUUID UUIDWithString:kServiceUUID] + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +- (void)testStartStopStartScanning { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start scanning."]; + + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + [medium startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [medium stopScanningWithCompletionHandler:^(NSError *error) { + XCTAssertNil(error); + [medium startScanningForService:serviceUUID + advertisementFoundHandler:^(id peripheral, + NSDictionary *data) { + } + completionHandler:^(NSError *error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + }]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +#pragma mark - Decode Advertisement Data + +- (void)testDecodeAndroidStyleAdvertisementData { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary *data = @{ + CBAdvertisementDataServiceDataKey : @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }, + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(expected, actual); + } +} + +- (void)testDecodeAndroidStyleAdvertisementDataWithLocalName { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary *data = @{ + CBAdvertisementDataLocalNameKey : @"Nearby", // Just happens to be base64 decodable. + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + CBAdvertisementDataServiceDataKey : @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }, + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(expected, actual); + } +} + +- (void)testDecodeAppleStyleAdvertisementData { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *expected = @{ + serviceUUID : [@"test" dataUsingEncoding:NSUTF8StringEncoding], + }; + + NSDictionary *data = @{ + CBAdvertisementDataLocalNameKey : @"dGVzdA", + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(expected, actual); + } +} + +- (void)testDecodeInvalidAdvertisementData { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID]; + + NSDictionary *data = @{ + CBAdvertisementDataLocalNameKey : @"!@#$", + CBAdvertisementDataServiceUUIDsKey : @[ serviceUUID ], + }; + NSDictionary *actual = [medium decodeAdvertisementData:data]; + + XCTAssertEqualObjects(@{}, actual); + } +} + +- (void)testDecodeEmptyAdvertisementData { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + + NSDictionary *actual = [medium decodeAdvertisementData:@{}]; + + XCTAssertEqualObjects(@{}, actual); + } +} + +#pragma mark - Start GATT Server + +- (void)testStartGATTServer { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start GATT server."]; + + [medium startGATTServerWithCompletionHandler:^(GNCBLEGATTServer *server, NSError *error) { + XCTAssertNotNil(server); + XCTAssertNil(error); + + // Verify internal structure based on flag + id mediumManager = [medium valueForKey:@"_peripheralManager"]; + id serverManager = [server valueForKey:@"_peripheralManager"]; + + if (enabled.boolValue) { + XCTAssertEqual(mediumManager, serverManager); + id multiplexer = [medium valueForKey:@"_multiplexer"]; + XCTAssertEqual([mediumManager peripheralDelegate], multiplexer); + } else { + XCTAssertNotEqual(mediumManager, serverManager); + id manager = [server valueForKey:@"_peripheralManager"]; + XCTAssertEqual([manager peripheralDelegate], server); + } + + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +#pragma mark - Start Advertising + +- (void)testStartAdvertising { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Start advertising."]; + + // Start advertising is fully covered with @c GNCBLEGATTServer tests. We are passing invalid + // advertising data here so we can test code paths relevant to @c GNCBLEMedium, but bail early + // enough to avoid making actual CoreBluetooth calls. + [medium startAdvertisingData:@{} + completionHandler:^(NSError *error) { + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +- (void)testStopAdvertising { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Stop advertising."]; + + // Stop advertising is fully covered with @c GNCBLEGATTServer tests. We are only testing stopping + // without having started which tests the code paths relevant to @c GNCBLEMedium. + [medium stopAdvertisingWithCompletionHandler:^(NSError *error) { + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +#pragma mark - Open L2CAP Channel + +- (void)testOpenL2CAPServerSocket { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *psmPublishedexpectation = + [[XCTestExpectation alloc] initWithDescription:@"PSM published."]; + XCTestExpectation *channelOpenedexpectation = + [[XCTestExpectation alloc] initWithDescription:@"Channel opened."]; + + [fakePeripheralManager simulatePeripheralManagerDidUpdateState:CBManagerStatePoweredOn]; + + // Open L2CAP server is fully covered with @c GNCBLEL2CAPServer tests. + [medium + openL2CAPServerWithPSMPublishedCompletionHandler:^(uint16_t PSM, NSError *error) { + XCTAssertEqual(PSM, fakePeripheralManager.PSM); + XCTAssertNil(error); + [psmPublishedexpectation fulfill]; + } + channelOpenedCompletionHandler:^(GNCBLEL2CAPStream *stream, NSError *error) { + XCTAssertNil(error); + [channelOpenedexpectation fulfill]; + } + peripheralManager:fakePeripheralManager]; + + [self waitForExpectations:@[ psmPublishedexpectation ] timeout:0.1]; + [self waitForExpectations:@[ channelOpenedexpectation ] timeout:0.5]; + } +} + +- (void)testSuccessfulOpenL2CAPChannel { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = + [[XCTestExpectation alloc] initWithDescription:@"Open L2CAP channel."]; + + GNCFakePeripheral *fakePeripheral = [[GNCFakePeripheral alloc] init]; + GNCBLEL2CAPClient *l2capClient = + [[GNCBLEL2CAPClient alloc] initWithQueue:nil + requestDisconnectionHandler:^(id _Nonnull peripheral){ + }]; + [medium setL2CAPClient:l2capClient]; + [medium openL2CAPChannelWithPSM:123 + peripheral:fakePeripheral + completionHandler:^(GNCBLEL2CAPStream *_Nullable stream, NSError *_Nullable error) { + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +#pragma mark - Connect + +- (void)testSuccessfulConnect { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Connect."]; + + [medium connectToGATTServerForPeripheral:[[GNCFakePeripheral alloc] init] + disconnectionHandler:nil + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + XCTAssertNotNil(client); + XCTAssertNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +- (void)testFailedConnect { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"Connect."]; + + fakeCentralManager.didFailToConnectPeripheralError = [NSError errorWithDomain:@"fake" + code:0 + userInfo:nil]; + + [medium connectToGATTServerForPeripheral:[[GNCFakePeripheral alloc] init] + disconnectionHandler:nil + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + XCTAssertNil(client); + XCTAssertNotNil(error); + [expectation fulfill]; + }]; + + [self waitForExpectations:@[ expectation ] timeout:3]; + } +} + +- (void)testDisconnect { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTestExpectation *disconnectExpectation = + [[XCTestExpectation alloc] initWithDescription:@"Disconnect."]; + + GNCFakePeripheral *peripheral = [[GNCFakePeripheral alloc] init]; + + [medium connectToGATTServerForPeripheral:peripheral + disconnectionHandler:^() { + [disconnectExpectation fulfill]; + } + completionHandler:^(GNCBLEGATTClient *client, NSError *error) { + XCTAssertNotNil(client); + XCTAssertNil(error); + [client disconnect]; + }]; + + [self waitForExpectations:@[ disconnectExpectation ] timeout:3]; + } +} + +- (void)testRetrievePeripheralWithIdentifier_exists { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTAssertNotNil( + [medium retrievePeripheralWithIdentifier: + [[NSUUID alloc] initWithUUIDString:@"11111111-1111-1111-1111-111111111111"]]); + } +} + +- (void)testRetrievePeripheralWithIdentifier_doesNotExist { + for (NSNumber *enabled in @[ @NO, @YES ]) { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + nearby::connections::config_package_nearby::nearby_connections_feature:: + kEnableSharedPeripheralManager, + enabled.boolValue); + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + GNCBLEMedium *medium = [[GNCBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; + XCTAssertNil( + [medium retrievePeripheralWithIdentifier: + [[NSUUID alloc] initWithUUIDString:@"11111111-1111-1111-1111-111111111112"]]); + } +} + +@end diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCBL2CAPChannel.h b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCBL2CAPChannel.h index 69a1b791..465b3120 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCBL2CAPChannel.h +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCBL2CAPChannel.h @@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN /** The socket file descriptor for the L2CAP channel. */ @property(nonatomic, readonly) int socketFD; /** The PSM (Protocol/Service Multiplexer) of the L2CAP channel. */ -@property(nonatomic, readonly) CBL2CAPPSM PSM; +@property(nonatomic, readwrite) CBL2CAPPSM PSM; @end diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.m b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.m index 912974df..3f18bf6a 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.m +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.m @@ -140,6 +140,7 @@ static const uint16_t kPSM = 192; GNCFakeCBL2CAPChannel *fakeChannel = [[GNCFakeCBL2CAPChannel alloc] init]; fakeChannel.inputStream = fakeStream.inputStream; fakeChannel.outputStream = fakeStream.outputStream; + fakeChannel.PSM = _PSM; [_peripheralDelegate gnc_peripheralManager:self didOpenL2CAPChannel:(CBL2CAPChannel *)fakeChannel error:_didOpenL2CAPChannelError]; diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCMBleUtilsTest.m b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCMBleUtilsTest.m index b1c08d95..11ca0c50 100644 --- a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCMBleUtilsTest.m +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCMBleUtilsTest.m @@ -131,7 +131,7 @@ static const NSTimeInterval kWaitForConnectionTimeout = 6.0; // Allow for the 5 GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init]; XCTestExpectation *expectation = [self expectationWithDescription:@"Connection success"]; - GNCMWaitForConnection((GNSSocket *)fakeSocket, ^(BOOL flag) { + GNCMWaitForConnection((GNSSocket *)fakeSocket, nil, ^(BOOL flag) { XCTAssertTrue(flag); [expectation fulfill]; }); @@ -142,12 +142,31 @@ static const NSTimeInterval kWaitForConnectionTimeout = 6.0; // Allow for the 5 [self waitForExpectationsWithTimeout:kTimeout handler:nil]; } +- (void)testWaitForConnection_CustomQueue { + GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init]; + dispatch_queue_t customQueue = dispatch_queue_create("com.google.nearby.testQueue", DISPATCH_QUEUE_SERIAL); + + XCTestExpectation *expectation = [self expectationWithDescription:@"Connection success on custom queue"]; + GNCMWaitForConnection((GNSSocket *)fakeSocket, customQueue, ^(BOOL flag) { + XCTAssertTrue(flag); + // Verify that we are on the custom queue + const char *label = dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL); + XCTAssertEqual(strcmp(label, "com.google.nearby.testQueue"), 0); + [expectation fulfill]; + }); + + // Simulate the connection callback + [fakeSocket simulateSocketDidConnect]; + + [self waitForExpectationsWithTimeout:kTimeout handler:nil]; +} + - (void)testWaitForConnection_Failure_Disconnect { GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init]; XCTestExpectation *expectation = [self expectationWithDescription:@"Connection failed on disconnect"]; - GNCMWaitForConnection((GNSSocket *)fakeSocket, ^(BOOL flag) { + GNCMWaitForConnection((GNSSocket *)fakeSocket, nil, ^(BOOL flag) { XCTAssertFalse(flag); [expectation fulfill]; }); @@ -164,7 +183,7 @@ static const NSTimeInterval kWaitForConnectionTimeout = 6.0; // Allow for the 5 XCTestExpectation *expectation = [self expectationWithDescription:@"Connection failed on timeout"]; - GNCMWaitForConnection((GNSSocket *)fakeSocket, ^(BOOL flag) { + GNCMWaitForConnection((GNSSocket *)fakeSocket, nil, ^(BOOL flag) { XCTAssertFalse(flag); [expectation fulfill]; }); diff --git a/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCPeripheralManagerMultiplexerTest.m b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCPeripheralManagerMultiplexerTest.m new file mode 100644 index 00000000..394eb4cc --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/BLE/Tests/GNCPeripheralManagerMultiplexerTest.m @@ -0,0 +1,495 @@ +// Copyright 2026 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. + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManagerMultiplexer.h" + +#import +#import +#import + +#import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheralManager.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" + +@interface GNCPeripheralManagerMultiplexerTest : XCTestCase +@end + +@interface FakePeripheralManagerDelegate : NSObject +@property(nonatomic) XCTestExpectation *expectation; +@property(nonatomic) BOOL didUpdateStateCalled; +@property(nonatomic) CBManagerState state; + +@property(nonatomic) BOOL didStartAdvertisingCalled; +@property(nonatomic) NSError *startAdvertisingError; + +@property(nonatomic) BOOL didAddServiceCalled; +@property(nonatomic) CBService *addedService; +@property(nonatomic) NSError *addServiceError; + +@property(nonatomic) BOOL didReceiveReadRequestCalled; +@property(nonatomic) CBATTRequest *readRequest; + +@property(nonatomic) BOOL didPublishL2CAPChannelCalled; +@property(nonatomic) CBL2CAPPSM publishedPSM; +@property(nonatomic) NSError *publishL2CAPChannelError; + +@property(nonatomic) BOOL didUnpublishL2CAPChannelCalled; +@property(nonatomic) CBL2CAPPSM unpublishedPSM; +@property(nonatomic) NSError *unpublishL2CAPChannelError; + +@property(nonatomic) BOOL didOpenL2CAPChannelCalled; +@property(nonatomic) CBL2CAPChannel *openedChannel; +@property(nonatomic) NSError *openL2CAPChannelError; + +@end + +@implementation FakePeripheralManagerDelegate + +- (void)gnc_peripheralManagerDidUpdateState:(id)peripheral { + _didUpdateStateCalled = YES; + _state = peripheral.state; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)gnc_peripheralManagerDidStartAdvertising:(id)peripheral + error:(nullable NSError *)error { + _didStartAdvertisingCalled = YES; + _startAdvertisingError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)gnc_peripheralManager:(id)peripheral + didAddService:(CBService *)service + error:(nullable NSError *)error { + _didAddServiceCalled = YES; + _addedService = service; + _addServiceError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)gnc_peripheralManager:(id)peripheral + didReceiveReadRequest:(CBATTRequest *)request { + _didReceiveReadRequestCalled = YES; + _readRequest = request; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)gnc_peripheralManager:(id)peripheral + didPublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(nullable NSError *)error { + _didPublishL2CAPChannelCalled = YES; + _publishedPSM = PSM; + _publishL2CAPChannelError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)gnc_peripheralManager:(id)peripheral + didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(NSError *)error { + _didUnpublishL2CAPChannelCalled = YES; + _unpublishedPSM = PSM; + _unpublishL2CAPChannelError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)gnc_peripheralManager:(id)peripheral + didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel + error:(nullable NSError *)error { + _didOpenL2CAPChannelCalled = YES; + _openedChannel = channel; + _openL2CAPChannelError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManagerDidUpdateState:(nonnull CBPeripheralManager *)peripheral { + _didUpdateStateCalled = YES; + _state = peripheral.state; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral + error:(nullable NSError *)error { + _didStartAdvertisingCalled = YES; + _startAdvertisingError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didAddService:(CBService *)service + error:(nullable NSError *)error { + _didAddServiceCalled = YES; + _addedService = service; + _addServiceError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didReceiveReadRequest:(CBATTRequest *)request { + _didReceiveReadRequestCalled = YES; + _readRequest = request; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didPublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(nullable NSError *)error { + _didPublishL2CAPChannelCalled = YES; + _publishedPSM = PSM; + _publishL2CAPChannelError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didUnpublishL2CAPChannel:(CBL2CAPPSM)PSM + error:(nullable NSError *)error { + _didUnpublishL2CAPChannelCalled = YES; + _unpublishedPSM = PSM; + _unpublishL2CAPChannelError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +- (void)peripheralManager:(CBPeripheralManager *)peripheral + didOpenL2CAPChannel:(nullable CBL2CAPChannel *)channel + error:(nullable NSError *)error { + _didOpenL2CAPChannelCalled = YES; + _openedChannel = channel; + _openL2CAPChannelError = error; + if (_expectation) { + [_expectation fulfill]; + } +} + +@end + +@implementation GNCPeripheralManagerMultiplexerTest + +- (void)testMultiplexerForwardsCallbacks { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate1 = [[FakePeripheralManagerDelegate alloc] init]; + FakePeripheralManagerDelegate *delegate2 = [[FakePeripheralManagerDelegate alloc] init]; + + delegate1.expectation = [self expectationWithDescription:@"Delegate 1 called"]; + delegate2.expectation = [self expectationWithDescription:@"Delegate 2 called"]; + + [multiplexer addListener:delegate1]; + [multiplexer addListener:delegate2]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + fakeManager.state = CBManagerStatePoweredOn; + + [multiplexer gnc_peripheralManagerDidUpdateState:fakeManager]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + + XCTAssertTrue(delegate1.didUpdateStateCalled); + XCTAssertTrue(delegate2.didUpdateStateCalled); + XCTAssertEqual(delegate1.state, CBManagerStatePoweredOn); + XCTAssertEqual(delegate2.state, CBManagerStatePoweredOn); +} + +- (void)testMultiplexerRemovesListener { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate1 = [[FakePeripheralManagerDelegate alloc] init]; + + delegate1.expectation = [self expectationWithDescription:@"Delegate 1 called"]; + + [multiplexer addListener:delegate1]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + fakeManager.state = CBManagerStatePoweredOn; + + [multiplexer removeListener:delegate1]; + [multiplexer gnc_peripheralManagerDidUpdateState:fakeManager]; + + // We expect delegate1 NOT to be called. + // Since removals are async, we wait a bit to ensure it had a chance (or didn't). + XCTWaiterResult result = [XCTWaiter waitForExpectations:@[ delegate1.expectation ] timeout:0.5]; + XCTAssertEqual(result, XCTWaiterResultTimedOut); + XCTAssertFalse(delegate1.didUpdateStateCalled); +} + +- (void)testMultiplexerForwardsDidStartAdvertising { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + NSError *error = [NSError errorWithDomain:@"test" code:1 userInfo:nil]; + + [multiplexer gnc_peripheralManagerDidStartAdvertising:fakeManager error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didStartAdvertisingCalled); + XCTAssertEqualObjects(delegate.startAdvertisingError, error); +} + +- (void)testMultiplexerForwardsDidAddService { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + CBMutableService *service = + [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"180D"] primary:YES]; + NSError *error = [NSError errorWithDomain:@"test" code:2 userInfo:nil]; + + [multiplexer gnc_peripheralManager:fakeManager didAddService:service error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didAddServiceCalled); + XCTAssertEqualObjects(delegate.addedService, service); + XCTAssertEqualObjects(delegate.addServiceError, error); +} + +- (void)testMultiplexerForwardsDidReceiveReadRequest { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + id request = [NSNull null]; // Use NSNull or any object as placeholder since we can't create + // CBATTRequest + + [multiplexer gnc_peripheralManager:fakeManager didReceiveReadRequest:request]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didReceiveReadRequestCalled); + XCTAssertEqual(delegate.readRequest, request); +} + +- (void)testMultiplexerForwardsDidPublishL2CAPChannel { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + CBL2CAPPSM psm = 42; + NSError *error = [NSError errorWithDomain:@"test" code:3 userInfo:nil]; + + [multiplexer gnc_peripheralManager:fakeManager didPublishL2CAPChannel:psm error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didPublishL2CAPChannelCalled); + XCTAssertEqual(delegate.publishedPSM, psm); + XCTAssertEqualObjects(delegate.publishL2CAPChannelError, error); +} + +- (void)testMultiplexerForwardsDidUnpublishL2CAPChannel { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + CBL2CAPPSM psm = 42; + NSError *error = [NSError errorWithDomain:@"test" code:4 userInfo:nil]; + + [multiplexer gnc_peripheralManager:fakeManager didUnpublishL2CAPChannel:psm error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didUnpublishL2CAPChannelCalled); + XCTAssertEqual(delegate.unpublishedPSM, psm); + XCTAssertEqualObjects(delegate.unpublishL2CAPChannelError, error); +} + +- (void)testMultiplexerForwardsDidOpenL2CAPChannel { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + id channel = [NSNull null]; // Placeholder + NSError *error = [NSError errorWithDomain:@"test" code:5 userInfo:nil]; + + [multiplexer gnc_peripheralManager:fakeManager didOpenL2CAPChannel:channel error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didOpenL2CAPChannelCalled); + XCTAssertEqual(delegate.openedChannel, channel); + XCTAssertEqualObjects(delegate.openL2CAPChannelError, error); +} + +- (void)testCBPeripheralManagerDelegateDidUpdateState { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + fakeManager.state = CBManagerStatePoweredOn; + + [multiplexer peripheralManagerDidUpdateState:(CBPeripheralManager *)fakeManager]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didUpdateStateCalled); + XCTAssertEqual(delegate.state, CBManagerStatePoweredOn); +} + +- (void)testCBPeripheralManagerDelegateDidStartAdvertising { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + NSError *error = [NSError errorWithDomain:@"test" code:10 userInfo:nil]; + + [multiplexer peripheralManagerDidStartAdvertising:(CBPeripheralManager *)fakeManager error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didStartAdvertisingCalled); + XCTAssertEqualObjects(delegate.startAdvertisingError, error); +} + +- (void)testCBPeripheralManagerDelegateDidAddService { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + CBMutableService *service = + [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"180F"] primary:YES]; + NSError *error = [NSError errorWithDomain:@"test" code:11 userInfo:nil]; + + [multiplexer peripheralManager:(CBPeripheralManager *)fakeManager didAddService:service error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didAddServiceCalled); + XCTAssertEqualObjects(delegate.addedService, service); + XCTAssertEqualObjects(delegate.addServiceError, error); +} + +- (void)testCBPeripheralManagerDelegateDidReceiveReadRequest { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + id request = [NSNull null]; + + [multiplexer peripheralManager:(CBPeripheralManager *)fakeManager didReceiveReadRequest:request]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didReceiveReadRequestCalled); + XCTAssertEqual(delegate.readRequest, request); +} + +- (void)testCBPeripheralManagerDelegateDidPublishL2CAPChannel { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + CBL2CAPPSM psm = 100; + NSError *error = [NSError errorWithDomain:@"test" code:13 userInfo:nil]; + + [multiplexer peripheralManager:(CBPeripheralManager *)fakeManager + didPublishL2CAPChannel:psm + error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didPublishL2CAPChannelCalled); + XCTAssertEqual(delegate.publishedPSM, psm); + XCTAssertEqualObjects(delegate.publishL2CAPChannelError, error); +} + +- (void)testCBPeripheralManagerDelegateDidUnpublishL2CAPChannel { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + CBL2CAPPSM psm = 101; + NSError *error = [NSError errorWithDomain:@"test" code:14 userInfo:nil]; + + [multiplexer peripheralManager:(CBPeripheralManager *)fakeManager + didUnpublishL2CAPChannel:psm + error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didUnpublishL2CAPChannelCalled); + XCTAssertEqual(delegate.unpublishedPSM, psm); + XCTAssertEqualObjects(delegate.unpublishL2CAPChannelError, error); +} + +- (void)testCBPeripheralManagerDelegateDidOpenL2CAPChannel { + GNCPeripheralManagerMultiplexer *multiplexer = + [[GNCPeripheralManagerMultiplexer alloc] initWithCallbackQueue:dispatch_get_main_queue()]; + FakePeripheralManagerDelegate *delegate = [[FakePeripheralManagerDelegate alloc] init]; + delegate.expectation = [self expectationWithDescription:@"Delegate called"]; + [multiplexer addListener:delegate]; + + GNCFakePeripheralManager *fakeManager = [[GNCFakePeripheralManager alloc] init]; + id channel = [NSNull null]; + NSError *error = [NSError errorWithDomain:@"test" code:15 userInfo:nil]; + + [multiplexer peripheralManager:(CBPeripheralManager *)fakeManager + didOpenL2CAPChannel:channel + error:error]; + + [self waitForExpectationsWithTimeout:1 handler:nil]; + XCTAssertTrue(delegate.didOpenL2CAPChannelCalled); + XCTAssertEqual(delegate.openedChannel, channel); + XCTAssertEqualObjects(delegate.openL2CAPChannelError, error); +} + +@end diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD b/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD index 43313086..59dfe33c 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/BUILD @@ -32,7 +32,7 @@ objc_library( "GNCNWFramework.m", "GNCNWFrameworkError.m", "GNCNWFrameworkServerSocket.m", - "GNCNWFrameworkSocket.m", + "GNCNWFrameworkSocket.mm", "GNCNWListenerImpl.m", "GNCNWParameters.m", ], diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h index 1893dbd6..df429dd8 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h @@ -26,4 +26,5 @@ typedef NS_ERROR_ENUM(GNCNWFrameworkErrorDomain, GNCNWFrameworkError){ GNCNWFrameworkErrorUnknown, GNCNWFrameworkErrorTimedOut, GNCNWFrameworkErrorDuplicateDiscovererForServiceType, + GNCNWFrameworkErrorNotConnected, }; diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h index 4336418c..a13b2774 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.h @@ -15,6 +15,12 @@ #import #import +#ifdef __cplusplus +#include +#include +#endif + + @protocol GNCNWConnection; @interface GNCNWFrameworkSocket : NSObject @@ -44,6 +50,21 @@ */ - (nullable NSData *)readMaxLength:(NSUInteger)length error:(NSError **_Nullable)error; +/** + * Reads the requested amount of bytes from the connection and converts it to a string. + * + * Blocks execution until the bytes have been read or an error occurs. + * + * @param length The number of bytes to read. + * @param[out] error Error that will be populated on failure. A read may return non-nil data along + * with an error. This normally happens if the data read is shorter than the + * requested length. + */ +#ifdef __cplusplus +- (std::optional)readStringWithMaxLength:(NSUInteger)length + error:(NSError **_Nullable)error; +#endif + /** * Writes the given data to the connection. * @@ -54,6 +75,17 @@ */ - (BOOL)write:(NSData *)data error:(NSError **_Nullable)error; +/** + * Writes raw bytes to the connection. + * + * @param bytes The buffer to write. + * @param length The number of bytes to write. + * @param error Error that will be populated on failure. + */ +- (BOOL)writeBytes:(const void *)bytes + length:(NSUInteger)length + error:(NSError **_Nullable)error; + /** * Gracefully closes the connection to remote endpoint. * diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.mm similarity index 55% rename from internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.m rename to internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.mm index 76d6c601..001fe2e0 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.m +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkSocket.mm @@ -17,6 +17,9 @@ #import #import +#include +#include + #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWConnection.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFrameworkError.h" @@ -85,6 +88,52 @@ static const NSTimeInterval kConnectionWriteTimeout = 5.0; // 5 seconds timeout return blockResult; } +- (std::optional)readStringWithMaxLength:(NSUInteger)length error:(NSError **)error { + if (!self.connection) { + if (error) { + *error = [NSError errorWithDomain:GNCNWFrameworkErrorDomain + code:GNCNWFrameworkErrorNotConnected + userInfo:nil]; + } + return std::nullopt; + } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block std::string resultString; + __block NSError *blockError = nil; + __block BOOL contentReceived = NO; + + [self.connection + receiveMessageWithMinLength:(uint32_t)length + maxLength:(uint32_t)length + completionHandler:^(dispatch_data_t _Nullable content, + nw_content_context_t _Nullable context, bool isComplete, + nw_error_t _Nullable receiveError) { + if (receiveError) { + blockError = (__bridge_transfer NSError *)nw_error_copy_cf_error(receiveError); + } + if (content) { + contentReceived = YES; + // OPTIMIZATION: Copy directly from dispatch_data_t into std::string + resultString.reserve(dispatch_data_get_size(content)); + dispatch_data_apply(content, ^bool(dispatch_data_t region, size_t offset, + const void *buffer, size_t size) { + resultString.append((const char *)buffer, size); + return true; + }); + } + dispatch_semaphore_signal(semaphore); + }]; + + // Block the current thread until the network callback completes. + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (error != nil) { + *error = blockError; + } + return (!contentReceived) ? std::nullopt : std::make_optional(std::move(resultString)); +} + - (BOOL)write:(NSData *)data error:(NSError **)error { if (!self.connection) { if (error) { @@ -136,6 +185,50 @@ static const NSTimeInterval kConnectionWriteTimeout = 5.0; // 5 seconds timeout return signaled && blockSuccess; } +- (BOOL)writeBytes:(const void *)bytes length:(NSUInteger)length error:(NSError **)error { + if (!self.connection) { + if (error) { + *error = [NSError errorWithDomain:GNCNWFrameworkErrorDomain + code:GNCNWFrameworkErrorNotConnected + userInfo:nil]; + } + return NO; + } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + __block NSError *blockError = nil; + + // OPTIMIZATION: Use DISPATCH_DATA_DESTRUCTOR_DEFAULT to perform a + // single copy into a GCD-managed buffer. No NSData required. + // TODO: edwinwu - Investigate to see if it is worth to make it zero-copy by replacing + // DISPATCH_DATA_DESTRUCTOR_DEFAULT with a custom empty destructor: + // dispatch_data_t dispatchData = dispatch_data_create(bytes, length, nil, ^{ + // // Zero-copy: ownership remains with the caller. + // }); + dispatch_data_t dispatchData = + dispatch_data_create(bytes, length, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT); + + [self.connection sendData:dispatchData + context:NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT + isComplete:NO + completionHandler:^(nw_error_t _Nullable sendError) { + if (sendError) { + blockError = (__bridge_transfer NSError *)nw_error_copy_cf_error(sendError); + } + dispatch_semaphore_signal(semaphore); + }]; + + // Wait until signaled or the 5-second timeout passes + intptr_t waitResult = dispatch_semaphore_wait( + semaphore, + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kConnectionWriteTimeout * NSEC_PER_SEC))); + if (error != nil) { + *error = blockError; + } + return (waitResult == 0) && (blockError == nil); +} + - (void)close { [_connection cancel]; _connection = nil; diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD index 57afaee9..5aaa96ad 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/BUILD @@ -29,7 +29,7 @@ objc_library( "GNCFakeNWConnection.m", "GNCFakeNWFramework.m", "GNCFakeNWFrameworkServerSocket.m", - "GNCFakeNWFrameworkSocket.m", + "GNCFakeNWFrameworkSocket.mm", "GNCFakeNWListener.m", ], hdrs = [ @@ -57,7 +57,7 @@ objc_library( "GNCNWBrowserImplTest.m", "GNCNWConnectionImplTest.m", "GNCNWFrameworkServerSocketTest.m", - "GNCNWFrameworkSocketTest.m", + "GNCNWFrameworkSocketTest.mm", "GNCNWFrameworkTest.m", "GNCNWListenerImplTest.m", "GNCNWParametersTest.m", diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.mm similarity index 65% rename from internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.m rename to internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.mm index 6bdaf67c..38428fb6 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.m +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWFrameworkSocket.mm @@ -44,6 +44,25 @@ return [NSData data]; } +- (std::optional)readStringWithMaxLength:(NSUInteger)length error:(NSError **)error { + if (self.readError) { + if (error) *error = self.readError; + return std::nullopt; + } + if (self.dataToRead) { + NSData *data = self.dataToRead; + self.dataToRead = nil; + NSUInteger actualLength = MIN(length, data.length); + if (data.length > actualLength) { + self.dataToRead = + [data subdataWithRange:NSMakeRange(actualLength, data.length - actualLength)]; + } + NSData *returnData = [data subdataWithRange:NSMakeRange(0, actualLength)]; + return std::string((const char *)returnData.bytes, returnData.length); + } + return std::string(); +} + - (BOOL)write:(NSData *)data error:(NSError **)error { if (self.writeError) { if (error) { @@ -55,6 +74,17 @@ return YES; } +- (BOOL)writeBytes:(const void *)bytes length:(NSUInteger)length error:(NSError **)error { + if (self.writeError) { + if (error) { + *error = self.writeError; + } + return NO; + } + [self.writtenData appendBytes:bytes length:length]; + return YES; +} + - (void)close { self.isClosed = YES; } diff --git a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.m b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.mm similarity index 61% rename from internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.m rename to internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.mm index e194a0f4..bce7847b 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.m +++ b/internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCNWFrameworkSocketTest.mm @@ -17,6 +17,9 @@ #import #import +#include +#include + #import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWConnection.h" NS_ASSUME_NONNULL_BEGIN @@ -75,6 +78,38 @@ NS_ASSUME_NONNULL_BEGIN XCTAssertNil(error); } +- (void)testReadStringWithMaxLength_Success { + NSError *error = nil; + NSString *testString = @"testData"; + NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding]; + dispatch_data_t dispatchData = dispatch_data_create(testData.bytes, testData.length, dispatch_get_main_queue(), ^{}); + _fakeConnection.dataToReceive = dispatchData; + + std::optional receivedString = [_socket readStringWithMaxLength:testData.length error:&error]; + + XCTAssertTrue(receivedString.has_value()); + XCTAssertEqualObjects(@(receivedString.value().c_str()), testString); + XCTAssertNil(error); +} + +- (void)testReadStringWithMaxLength_Error { + NSError *error = nil; + _fakeConnection.simulateReceiveFailure = YES; + + std::optional receivedString = [_socket readStringWithMaxLength:10 error:&error]; + + XCTAssertFalse(receivedString.has_value()); + XCTAssertNil(error); // Fake doesn't produce an NSError +} + +- (void)testReadStringWithMaxLength_Zero { + NSError *error = nil; + std::optional receivedString = [_socket readStringWithMaxLength:0 error:&error]; + + XCTAssertFalse(receivedString.has_value()); + XCTAssertNil(error); +} + - (void)testWrite_Success { NSError *error = nil; NSString *testString = @"testData"; @@ -97,6 +132,28 @@ NS_ASSUME_NONNULL_BEGIN XCTAssertFalse(result); } +- (void)testWriteBytes_Success { + NSError *error = nil; + NSString *testString = @"testData"; + NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding]; + + BOOL result = [_socket writeBytes:testData.bytes length:testData.length error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); +} + +- (void)testWriteBytes_Error { + NSError *error = nil; + NSString *testString = @"testData"; + NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding]; + _fakeConnection.simulateSendFailure = YES; + + BOOL result = [_socket writeBytes:testData.bytes length:testData.length error:&error]; + + XCTAssertFalse(result); +} + - (void)testClose { XCTAssertFalse(_fakeConnection.cancelCalled); [_socket close]; @@ -105,6 +162,7 @@ NS_ASSUME_NONNULL_BEGIN NSError *error = nil; XCTAssertNil([_socket readMaxLength:10 error:&error]); XCTAssertFalse([_socket write:[NSData data] error:&error]); + XCTAssertFalse([_socket writeBytes:"test" length:4 error:&error]); } @end diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index b27b3c4b..32369963 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -56,8 +56,10 @@ objc_library( "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", + "//internal/platform/implementation:webrtc_platform", "//internal/platform/implementation/apple", # buildcleaner: keep "//internal/platform/implementation/apple:Shared", + "//internal/platform/implementation/apple:apple_webrtc", # buildcleaner: keep "//internal/platform/implementation/apple:ble_v2", "//internal/platform/implementation/apple:network_utils", "//internal/platform/implementation/apple/Flags", diff --git a/internal/platform/implementation/apple/Tests/GNCAwdlMediumTest.mm b/internal/platform/implementation/apple/Tests/GNCAwdlMediumTest.mm index 4ea125a8..6eeec152 100644 --- a/internal/platform/implementation/apple/Tests/GNCAwdlMediumTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCAwdlMediumTest.mm @@ -18,6 +18,9 @@ #include +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "internal/flags/nearby_flags.h" + #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFramework.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWConnection.h" @@ -45,6 +48,7 @@ static const int kTestPort = 1234; - (void)tearDown { _awdlMedium.reset(); + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); [super tearDown]; } @@ -128,6 +132,10 @@ static const int kTestPort = 1234; } - (void)testSocketAndStream { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + false); + // Create a server socket. std::unique_ptr serverSocket = _awdlMedium->ListenForService(kTestPort); @@ -167,6 +175,49 @@ static const int kTestPort = 1234; XCTAssertTrue(fakeServerSocket.isClosed); } +- (void)testSocketAndStream_SingleCopyEnabled { + // Enable the flag. + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + true); + + // Create a server socket. + std::unique_ptr serverSocket = + _awdlMedium->ListenForService(kTestPort); + XCTAssertTrue(serverSocket != nullptr); + + GNCFakeNWFrameworkServerSocket* fakeServerSocket = + (GNCFakeNWFrameworkServerSocket*)_fakeNWFramework.serverSockets[0]; + GNCFakeNWConnection* connection = [[GNCFakeNWConnection alloc] init]; + GNCFakeNWFrameworkSocket* fakeSocket = + [[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection]; + fakeServerSocket.socketToReturnOnAccept = fakeSocket; + + // Accept a client socket. + std::unique_ptr clientSocket = serverSocket->Accept(); + XCTAssertTrue(clientSocket != nullptr); + + // Test input stream with optimized single-copy read. + nearby::InputStream& inputStream = clientSocket->GetInputStream(); + fakeSocket.dataToRead = [@"optimized awdl data" dataUsingEncoding:NSUTF8StringEncoding]; + // "optimized awdl data" is 19 bytes. + nearby::ExceptionOr readData = inputStream.Read(19); + + XCTAssertTrue(readData.ok()); + XCTAssertEqual(std::string(readData.result()), "optimized awdl data"); + + // Test output stream. + nearby::OutputStream& outputStream = clientSocket->GetOutputStream(); + absl::string_view writeData("write data"); + XCTAssertTrue(outputStream.Write(writeData).Ok()); + XCTAssertEqualObjects(fakeSocket.writtenData, + [@"write data" dataUsingEncoding:NSUTF8StringEncoding]); + + // Clean up. + XCTAssertTrue(clientSocket->Close().Ok()); + XCTAssertTrue(serverSocket->Close().Ok()); +} + - (void)testServerSocketGetIPAddress { // Create a server socket. std::unique_ptr serverSocket = @@ -195,6 +246,39 @@ static const int kTestPort = 1234; XCTAssertTrue(serverSocket->Close().Ok()); } +- (void)testOutputStreamWrite_SingleCopyEnabled { + // Enable the flag. + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + true); + + // Create a server socket and accept a client. + std::unique_ptr serverSocket = + _awdlMedium->ListenForService(kTestPort); + GNCFakeNWFrameworkServerSocket* fakeServerSocket = + (GNCFakeNWFrameworkServerSocket*)_fakeNWFramework.serverSockets[0]; + GNCFakeNWConnection* connection = [[GNCFakeNWConnection alloc] init]; + GNCFakeNWFrameworkSocket* fakeSocket = + [[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection]; + fakeServerSocket.socketToReturnOnAccept = fakeSocket; + std::unique_ptr clientSocket = serverSocket->Accept(); + XCTAssertTrue(clientSocket != nullptr); + + // Test output stream. + nearby::OutputStream& outputStream = clientSocket->GetOutputStream(); + absl::string_view writeData("optimized write data"); + XCTAssertTrue(outputStream.Write(writeData).Ok()); + XCTAssertEqualObjects(fakeSocket.writtenData, + [@"optimized write data" dataUsingEncoding:NSUTF8StringEncoding]); + + // Clean up. + XCTAssertTrue(clientSocket->Close().Ok()); + XCTAssertTrue(serverSocket->Close().Ok()); + + // Reset the flag. + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); +} + - (void)testOutputStreamClose { // Create a server socket and accept a client. std::unique_ptr serverSocket = diff --git a/internal/platform/implementation/apple/Tests/GNCDeviceInfoTest.mm b/internal/platform/implementation/apple/Tests/GNCDeviceInfoTest.mm index 39988866..edaf54ad 100644 --- a/internal/platform/implementation/apple/Tests/GNCDeviceInfoTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCDeviceInfoTest.mm @@ -49,27 +49,20 @@ } - (void)testGetDownloadPath { - XCTAssertNotNil(@(_deviceInfo->GetDownloadPath().value().GetPath().c_str())); + XCTAssertNotNil(@(_deviceInfo->GetDownloadPath().GetPath().c_str())); } - (void)testGetLocalAppDataPath { - XCTAssertNotNil(@(_deviceInfo->GetLocalAppDataPath().value().GetPath().c_str())); -} - -- (void)testGetCommonAppDataPath { - XCTAssertNotNil(@(_deviceInfo->GetCommonAppDataPath().value().GetPath().c_str())); + XCTAssertNotNil( + @(_deviceInfo->GetLocalAppDataPath(nearby::FilePath("sub_path")).GetPath().c_str())); } - (void)testGetTemporaryPath { - XCTAssertNotNil(@(_deviceInfo->GetTemporaryPath().value().GetPath().c_str())); + XCTAssertNotNil(@(_deviceInfo->GetTemporaryPath().GetPath().c_str())); } - (void)testGetLogPath { - XCTAssertNotNil(@(_deviceInfo->GetLogPath().value().GetPath().c_str())); -} - -- (void)testGetCrashDumpPath { - XCTAssertNotNil(@(_deviceInfo->GetCrashDumpPath().value().GetPath().c_str())); + XCTAssertNotNil(@(_deviceInfo->GetLogPath().GetPath().c_str())); } - (void)testIsScreenLocked { diff --git a/internal/platform/implementation/apple/Tests/GNCMultiThreadExecutorTest.mm b/internal/platform/implementation/apple/Tests/GNCMultiThreadExecutorTest.mm index 886ff646..2d794f65 100644 --- a/internal/platform/implementation/apple/Tests/GNCMultiThreadExecutorTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCMultiThreadExecutorTest.mm @@ -93,7 +93,7 @@ using MultiThreadExecutor = ::nearby::api::SubmittableExecutor; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_TARGET_QUEUE_DEFAULT, 0); XCTestExpectation *expectation = [self expectationWithDescription:@"finished"]; - const int kRunnableCount = 1000; + const int kRunnableCount = 100; for (int i = 0; i < kRunnableCount; i++) { executor->Execute([self]() { self.counter++; }); } diff --git a/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm b/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm index cfaaebac..22afb8c1 100644 --- a/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCPlatformTest.mm @@ -13,6 +13,7 @@ // limitations under the License. #include "internal/platform/implementation/platform.h" +#include "internal/platform/implementation/webrtc_platform.h" #import #import @@ -320,7 +321,7 @@ void GNCEnsureFileAtPath(std::string path) { } - (void)testCreateWebRtcMedium { - auto webrtc_medium = nearby::api::ImplementationPlatform::CreateWebRtcMedium(); + auto webrtc_medium = nearby::api::WebRtcImplementationPlatform::CreateWebRtcMedium(); XCTAssertNotEqual(webrtc_medium.get(), nullptr); } diff --git a/internal/platform/implementation/apple/Tests/GNCSingleThreadExecutorTest.mm b/internal/platform/implementation/apple/Tests/GNCSingleThreadExecutorTest.mm index e5857cb8..8e5e1dbf 100644 --- a/internal/platform/implementation/apple/Tests/GNCSingleThreadExecutorTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCSingleThreadExecutorTest.mm @@ -76,20 +76,14 @@ using SingleThreadExecutor = ::nearby::api::SubmittableExecutor; // Tests that shutting down an existing task allows to complete. - (void)testShutdownToAllowExistingTaskComplete { std::unique_ptr executor([self executor]); - - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_TARGET_QUEUE_DEFAULT, 0); XCTestExpectation *expectation = [self expectationWithDescription:@"finished"]; - - executor->Execute([self]() { self.counter++; }); - - executor->Shutdown(); - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), queue, ^{ - XCTAssertEqual(self.counter, 1); + executor->Execute([self, expectation]() { + self.counter++; [expectation fulfill]; }); - - [self waitForExpectationsWithTimeout:0.5 handler:nil]; + executor->Shutdown(); + [self waitForExpectationsWithTimeout:1.0 handler:nil]; + XCTAssertEqual(self.counter, 1); } @end diff --git a/internal/platform/implementation/apple/Tests/GNCTimerTest.mm b/internal/platform/implementation/apple/Tests/GNCTimerTest.mm index 269bdf0f..32c895f1 100644 --- a/internal/platform/implementation/apple/Tests/GNCTimerTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCTimerTest.mm @@ -65,7 +65,7 @@ auto timer = std::make_unique(); std::atomic fireCount = 0; - XCTAssertTrue(timer->Create(10, 10, [&]() { + XCTAssertTrue(timer->Create(100, 100, [&]() { if (fireCount.fetch_add(1) == 1) { dispatch_async(dispatch_get_main_queue(), ^{ [expectation fulfill]; @@ -73,9 +73,9 @@ } })); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; + [self waitForExpectationsWithTimeout:2.0 handler:nil]; XCTAssertTrue(timer->Stop()); - XCTAssertEqual(fireCount.load(), 2); + XCTAssertGreaterThanOrEqual(fireCount.load(), 2); } - (void)testRestart { diff --git a/internal/platform/implementation/apple/Tests/GNCWifiHotspotMediumTest.mm b/internal/platform/implementation/apple/Tests/GNCWifiHotspotMediumTest.mm index 59687ab1..8c2e7803 100644 --- a/internal/platform/implementation/apple/Tests/GNCWifiHotspotMediumTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCWifiHotspotMediumTest.mm @@ -19,8 +19,11 @@ #include +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/byte_array.h" #include "internal/platform/exception.h" + #import "internal/platform/implementation/apple/Mediums/CoreLocation/CLLocationManager/Fake/CLLocationManagerFake.h" #import "internal/platform/implementation/apple/Mediums/Hotspot/GNCHotspotMedium.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" @@ -59,8 +62,8 @@ const char kIPAddress[] = "192.168.1.2"; _medium.locationManager = _fakeLocationManager; _hotspotMedium = std::make_unique(_medium); _service_address = { - .address = {static_cast(192), static_cast(168), 1, 2}, - .port = 1234, + .address = {static_cast(192), static_cast(168), 1, 2}, + .port = 1234, }; } @@ -98,6 +101,10 @@ const char kIPAddress[] = "192.168.1.2"; } - (void)testInputStreamRead { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + false); + nearby::CancellationFlag cancellationFlag; std::unique_ptr socket = _hotspotMedium->ConnectToService(_service_address, &cancellationFlag); @@ -110,6 +117,28 @@ const char kIPAddress[] = "192.168.1.2"; XCTAssertTrue(readData.ok()); XCTAssertEqual(readData.result().size(), 4); XCTAssertEqual(strncmp(readData.result().data(), "Test", 4), 0); + + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); +} + +- (void)testInputStreamRead_SingleCopyEnabled { + // Enable the flag + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + true); + + nearby::CancellationFlag cancellationFlag; + std::unique_ptr socket = + _hotspotMedium->ConnectToService(_service_address, &cancellationFlag); + GNCFakeNWFrameworkSocket *fakeSocket = _fakeNWFramework.sockets.firstObject; + fakeSocket.dataToRead = [@"HotspotOpt" dataUsingEncoding:NSUTF8StringEncoding]; + + nearby::ExceptionOr readData = socket->GetInputStream().Read(10); + + XCTAssertTrue(readData.ok()); + XCTAssertEqual(std::string(readData.result()), "HotspotOpt"); + + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); } - (void)testInputStreamClose { @@ -125,6 +154,10 @@ const char kIPAddress[] = "192.168.1.2"; } - (void)testOutputStreamWrite { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + false); + nearby::CancellationFlag cancellationFlag; std::unique_ptr socket = _hotspotMedium->ConnectToService(_service_address, &cancellationFlag); @@ -136,6 +169,29 @@ const char kIPAddress[] = "192.168.1.2"; XCTAssertTrue(writeResult.Ok()); XCTAssertEqualObjects(fakeSocket.writtenData, data); + + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); +} + +- (void)testOutputStreamWrite_SingleCopyEnabled { + // Enable the flag + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + true); + + nearby::CancellationFlag cancellationFlag; + std::unique_ptr socket = + _hotspotMedium->ConnectToService(_service_address, &cancellationFlag); + GNCFakeNWFrameworkSocket *fakeSocket = _fakeNWFramework.sockets.firstObject; + NSData *data = [@"TestDataOpt" dataUsingEncoding:NSUTF8StringEncoding]; + absl::string_view data_str(reinterpret_cast(data.bytes), data.length); + + nearby::Exception writeResult = socket->GetOutputStream().Write(data_str); + + XCTAssertTrue(writeResult.Ok()); + XCTAssertEqualObjects(fakeSocket.writtenData, data); + + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); } - (void)testSocketClose { diff --git a/internal/platform/implementation/apple/Tests/GNCWifiLanMediumTest.mm b/internal/platform/implementation/apple/Tests/GNCWifiLanMediumTest.mm index 1d581fb2..fd633d60 100644 --- a/internal/platform/implementation/apple/Tests/GNCWifiLanMediumTest.mm +++ b/internal/platform/implementation/apple/Tests/GNCWifiLanMediumTest.mm @@ -18,6 +18,9 @@ #include +#include "connections/implementation/flags/nearby_connections_feature_flags.h" +#include "internal/flags/nearby_flags.h" + #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFramework.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/Tests/GNCFakeNWConnection.h" @@ -118,6 +121,10 @@ } - (void)testSocketAndStream { + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + false); + // Create a server socket. std::unique_ptr serverSocket = _wifiLanMedium->ListenForService(1234); @@ -155,6 +162,38 @@ // Test closing the server socket. XCTAssertTrue(serverSocket->Close().Ok()); XCTAssertTrue(fakeServerSocket.isClosed); + // Reset the flag. + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); +} + +- (void)testSocketAndStream_SingleCopyEnabled { + // Enable the flag + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + true); + + // Create a server socket and accept a client. + std::unique_ptr serverSocket = + _wifiLanMedium->ListenForService(1234); + GNCFakeNWFrameworkServerSocket* fakeServerSocket = + (GNCFakeNWFrameworkServerSocket*)_fakeNWFramework.serverSockets[0]; + GNCFakeNWConnection* connection = [[GNCFakeNWConnection alloc] init]; + GNCFakeNWFrameworkSocket* fakeSocket = + [[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection]; + fakeServerSocket.socketToReturnOnAccept = fakeSocket; + + std::unique_ptr clientSocket = serverSocket->Accept(); + nearby::InputStream& inputStream = clientSocket->GetInputStream(); + + // Test optimized single-copy read. + fakeSocket.dataToRead = [@"optimized data" dataUsingEncoding:NSUTF8StringEncoding]; + nearby::ExceptionOr readData = inputStream.Read(14); + + XCTAssertTrue(readData.ok()); + XCTAssertEqual(std::string(readData.result()), "optimized data"); + + // Reset the flag. + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); } - (void)testServerSocketGetIPAddress { @@ -185,6 +224,39 @@ XCTAssertTrue(serverSocket->Close().Ok()); } +- (void)testOutputStreamWrite_SingleCopyEnabled { + // Enable the flag + nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( + ::nearby::connections::config_package_nearby::nearby_connections_feature::kEnableSingleCopy, + true); + + // Create a server socket and accept a client. + std::unique_ptr serverSocket = + _wifiLanMedium->ListenForService(1234); + GNCFakeNWFrameworkServerSocket* fakeServerSocket = + (GNCFakeNWFrameworkServerSocket*)_fakeNWFramework.serverSockets[0]; + GNCFakeNWConnection* connection = [[GNCFakeNWConnection alloc] init]; + GNCFakeNWFrameworkSocket* fakeSocket = + [[GNCFakeNWFrameworkSocket alloc] initWithConnection:connection]; + fakeServerSocket.socketToReturnOnAccept = fakeSocket; + + std::unique_ptr clientSocket = serverSocket->Accept(); + nearby::OutputStream& outputStream = clientSocket->GetOutputStream(); + + // Test optimized single-copy write. + absl::string_view writeData("optimized data"); + XCTAssertTrue(outputStream.Write(writeData).Ok()); + XCTAssertEqualObjects(fakeSocket.writtenData, + [@"optimized data" dataUsingEncoding:NSUTF8StringEncoding]); + + // Clean up. + XCTAssertTrue(clientSocket->Close().Ok()); + XCTAssertTrue(serverSocket->Close().Ok()); + + // Reset the flag. + nearby::NearbyFlags::GetInstance().ResetOverridedValues(); +} + - (void)testOutputStreamClose { // Create a server socket and accept a client. std::unique_ptr serverSocket = diff --git a/internal/platform/implementation/apple/Tests/UtilsTest.mm b/internal/platform/implementation/apple/Tests/UtilsTest.mm index cabf5d3d..5c513c1f 100644 --- a/internal/platform/implementation/apple/Tests/UtilsTest.mm +++ b/internal/platform/implementation/apple/Tests/UtilsTest.mm @@ -56,8 +56,9 @@ using ::nearby::ObjCStringFromCppString; - (void)testUUIDStringFromNSUUID { NSString *uuidString = @"E621E1F8-C36C-495A-93FC-0C247A3E6E5F"; NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString]; - std::string expectedCppString = [uuidString UTF8String]; - XCTAssertEqual(nearby::UUIDStringFromNSUUID(uuid), expectedCppString); + XCTAssert(nearby::UUIDStringFromNSUUID(uuid) == + std::string([uuidString UTF8String], + [uuidString lengthOfBytesUsingEncoding:NSUTF8StringEncoding])); } - (void)testBluetoothUUIDConversions { diff --git a/internal/platform/implementation/apple/Tests/ble_gatt_client_test.mm b/internal/platform/implementation/apple/Tests/ble_gatt_client_test.mm index c5969c5f..ae1066a8 100644 --- a/internal/platform/implementation/apple/Tests/ble_gatt_client_test.mm +++ b/internal/platform/implementation/apple/Tests/ble_gatt_client_test.mm @@ -210,19 +210,6 @@ XCTAssertFalse(result); } -- (void)testSetCharacteristicSubscriptionReturnsFalse { - GNCBLEGATTCharacteristic *characteristic = - [[GNCBLEGATTCharacteristic alloc] initWithUUID:[CBUUID UUIDWithString:@"B2B4"] - serviceUUID:[CBUUID UUIDWithString:@"FEF3"] - permissions:CBAttributePermissionsReadable - properties:CBCharacteristicPropertyNotify]; - nearby::api::ble::GattCharacteristic cppCharacteristic = - nearby::apple::CPPGATTCharacteristicFromObjC(characteristic); - BOOL result = _gattClient->SetCharacteristicSubscription(cppCharacteristic, true, - [](absl::string_view value) {}); - XCTAssertFalse(result); -} - - (void)testDisconnectWhenFlagEnabled { nearby::NearbyFlags::GetInstance().OverrideBoolFlagValue( nearby::connections::config_package_nearby::nearby_connections_feature:: diff --git a/internal/platform/implementation/apple/Tests/ble_l2cap_server_socket_test.mm b/internal/platform/implementation/apple/Tests/ble_l2cap_server_socket_test.mm index 88b47282..2be79381 100644 --- a/internal/platform/implementation/apple/Tests/ble_l2cap_server_socket_test.mm +++ b/internal/platform/implementation/apple/Tests/ble_l2cap_server_socket_test.mm @@ -50,8 +50,9 @@ - (void)testBleL2capServerSocketAccept { XCTestExpectation *expectation = [self expectationWithDescription:@"accept"]; + nearby::apple::BleL2capServerSocket *serverSocket = _serverSocket.get(); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - std::unique_ptr clientSocket = _serverSocket->Accept(); + std::unique_ptr clientSocket = serverSocket->Accept(); XCTAssertNotEqual(clientSocket.get(), nullptr); [expectation fulfill]; }); @@ -76,8 +77,9 @@ - (void)testBleL2capServerSocketClose { XCTestExpectation *expectation = [self expectationWithDescription:@"close"]; + nearby::apple::BleL2capServerSocket *serverSocket = _serverSocket.get(); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - std::unique_ptr clientSocket = _serverSocket->Accept(); + std::unique_ptr clientSocket = serverSocket->Accept(); XCTAssertEqual(clientSocket.get(), nullptr); [expectation fulfill]; }); diff --git a/internal/platform/implementation/apple/Tests/ble_medium_test.mm b/internal/platform/implementation/apple/Tests/ble_medium_test.mm index b628c3f3..a8fb6199 100644 --- a/internal/platform/implementation/apple/Tests/ble_medium_test.mm +++ b/internal/platform/implementation/apple/Tests/ble_medium_test.mm @@ -23,9 +23,7 @@ #include #include -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTClient.h" -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEGATTServer.h" -#import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPClient.h" +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEMedium.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCPeripheral.h" #import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Central/GNSCentralManager.h" @@ -33,9 +31,13 @@ #import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralManager.h" #import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Peripheral/GNSPeripheralServiceManager.h" #import "internal/platform/implementation/apple/Mediums/BLE/Sockets/Source/Shared/GNSSocket.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCBLEMedium+Testing.h" #import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeBLEGATTServer.h" #import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeBLEMedium.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeCentralManager.h" #import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheral.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakePeripheralManager.h" +#import "internal/platform/implementation/apple/Mediums/BLE/Tests/GNCFakeSocket.h" #include "internal/platform/implementation/apple/ble_utils.h" #include "internal/platform/implementation/ble.h" #import "third_party/objective_c/ocmock/v3/Source/OCMock/OCMock.h" @@ -45,11 +47,16 @@ namespace apple { class BleMediumPeer { public: - static void SetSocketCentralManager(BleMedium *ble_medium, GNSCentralManager *manager) { - ble_medium->socketCentralManager_ = manager; + static void SetPeripheralManagerFactory(BleMedium *ble_medium, + BleMedium::PeripheralManagerFactory factory) { + ble_medium->peripheral_manager_factory_ = std::move(factory); } - static void SetSocketPeripheralManager(BleMedium *ble_medium, GNSPeripheralManager *manager) { - ble_medium->socketPeripheralManager_ = manager; + static void SetCentralManagerFactory(BleMedium *ble_medium, + BleMedium::CentralManagerFactory factory) { + ble_medium->central_manager_factory_ = std::move(factory); + } + static GNSPeripheralServiceManager *GetSocketPeripheralServiceManager(BleMedium *ble_medium) { + return ble_medium->socketPeripheralServiceManager_; } }; @@ -71,7 +78,11 @@ static const char *const kTestServiceID = "TestServiceID"; - (void)setUp { [super setUp]; - _fakeGNCBLEMedium = [[GNCFakeBLEMedium alloc] init]; + GNCFakeCentralManager *fakeCentralManager = [[GNCFakeCentralManager alloc] init]; + GNCFakePeripheralManager *fakePeripheralManager = [[GNCFakePeripheralManager alloc] init]; + _fakeGNCBLEMedium = [[GNCFakeBLEMedium alloc] initWithCentralManager:fakeCentralManager + peripheralManager:fakePeripheralManager + queue:dispatch_get_main_queue()]; _medium = std::make_unique((GNCBLEMedium *)_fakeGNCBLEMedium); } @@ -79,6 +90,28 @@ static const char *const kTestServiceID = "TestServiceID"; [super tearDown]; } +- (void)testOpenServerSocket_UsesFactoryForInitialization { + __block BOOL factoryWasCalled = NO; + id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]); + OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any] + bleServiceAddedCompletion:[OCMArg any]]) + .andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager, + void (^completion)(NSError *error)) { + completion(nil); + }); + + nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() { + factoryWasCalled = YES; + return mockPeripheralManager; + }); + + // This call should trigger the factory inside BleMedium. + auto server_socket = _medium->OpenServerSocket(kTestServiceID); + + XCTAssertTrue(factoryWasCalled, @"BleMedium should have requested the manager from the factory."); + XCTAssertNotEqual(server_socket.get(), nullptr); +} + #pragma mark - Advertising Tests - (void)testStartAdvertising_Success { @@ -225,8 +258,8 @@ static const char *const kTestServiceID = "TestServiceID"; #pragma mark - GATT Server Tests - (void)testStartGattServer_Success { - _fakeGNCBLEMedium.fakeGATTServer = [[GNCFakeBLEGATTServer alloc] init]; - + _fakeGNCBLEMedium.fakeGATTServer = [[GNCFakeBLEGATTServer alloc] initWithPeripheralManager:nil + queue:nil]; auto gatt_server = _medium->StartGattServer({}); XCTAssertNotEqual(gatt_server.get(), nullptr); @@ -422,7 +455,9 @@ static const char *const kTestServiceID = "TestServiceID"; id mockCentralManager = OCMClassMock([GNSCentralManager class]); OCMStub([mockCentralManager retrieveCentralPeerWithIdentifier:fakePeripheral.identifier]) .andReturn(nil); - nearby::apple::BleMediumPeer::SetSocketCentralManager(_medium.get(), mockCentralManager); + nearby::apple::BleMediumPeer::SetCentralManagerFactory(_medium.get(), ^(CBUUID *uuid) { + return mockCentralManager; + }); auto socket = _medium->Connect(kTestServiceID, nearby::api::ble::TxPowerLevel::kUltraLow, fakePeripheral.identifier.hash, nullptr); @@ -460,7 +495,9 @@ static const char *const kTestServiceID = "TestServiceID"; id mockCentralManager = OCMClassMock([GNSCentralManager class]); OCMStub([mockCentralManager retrieveCentralPeerWithIdentifier:fakePeripheral.identifier]) .andReturn(mockCentralPeerManager); - nearby::apple::BleMediumPeer::SetSocketCentralManager(_medium.get(), mockCentralManager); + nearby::apple::BleMediumPeer::SetCentralManagerFactory(_medium.get(), ^(CBUUID *uuid) { + return mockCentralManager; + }); auto socket = _medium->Connect(kTestServiceID, nearby::api::ble::TxPowerLevel::kUltraLow, fakePeripheral.identifier.hash, nullptr); @@ -470,7 +507,10 @@ static const char *const kTestServiceID = "TestServiceID"; #pragma mark - Server Socket Tests -- (void)testOpenServerSocket_Success { +- (void)testOpenServerSocket_Success_LegacyPath { + id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]); + OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(NO); + id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]); OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any] bleServiceAddedCompletion:[OCMArg any]]) @@ -478,11 +518,97 @@ static const char *const kTestServiceID = "TestServiceID"; void (^completion)(NSError *error)) { completion(nil); }); - nearby::apple::BleMediumPeer::SetSocketPeripheralManager(_medium.get(), mockPeripheralManager); + nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() { + return mockPeripheralManager; + }); auto server_socket = _medium->OpenServerSocket(kTestServiceID); XCTAssertNotEqual(server_socket.get(), nullptr); + + GNSPeripheralServiceManager *serviceManager = + nearby::apple::BleMediumPeer::GetSocketPeripheralServiceManager(_medium.get()); + XCTAssertNotNil(serviceManager); +} + +- (void)testOpenServerSocket_Success_OptimizedPath { + id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]); + OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(YES); + + id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]); + OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any] + bleServiceAddedCompletion:[OCMArg any]]) + .andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager, + void (^completion)(NSError *error)) { + completion(nil); + }); + nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() { + return mockPeripheralManager; + }); + + auto server_socket = _medium->OpenServerSocket(kTestServiceID); + + XCTAssertNotEqual(server_socket.get(), nullptr); + + GNSPeripheralServiceManager *serviceManager = + nearby::apple::BleMediumPeer::GetSocketPeripheralServiceManager(_medium.get()); + XCTAssertNotNil(serviceManager); +} + +- (void)testOpenServerSocket_OptimizedPath_AcceptSocketAfterClose { + id mockFeatureFlags = OCMClassMock([GNCFeatureFlags class]); + OCMStub([mockFeatureFlags fixBleServerSocketDeadlockEnabled]).andReturn(YES); + + id mockPeripheralManager = OCMClassMock([GNSPeripheralManager class]); + OCMStub([mockPeripheralManager addPeripheralServiceManager:[OCMArg any] + bleServiceAddedCompletion:[OCMArg any]]) + .andDo(^(GNSPeripheralManager *localSelf, GNSPeripheralServiceManager *manager, + void (^completion)(NSError *error)) { + completion(nil); + }); + nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() { + return mockPeripheralManager; + }); + + auto server_socket = _medium->OpenServerSocket(kTestServiceID); + XCTAssertNotEqual(server_socket.get(), nullptr); + __block BOOL (^capturedHandler)(GNSSocket *) = nil; + id mockServiceManagerClass = OCMClassMock([GNSPeripheralServiceManager class]); + OCMStub([mockServiceManagerClass alloc]).andReturn(mockServiceManagerClass); + OCMStub([mockServiceManagerClass initWithBleServiceUUID:[OCMArg any] + addPairingCharacteristic:NO + shouldAcceptSocketHandler:[OCMArg any]]) + .andDo(^(NSInvocation *invocation) { + BOOL (^handler)(GNSSocket *); + [invocation getArgument:&handler atIndex:4]; + capturedHandler = handler; + }) + .andReturn(mockServiceManagerClass); + + auto server_socket_for_handler_capture = _medium->OpenServerSocket(kTestServiceID); + XCTAssertNotEqual(server_socket_for_handler_capture.get(), nullptr); + XCTAssertNotNil(capturedHandler); + + // Invoke the shouldAcceptSocketHandler with a fake socket. + GNCFakeSocket *fakeSocket = [[GNCFakeSocket alloc] init]; + BOOL result = capturedHandler((GNSSocket *)fakeSocket); + XCTAssertTrue(result); + + // Close the server_socket. This triggers the close notifier, setting server_socket_ptr_ to null. + server_socket_for_handler_capture->Close(); + + // Now simulate the connection completing. It should safely ignore the connection because + // server_socket_ptr_ is null, preventing use-after-free or deadlocks. + [fakeSocket simulateSocketDidConnect]; + + // Since we use dispatch_async internally for connection callback, give it a small amount of time + // to process so we know it didn't crash. + XCTestExpectation *expectation2 = [self expectationWithDescription:@"Wait for async execution"]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ + [expectation2 fulfill]; + }); + [self waitForExpectations:@[ expectation2 ] timeout:1.0]; } - (void)testOpenServerSocket_Failure { @@ -493,7 +619,9 @@ static const char *const kTestServiceID = "TestServiceID"; void (^completion)(NSError *error)) { completion([NSError errorWithDomain:@"test" code:0 userInfo:nil]); }); - nearby::apple::BleMediumPeer::SetSocketPeripheralManager(_medium.get(), mockPeripheralManager); + nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() { + return mockPeripheralManager; + }); auto server_socket = _medium->OpenServerSocket(kTestServiceID); @@ -508,7 +636,9 @@ static const char *const kTestServiceID = "TestServiceID"; void (^completion)(NSError *error)){ // Do not call completion to simulate timeout. }); - nearby::apple::BleMediumPeer::SetSocketPeripheralManager(_medium.get(), mockPeripheralManager); + nearby::apple::BleMediumPeer::SetPeripheralManagerFactory(_medium.get(), ^() { + return mockPeripheralManager; + }); auto server_socket = _medium->OpenServerSocket(kTestServiceID); @@ -646,18 +776,20 @@ static const char *const kTestServiceID = "TestServiceID"; NSDictionary *serviceData = @{[CBUUID UUIDWithString:kTestServiceUUIDString] : [NSData dataWithBytes:"test" length:4]}; - __block XCTestExpectation *expectation1 = [self expectationWithDescription:@"Callback 1"]; + XCTestExpectation *expectation1 = [self expectationWithDescription:@"Callback 1"]; XCTestExpectation *expectation2 = [self expectationWithDescription:@"Callback 2"]; expectation2.inverted = YES; // Should NOT be called. + auto callback1_fulfilled = std::make_shared>(false); + nearby::api::ble::BleMedium::ScanCallback callback = { .advertisement_found_cb = std::function( - ^(nearby::api::ble::BlePeripheral::UniqueId peripheral_id, - const nearby::api::ble::BleAdvertisementData &advertisement) { - if ([expectation1.description isEqualToString:@"Callback 1"]) { + [callback1_fulfilled, expectation1, expectation2]( + nearby::api::ble::BlePeripheral::UniqueId peripheral_id, + const nearby::api::ble::BleAdvertisementData &advertisement) { + if (!callback1_fulfilled->exchange(true)) { [expectation1 fulfill]; - expectation1 = nil; // Prevent double fulfillment } else { [expectation2 fulfill]; } diff --git a/internal/platform/implementation/apple/Tests/ble_server_socket_test.mm b/internal/platform/implementation/apple/Tests/ble_server_socket_test.mm index 1b887880..a9574f96 100644 --- a/internal/platform/implementation/apple/Tests/ble_server_socket_test.mm +++ b/internal/platform/implementation/apple/Tests/ble_server_socket_test.mm @@ -42,8 +42,9 @@ - (void)testBleServerSocketAccept { XCTestExpectation *expectation = [self expectationWithDescription:@"accept"]; + nearby::apple::BleServerSocket *serverSocket = _serverSocket.get(); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - std::unique_ptr clientSocket = _serverSocket->Accept(); + std::unique_ptr clientSocket = serverSocket->Accept(); XCTAssertNotEqual(clientSocket.get(), nullptr); [expectation fulfill]; }); @@ -57,8 +58,9 @@ - (void)testBleServerSocketClose { XCTestExpectation *expectation = [self expectationWithDescription:@"close"]; + nearby::apple::BleServerSocket *serverSocket = _serverSocket.get(); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - std::unique_ptr clientSocket = _serverSocket->Accept(); + std::unique_ptr clientSocket = serverSocket->Accept(); XCTAssertEqual(clientSocket.get(), nullptr); [expectation fulfill]; }); diff --git a/internal/platform/implementation/apple/atomic_boolean_test.cc b/internal/platform/implementation/apple/atomic_boolean_test.cc index 26c6b4f7..cd86bf4d 100644 --- a/internal/platform/implementation/apple/atomic_boolean_test.cc +++ b/internal/platform/implementation/apple/atomic_boolean_test.cc @@ -15,7 +15,7 @@ #include "internal/platform/implementation/apple/atomic_boolean.h" #include "gtest/gtest.h" -#include "thread/fiber/fiber.h" +#include "third_party/gloop/thread/fiber/fiber.h" namespace nearby { namespace apple { diff --git a/internal/platform/implementation/apple/atomic_uint32_test.cc b/internal/platform/implementation/apple/atomic_uint32_test.cc index 54c2ac79..5fe2917f 100644 --- a/internal/platform/implementation/apple/atomic_uint32_test.cc +++ b/internal/platform/implementation/apple/atomic_uint32_test.cc @@ -15,7 +15,7 @@ #include "internal/platform/implementation/apple/atomic_uint32.h" #include "gtest/gtest.h" -#include "thread/fiber/fiber.h" +#include "third_party/gloop/thread/fiber/fiber.h" namespace nearby { namespace apple { diff --git a/internal/platform/implementation/apple/awdl.mm b/internal/platform/implementation/apple/awdl.mm index f23b61b5..8720d1e9 100644 --- a/internal/platform/implementation/apple/awdl.mm +++ b/internal/platform/implementation/apple/awdl.mm @@ -19,6 +19,7 @@ #include #include +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFramework.h" @@ -35,12 +36,22 @@ AwdlInputStream::AwdlInputStream(GNCNWFrameworkSocket* socket) : socket_(socket) ExceptionOr AwdlInputStream::Read(std::int64_t size) { NSError* error = nil; - NSData* data = [socket_ readMaxLength:size error:&error]; - if (data == nil) { - GNCLoggerError(@"Error reading socket: %@", error); - return {Exception::kIo}; + if (GNCFeatureFlags.singleCopyEnabled) { + auto result = [socket_ readStringWithMaxLength:size error:&error]; + if (!result.has_value()) { + GNCLoggerError(@"Error reading socket: %@", error); + return {Exception::kIo}; + } + // OPTIMIZATION: Zero-copy transfer from std::string to ByteArray + return ExceptionOr{ByteArray(std::move(result.value()))}; + } else { + NSData* data = [socket_ readMaxLength:size error:&error]; + if (data == nil) { + GNCLoggerError(@"Error reading socket: %@", error); + return {Exception::kIo}; + } + return ExceptionOr{ByteArray((const char*)data.bytes, data.length)}; } - return ExceptionOr{ByteArray((const char*)data.bytes, data.length)}; } Exception AwdlInputStream::Close() { @@ -55,7 +66,15 @@ AwdlOutputStream::AwdlOutputStream(GNCNWFrameworkSocket* socket) : socket_(socke Exception AwdlOutputStream::Write(absl::string_view data) { NSError* error = nil; - BOOL result = [socket_ write:[NSData dataWithBytes:data.data() length:data.size()] error:&error]; + BOOL result = NO; + + if (GNCFeatureFlags.singleCopyEnabled) { + // OPTIMIZATION: Write raw bytes directly, avoiding NSData creation. + result = [socket_ writeBytes:data.data() length:data.size() error:&error]; + } else { + result = [socket_ write:[NSData dataWithBytes:data.data() length:data.size()] error:&error]; + } + if (!result) { GNCLoggerError(@"Error writing socket: %@", error); return {Exception::kIo}; diff --git a/internal/platform/implementation/apple/ble_gatt_client.h b/internal/platform/implementation/apple/ble_gatt_client.h index f375586c..1be7ae1e 100644 --- a/internal/platform/implementation/apple/ble_gatt_client.h +++ b/internal/platform/implementation/apple/ble_gatt_client.h @@ -66,16 +66,6 @@ class GattClient : public api::ble::GattClient { bool WriteCharacteristic(const api::ble::GattCharacteristic &characteristic, absl::string_view value, api::ble::GattClient::WriteType type) override; - // Enable or disable notifications/indications for a given characteristic. - // - // Once notifications are enabled for a characteristic, on_characteristic_changed_cb will be - // triggered if the remote device indicates that the given characteristic has changed. - // - // Returns whether or not the subscription was successful. - bool SetCharacteristicSubscription( - const api::ble::GattCharacteristic &characteristic, bool enable, - absl::AnyInvocable on_characteristic_changed_cb) override; - // Disconnects an established connection, or cancels a connection attempt currently in progress. void Disconnect() override; diff --git a/internal/platform/implementation/apple/ble_gatt_client.mm b/internal/platform/implementation/apple/ble_gatt_client.mm index 655878cf..4b1a07f2 100644 --- a/internal/platform/implementation/apple/ble_gatt_client.mm +++ b/internal/platform/implementation/apple/ble_gatt_client.mm @@ -121,13 +121,6 @@ bool GattClient::WriteCharacteristic(const api::ble::GattCharacteristic &charact return false; } -// TODO(b/290385712): Implement. -bool GattClient::SetCharacteristicSubscription( - const api::ble::GattCharacteristic &characteristic, bool enable, - absl::AnyInvocable on_characteristic_changed_cb) { - return false; -} - void GattClient::Disconnect() { // There seems to be an issue between some iOS<>Android device pairs where the Android device will // not connect to the iOS device if the iOS device disconnects and then attempts to reconnect. diff --git a/internal/platform/implementation/apple/ble_l2cap_socket.mm b/internal/platform/implementation/apple/ble_l2cap_socket.mm index e44c6728..3cf2f2a3 100644 --- a/internal/platform/implementation/apple/ble_l2cap_socket.mm +++ b/internal/platform/implementation/apple/ble_l2cap_socket.mm @@ -14,9 +14,11 @@ #import "internal/platform/implementation/apple/ble_l2cap_socket.h" +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCBLEL2CAPConnection.h" #import "internal/platform/implementation/apple/utils.h" + #include "internal/platform/implementation/ble.h" namespace nearby { @@ -52,40 +54,81 @@ BleL2capInputStream::~BleL2capInputStream() { } ExceptionOr BleL2capInputStream::Read(std::int64_t size) { - // Block until either (a) the connection has been closed, (b) we have enough data to return. - NSData *dataToReturn; - [condition_ lock]; - while (true) { - // Check if the stream has been closed or severed. - if (!newDataPackets_) break; + if (GNCFeatureFlags.singleCopyEnabled) { + std::string dataToReturn; + bool success = false; - if (newDataPackets_.count > 0) { - // Add the packet data to the accumulated data. - for (NSData *data in newDataPackets_) { - if (data.length > 0) { - [accumulatedData_ appendData:data]; + [condition_ lock]; + while (true) { + // Check if the stream has been closed or severed. + if (!newDataPackets_) break; + + if (newDataPackets_.count > 0) { + // Add the packet data to the accumulated data. + for (NSData *data in newDataPackets_) { + if (data.length > 0) { + [accumulatedData_ appendData:data]; + } } + [newDataPackets_ removeAllObjects]; } - [newDataPackets_ removeAllObjects]; + + if (accumulatedData_.length > 0) { + std::int64_t sizeToReturn = + (accumulatedData_.length < size) ? accumulatedData_.length : size; + NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); + + // Copy bytes directly into std::string, avoiding [NSData subdataWithRange:] + dataToReturn.assign((const char *)accumulatedData_.bytes, sizeToReturn); + [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; + + success = true; + break; + } + [condition_ wait]; } + [condition_ unlock]; - if (accumulatedData_.length > 0) { - // Return up to |size| bytes of the data. - std::int64_t sizeToReturn = (accumulatedData_.length < size) ? accumulatedData_.length : size; - NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); - dataToReturn = [accumulatedData_ subdataWithRange:range]; - [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; - break; + if (success) { + // OPTIMIZATION: Zero-copy transfer from std::string to ByteArray + return ExceptionOr{ByteArray(std::move(dataToReturn))}; + } else { + return ExceptionOr{Exception::kIo}; } - - [condition_ wait]; - } - [condition_ unlock]; - - if (dataToReturn) { - return ExceptionOr{ByteArray((const char *)dataToReturn.bytes, dataToReturn.length)}; } else { - return ExceptionOr{Exception::kIo}; + // Legacy Path + NSData *dataToReturn; + [condition_ lock]; + while (true) { + if (!newDataPackets_) break; + + if (newDataPackets_.count > 0) { + for (NSData *data in newDataPackets_) { + if (data.length > 0) { + [accumulatedData_ appendData:data]; + } + } + [newDataPackets_ removeAllObjects]; + } + + if (accumulatedData_.length > 0) { + std::int64_t sizeToReturn = + (accumulatedData_.length < size) ? accumulatedData_.length : size; + NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); + dataToReturn = [accumulatedData_ subdataWithRange:range]; + [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; + break; + } + [condition_ wait]; + } + [condition_ unlock]; + + if (dataToReturn) { + return ExceptionOr{ + ByteArray((const char *)dataToReturn.bytes, dataToReturn.length)}; + } else { + return ExceptionOr{Exception::kIo}; + } } } @@ -111,7 +154,17 @@ Exception BleL2capOutputStream::Write(absl::string_view data) { return {Exception::kIo}; } - NSMutableData *packet = [NSMutableData dataWithBytes:data.data() length:data.size()]; + NSData *packet; + if (GNCFeatureFlags.singleCopyEnabled) { + // OPTIMIZATION: Use DISPATCH_DATA_DESTRUCTOR_DEFAULT to perform a + // single copy into a GCD-managed buffer. No NSData required. + dispatch_data_t dispatchData = + dispatch_data_create(data.data(), data.size(), nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT); + // dispatch_data_t is toll-free bridged to NSData + packet = (NSData *)dispatchData; + } else { + packet = [NSMutableData dataWithBytes:data.data() length:data.size()]; + } // Send the data, blocking until the completion handler is called. __block BOOL isComplete = NO; diff --git a/internal/platform/implementation/apple/ble_medium.h b/internal/platform/implementation/apple/ble_medium.h index 7c052c43..34695757 100644 --- a/internal/platform/implementation/apple/ble_medium.h +++ b/internal/platform/implementation/apple/ble_medium.h @@ -21,6 +21,7 @@ #import +#include #include #include #include @@ -50,6 +51,10 @@ class BleMedium : public api::ble::BleMedium { friend class BleMediumPeer; public: + // Define factory types for managers. + using PeripheralManagerFactory = std::function; + using CentralManagerFactory = std::function; + BleMedium(); // For testing only. explicit BleMedium(GNCBLEMedium *medium); @@ -207,9 +212,20 @@ class BleMedium : public api::ble::BleMedium { NSDictionary *service_data); NSDate *GetLastTimestampToCleanExpiredAdvertisementPackets(); + // Opens a BLE server socket based on service ID with deadlock safety. + std::unique_ptr OpenServerSocketWithDeadlockSafety( + const std::string &service_id); + + // Opens a BLE server socket based on service ID using the legacy implementation. + std::unique_ptr OpenServerSocketLegacy(const std::string &service_id); + // The executor for handling callbacks. apple::SingleThreadExecutor callback_executor_; + // Factories for lazy initialization + PeripheralManagerFactory peripheral_manager_factory_ = nullptr; + CentralManagerFactory central_manager_factory_ = nullptr; + GNCBLEMedium *medium_; PeripheralsMap peripherals_; @@ -229,14 +245,22 @@ class BleMedium : public api::ble::BleMedium { GNSPeripheralServiceManager *socketPeripheralServiceManager_; GNSPeripheralManager *socketPeripheralManager_; - GNSCentralManager *socketCentralManager_; + + absl::Mutex scanning_mutex_; + GNSCentralManager *socketCentralManager_ ABSL_GUARDED_BY(scanning_mutex_); // Used for the blocking version of StartAdvertising and only has an advertisement found callback. - api::ble::BleMedium::ScanCallback scan_cb_; + std::shared_ptr scan_cb_ ABSL_GUARDED_BY(scanning_mutex_); // Used for the async version of StartAdvertising and has both an advertisement found and result // callback. - api::ble::BleMedium::ScanningCallback scanning_cb_; + std::shared_ptr scanning_cb_ + ABSL_GUARDED_BY(scanning_mutex_); + // Used for the BleServerSocket. + absl::Mutex server_socket_mutex_; + BleServerSocket *server_socket_ptr_ ABSL_GUARDED_BY(server_socket_mutex_) = nullptr; + + // Used for the L2CAP server socket. absl::Mutex l2cap_server_socket_mutex_; BleL2capServerSocket *l2cap_server_socket_ptr_ = nullptr; diff --git a/internal/platform/implementation/apple/ble_medium.mm b/internal/platform/implementation/apple/ble_medium.mm index afefac0b..1120f8b6 100644 --- a/internal/platform/implementation/apple/ble_medium.mm +++ b/internal/platform/implementation/apple/ble_medium.mm @@ -173,11 +173,19 @@ void BleMedium::HandleAdvertisementFound(id peripheral, } #endif - if (scanning_cb_.advertisement_found_cb) { - scanning_cb_.advertisement_found_cb(unique_id, data); + std::shared_ptr scanning_cb; + std::shared_ptr scan_cb; + { + absl::MutexLock lock(&scanning_mutex_); + scanning_cb = scanning_cb_; + scan_cb = scan_cb_; } - if (scan_cb_.advertisement_found_cb) { - scan_cb_.advertisement_found_cb(unique_id, data); + + if (scanning_cb && scanning_cb->advertisement_found_cb) { + scanning_cb->advertisement_found_cb(unique_id, data); + } + if (scan_cb && scan_cb->advertisement_found_cb) { + scan_cb->advertisement_found_cb(unique_id, data); } } @@ -185,7 +193,17 @@ std::unique_ptr BleMedium::StartScanning( const Uuid &service_uuid, api::ble::TxPowerLevel tx_power_level, api::ble::BleMedium::ScanningCallback callback) { CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); - scanning_cb_ = std::move(callback); + + { + absl::MutexLock lock(&scanning_mutex_); + scanning_cb_ = std::make_shared(std::move(callback)); + + if (central_manager_factory_) { + socketCentralManager_ = central_manager_factory_(serviceUUID); + } else { + socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID]; + } + } // 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 @@ -193,8 +211,10 @@ std::unique_ptr BleMedium::StartScanning( peripherals_.Clear(); ClearAdvertisementPacketsMap(); - socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID]; - [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]]; + { + absl::MutexLock lock(&scanning_mutex_); + [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]]; + } dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); __block NSError *blockError = nil; @@ -207,8 +227,13 @@ std::unique_ptr BleMedium::StartScanning( } completionHandler:^(NSError *error) { blockError = error; - if (scanning_cb_.start_scanning_result) { - scanning_cb_.start_scanning_result( + std::shared_ptr scanning_cb; + { + absl::MutexLock lock(&scanning_mutex_); + scanning_cb = scanning_cb_; + } + if (scanning_cb && scanning_cb->start_scanning_result) { + scanning_cb->start_scanning_result( error == nil ? absl::OkStatus() : absl::InternalError(error.localizedDescription.UTF8String)); } @@ -218,8 +243,13 @@ std::unique_ptr BleMedium::StartScanning( dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, kApiTimeoutInSeconds * NSEC_PER_SEC); if (dispatch_semaphore_wait(semaphore, timeout) != 0) { GNCLoggerError(@"Start scanning operation timed out."); - if (scanning_cb_.start_scanning_result) { - scanning_cb_.start_scanning_result(absl::DeadlineExceededError("Start scanning timed out")); + std::shared_ptr scanning_cb; + { + absl::MutexLock lock(&scanning_mutex_); + scanning_cb = scanning_cb_; + } + if (scanning_cb && scanning_cb->start_scanning_result) { + scanning_cb->start_scanning_result(absl::DeadlineExceededError("Start scanning timed out")); } return nullptr; } @@ -239,7 +269,17 @@ std::unique_ptr BleMedium::StartScanning( bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble::TxPowerLevel tx_power_level, api::ble::BleMedium::ScanCallback callback) { CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid); - scan_cb_ = std::move(callback); + + { + absl::MutexLock lock(&scanning_mutex_); + scan_cb_ = std::make_shared(std::move(callback)); + + if (central_manager_factory_) { + socketCentralManager_ = central_manager_factory_(serviceUUID); + } else { + socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID]; + } + } // 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 @@ -247,8 +287,10 @@ bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble::TxPowerLevel t peripherals_.Clear(); ClearAdvertisementPacketsMap(); - socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID]; - [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]]; + { + absl::MutexLock lock(&scanning_mutex_); + [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]]; + } dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); __block NSError *blockError = nil; @@ -286,7 +328,16 @@ bool BleMedium::StartMultipleServicesScanning(const std::vector &service_u [serviceUUIDs addObject:CBUUID128FromCPP(service_uuid)]; } - scan_cb_ = std::move(callback); + { + absl::MutexLock lock(&scanning_mutex_); + scan_cb_ = std::make_shared(std::move(callback)); + + if (central_manager_factory_) { + socketCentralManager_ = central_manager_factory_(serviceUUIDs[0]); + } else { + socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUIDs[0]]; + } + } // 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 @@ -294,8 +345,10 @@ bool BleMedium::StartMultipleServicesScanning(const std::vector &service_u peripherals_.Clear(); ClearAdvertisementPacketsMap(); - socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUIDs[0]]; - [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUIDs[0] ]]; + { + absl::MutexLock lock(&scanning_mutex_); + [socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUIDs[0] ]]; + } dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); __block NSError *blockError = nil; @@ -321,7 +374,12 @@ bool BleMedium::StartMultipleServicesScanning(const std::vector &service_u } bool BleMedium::StopScanning() { - [socketCentralManager_ stopNoScanMode]; + { + absl::MutexLock lock(&scanning_mutex_); + [socketCentralManager_ stopNoScanMode]; + scan_cb_ = nullptr; + scanning_cb_ = nullptr; + } dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); __block NSError *blockError = nil; @@ -448,24 +506,118 @@ std::unique_ptr BleMedium::ConnectToGattServer( // TODO(b/293336684): Old Weave code that need to be deleted once shared Weave is complete. std::unique_ptr BleMedium::OpenServerSocket( const std::string &service_id) { + if (GNCFeatureFlags.fixBleServerSocketDeadlockEnabled) { + return OpenServerSocketWithDeadlockSafety(service_id); + } else { + return OpenServerSocketLegacy(service_id); + } +} + +std::unique_ptr BleMedium::OpenServerSocketWithDeadlockSafety( + const std::string &service_id) { auto server_socket = std::make_unique(); - __block auto server_socket_ptr = server_socket.get(); if (socketPeripheralManager_ == nil) { - socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil - restoreIdentifier:nil]; + if (peripheral_manager_factory_) { + socketPeripheralManager_ = peripheral_manager_factory_(); + } else { + socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil + restoreIdentifier:nil]; + } } - if (socketPeripheralManager_ == nil) { - GNCLoggerError(@"Failed to create peripheral manager."); - return nullptr; + // Fix for b/494335036 (Registry + Background Queue) + { + absl::MutexLock lock(server_socket_mutex_); + server_socket_ptr_ = server_socket.get(); } + server_socket->SetCloseNotifier([this]() { + absl::MutexLock lock(server_socket_mutex_); + server_socket_ptr_ = nullptr; + }); socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc] initWithBleServiceUUID:[CBUUID UUIDWithString:kWeaveServiceUUID] addPairingCharacteristic:NO shouldAcceptSocketHandler:^BOOL(GNSSocket *socket) { - GNCMWaitForConnection(socket, ^(BOOL didConnect) { + // Optimized Path: Use background queue and registry validation. + GNCMWaitForConnection(socket, connection_callback_queue_, ^(BOOL didConnect) { + GNCMBleConnection *connection = + [GNCMBleConnection connectionWithSocket:socket + serviceID:nil + expectedIntroPacket:YES + callbackQueue:connection_callback_queue_]; + + auto socket_wrapper = std::make_unique(connection); + socket_wrapper->SetCloseNotifier( + [socketPeripheralManager = socketPeripheralManager_, + serviceUUID = socketPeripheralServiceManager_.serviceUUID]() { + [socketPeripheralManager + removePeripheralServiceManagerForServiceUUID:serviceUUID + bleServiceRemovedCompletion:^(NSError *_Nullable error) { + GNCLoggerInfo(@"BleSocket is removed peripheral manager."); + }]; + }); + + connection.connectionHandlers = socket_wrapper->GetInputStream().GetConnectionHandlers(); + + // Fix: Verify the BleServerSocket still exists before calling Connect(). + // This prevents the use-after-free/deadlock reported in b/494335036. + absl::MutexLock lock(server_socket_mutex_); + if (server_socket_ptr_) { + server_socket_ptr_->Connect(std::move(socket_wrapper)); + GNCLoggerInfo(@"BleServerSocket is created with connection"); + } else { + GNCLoggerWarning(@"BleServerSocket was destroyed; ignoring connection."); + } + }); + return YES; + }]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block NSError *blockError = nil; + [socketPeripheralManager_ addPeripheralServiceManager:socketPeripheralServiceManager_ + bleServiceAddedCompletion:^(NSError *error) { + if (error != nil) { + GNCLoggerError(@"Failed to add Weave service: %@", error); + blockError = error; + } + dispatch_semaphore_signal(semaphore); + }]; + [socketPeripheralManager_ start]; + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, kApiTimeoutInSeconds * NSEC_PER_SEC); + if (dispatch_semaphore_wait(semaphore, timeout) != 0) { + GNCLoggerError(@"OpenServerSocket operation timed out."); + return nullptr; + } + if (blockError != nil) { + return nullptr; + } + return std::move(server_socket); +} + +std::unique_ptr BleMedium::OpenServerSocketLegacy( + const std::string &service_id) { + auto server_socket = std::make_unique(); + + if (socketPeripheralManager_ == nil) { + if (peripheral_manager_factory_) { + socketPeripheralManager_ = peripheral_manager_factory_(); + } else { + socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil + restoreIdentifier:nil]; + } + } + + // Raw pointer for closure capture in the legacy path (risks use-after-free). + BleServerSocket *server_socket_ptr = server_socket.get(); + + socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc] + initWithBleServiceUUID:[CBUUID UUIDWithString:kWeaveServiceUUID] + addPairingCharacteristic:NO + shouldAcceptSocketHandler:^BOOL(GNSSocket *socket) { + // Legacy Path: Verbatim copy of original code (blocks Main Thread). + GNCMWaitForConnection(socket, nil, ^(BOOL didConnect) { GNCMBleConnection *connection = [GNCMBleConnection connectionWithSocket:socket // This must be nil as the advertiser even though we @@ -588,8 +740,12 @@ std::unique_ptr BleMedium::Connect( return nullptr; } - GNSCentralPeerManager *updatedCentralPeerManager = - [socketCentralManager_ retrieveCentralPeerWithIdentifier:peripheral.identifier]; + GNSCentralPeerManager *updatedCentralPeerManager; + { + absl::MutexLock lock(&scanning_mutex_); + updatedCentralPeerManager = + [socketCentralManager_ retrieveCentralPeerWithIdentifier:peripheral.identifier]; + } if (!updatedCentralPeerManager) { return nullptr; } @@ -603,7 +759,14 @@ std::unique_ptr BleMedium::Connect( dispatch_semaphore_signal(semaphore); return; } - GNCMWaitForConnection(nssocket, ^(BOOL didConnect) { + + // Suggestion: Use the connection callback queue instead of nil + dispatch_queue_t targetQueue = + GNCFeatureFlags.fixBleServerSocketDeadlockEnabled + ? connection_callback_queue_ + : nil; + + GNCMWaitForConnection(nssocket, targetQueue, ^(BOOL didConnect) { if (!didConnect) { dispatch_semaphore_signal(semaphore); return; diff --git a/internal/platform/implementation/apple/ble_socket.mm b/internal/platform/implementation/apple/ble_socket.mm index e34eb9e1..3ea6daf2 100644 --- a/internal/platform/implementation/apple/ble_socket.mm +++ b/internal/platform/implementation/apple/ble_socket.mm @@ -14,13 +14,13 @@ #import "internal/platform/implementation/apple/ble_socket.h" -#include "internal/platform/implementation/ble.h" - +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Mediums/BLE/GNCMBleConnection.h" #import "internal/platform/implementation/apple/ble_peripheral.h" #import "internal/platform/implementation/apple/ble_utils.h" #import "internal/platform/implementation/apple/utils.h" +#include "internal/platform/implementation/ble.h" // TODO(b/293336684): Remove this file when shared Weave is complete. namespace nearby { @@ -55,45 +55,94 @@ BleInputStream::~BleInputStream() { } ExceptionOr BleInputStream::Read(std::int64_t size) { - // Block until either (a) the connection has been closed, (b) we have enough data to return. - NSData *dataToReturn; - [condition_ lock]; - while (true) { - // Check if the stream has been closed or severed. - if (!newDataPackets_) break; + if (GNCFeatureFlags.singleCopyEnabled) { + std::string dataToReturn; + bool success = false; - if (newDataPackets_.count > 0) { - // Add the packet data to the accumulated data. - for (NSData *data in newDataPackets_) { - if (data.length > 0) { - [accumulatedData_ appendData:data]; + [condition_ lock]; + while (true) { + // Check if the stream has been closed or severed. + if (!newDataPackets_) break; + + if (newDataPackets_.count > 0) { + // Add the packet data to the accumulated data. + for (NSData *data in newDataPackets_) { + if (data.length > 0) { + [accumulatedData_ appendData:data]; + } } + [newDataPackets_ removeAllObjects]; } - [newDataPackets_ removeAllObjects]; + + if ((size == -1) && (accumulatedData_.length > 0)) { + // Return all of the data. + dataToReturn.assign((const char *)accumulatedData_.bytes, accumulatedData_.length); + accumulatedData_ = [NSMutableData data]; + success = true; + break; + } else if (accumulatedData_.length > 0) { + // Return up to |size| bytes of the data. + std::int64_t sizeToReturn = + (accumulatedData_.length < size) ? accumulatedData_.length : size; + NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); + // Copy bytes directly into std::string, avoiding [NSData subdataWithRange:] + dataToReturn.assign((const char *)accumulatedData_.bytes, sizeToReturn); + [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; + success = true; + break; + } + + [condition_ wait]; } + [condition_ unlock]; - if ((size == -1) && (accumulatedData_.length > 0)) { - // Return all of the data. - dataToReturn = accumulatedData_; - accumulatedData_ = [NSMutableData data]; - break; - } else if (accumulatedData_.length > 0) { - // Return up to |size| bytes of the data. - std::int64_t sizeToReturn = (accumulatedData_.length < size) ? accumulatedData_.length : size; - NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); - dataToReturn = [accumulatedData_ subdataWithRange:range]; - [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; - break; + if (success) { + // OPTIMIZATION: Zero-copy transfer from std::string to ByteArray + return ExceptionOr{ByteArray(std::move(dataToReturn))}; + } else { + return ExceptionOr{Exception::kIo}; } - - [condition_ wait]; - } - [condition_ unlock]; - - if (dataToReturn) { - return ExceptionOr(ByteArrayFromNSData(dataToReturn)); } else { - return ExceptionOr{Exception::kIo}; + // Legacy path + NSData *dataToReturn; + [condition_ lock]; + while (true) { + // Check if the stream has been closed or severed. + if (!newDataPackets_) break; + + if (newDataPackets_.count > 0) { + for (NSData *data in newDataPackets_) { + if (data.length > 0) { + [accumulatedData_ appendData:data]; + } + } + [newDataPackets_ removeAllObjects]; + } + + if ((size == -1) && (accumulatedData_.length > 0)) { + // Return all of the data. + dataToReturn = accumulatedData_; + accumulatedData_ = [NSMutableData data]; + break; + } else if (accumulatedData_.length > 0) { + // Return up to |size| bytes of the data. + std::int64_t sizeToReturn = + (accumulatedData_.length < size) ? accumulatedData_.length : size; + NSRange range = NSMakeRange(0, (NSUInteger)sizeToReturn); + dataToReturn = [accumulatedData_ subdataWithRange:range]; + [accumulatedData_ replaceBytesInRange:range withBytes:nil length:0]; + break; + } + + [condition_ wait]; + } + [condition_ unlock]; + + if (dataToReturn) { + return ExceptionOr(ByteArrayFromNSData(dataToReturn)); + } else { + return ExceptionOr{Exception::kIo}; + } } } @@ -119,7 +168,17 @@ Exception BleOutputStream::Write(absl::string_view data) { return {Exception::kIo}; } - NSMutableData *packet = [NSMutableData dataWithBytes:data.data() length:data.size()]; + NSData *packet; + if (GNCFeatureFlags.singleCopyEnabled) { + // OPTIMIZATION: Use DISPATCH_DATA_DESTRUCTOR_DEFAULT to perform a + // single copy into a GCD-managed buffer. No NSData required. + dispatch_data_t dispatchData = + dispatch_data_create(data.data(), data.size(), nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT); + // dispatch_data_t is toll-free bridged to NSData + packet = (NSData *)dispatchData; + } else { + packet = [NSMutableData dataWithBytes:data.data() length:data.size()]; + } // Send the data, blocking until the completion handler is called. __block bool isComplete = NO; diff --git a/internal/platform/implementation/apple/condition_variable_test.cc b/internal/platform/implementation/apple/condition_variable_test.cc index 846ad438..4b7af71b 100644 --- a/internal/platform/implementation/apple/condition_variable_test.cc +++ b/internal/platform/implementation/apple/condition_variable_test.cc @@ -16,8 +16,8 @@ #include "gtest/gtest.h" #include "absl/time/clock.h" +#include "third_party/gloop/thread/fiber/fiber.h" #include "internal/platform/implementation/apple/mutex.h" -#include "thread/fiber/fiber.h" namespace nearby { namespace apple { diff --git a/internal/platform/implementation/apple/count_down_latch_test.cc b/internal/platform/implementation/apple/count_down_latch_test.cc index 3b26af10..0f164f7a 100644 --- a/internal/platform/implementation/apple/count_down_latch_test.cc +++ b/internal/platform/implementation/apple/count_down_latch_test.cc @@ -18,7 +18,7 @@ #include "gtest/gtest.h" #include "absl/time/time.h" -#include "thread/fiber/fiber.h" +#include "third_party/gloop/thread/fiber/fiber.h" namespace nearby { namespace apple { diff --git a/internal/platform/implementation/apple/device_info.h b/internal/platform/implementation/apple/device_info.h index ce436201..e42b2b16 100644 --- a/internal/platform/implementation/apple/device_info.h +++ b/internal/platform/implementation/apple/device_info.h @@ -34,17 +34,13 @@ class DeviceInfo : public api::DeviceInfo { api::DeviceInfo::OsType GetOsType() const override; - std::optional GetDownloadPath() const override; + FilePath GetDownloadPath() const override; - std::optional GetLocalAppDataPath() const override; + FilePath GetLocalAppDataPath(FilePath sub_path) const override; - std::optional GetCommonAppDataPath() const override; + FilePath GetTemporaryPath() const override; - std::optional GetTemporaryPath() const override; - - std::optional GetLogPath() const override; - - std::optional GetCrashDumpPath() const override; + FilePath GetLogPath() const override; bool IsScreenLocked() const override; diff --git a/internal/platform/implementation/apple/device_info.mm b/internal/platform/implementation/apple/device_info.mm index 08dc3536..c66f3148 100644 --- a/internal/platform/implementation/apple/device_info.mm +++ b/internal/platform/implementation/apple/device_info.mm @@ -79,7 +79,7 @@ api::DeviceInfo::OsType DeviceInfo::GetOsType() const { #endif } -std::optional DeviceInfo::GetDownloadPath() const { +FilePath DeviceInfo::GetDownloadPath() const { NSFileManager *manager = [NSFileManager defaultManager]; NSError *error = nil; @@ -90,30 +90,24 @@ std::optional DeviceInfo::GetDownloadPath() const { error:&error]; if (!downloadsURL) { GNCLoggerError(@"Failed to get download path: %@", error); - return std::nullopt; + return GetTemporaryPath(); } return FilePath(absl::string_view([downloadsURL.path cString])); } -std::optional DeviceInfo::GetLocalAppDataPath() const { - return FilePath(absl::string_view([GNCLocalAppDataPath().path cString])); +FilePath DeviceInfo::GetLocalAppDataPath(FilePath sub_path) const { + return FilePath(absl::string_view([GNCLocalAppDataPath().path cString])).append(sub_path); } -std::optional DeviceInfo::GetCommonAppDataPath() const { return GetLocalAppDataPath(); } - -std::optional DeviceInfo::GetTemporaryPath() const { +FilePath DeviceInfo::GetTemporaryPath() const { return FilePath(absl::string_view([NSTemporaryDirectory() cString])); } -std::optional DeviceInfo::GetLogPath() const { +FilePath DeviceInfo::GetLogPath() const { return FilePath(absl::string_view([GNCLogPath().path cString])); } -std::optional DeviceInfo::GetCrashDumpPath() const { - return FilePath(absl::string_view([GNCCrashDumpPath().path cString])); -} - bool DeviceInfo::IsScreenLocked() const { return false; } void DeviceInfo::RegisterScreenLockedListener( diff --git a/internal/platform/implementation/apple/mutex_test.cc b/internal/platform/implementation/apple/mutex_test.cc index 4ebadce0..2ad2fce0 100644 --- a/internal/platform/implementation/apple/mutex_test.cc +++ b/internal/platform/implementation/apple/mutex_test.cc @@ -18,7 +18,7 @@ #include "absl/base/thread_annotations.h" #include "absl/synchronization/notification.h" #include "absl/time/time.h" -#include "thread/fiber/fiber.h" +#include "third_party/gloop/thread/fiber/fiber.h" namespace nearby { namespace apple { diff --git a/internal/platform/implementation/apple/platform.mm b/internal/platform/implementation/apple/platform.mm index 5f95d4d6..e11b524b 100644 --- a/internal/platform/implementation/apple/platform.mm +++ b/internal/platform/implementation/apple/platform.mm @@ -45,10 +45,6 @@ #include "internal/platform/implementation/shared/file.h" #include "internal/platform/payload_id.h" -#ifndef NO_WEBRTC -#import "internal/platform/implementation/apple/webrtc.h" -#endif - namespace nearby { namespace api { @@ -205,12 +201,6 @@ std::unique_ptr ImplementationPlatform::CreateWifiDirectMedium return nullptr; } -#ifndef NO_WEBRTC -std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { - return std::make_unique(); -} -#endif - std::unique_ptr ImplementationPlatform::CreateAppLifecycleMonitor( std::function state_updated_callback) { #if TARGET_OS_IPHONE diff --git a/internal/platform/implementation/apple/utils.mm b/internal/platform/implementation/apple/utils.mm index 386e1036..e517310d 100644 --- a/internal/platform/implementation/apple/utils.mm +++ b/internal/platform/implementation/apple/utils.mm @@ -27,11 +27,15 @@ bool CppBoolFromObjCBool(BOOL b) { return b ? true : false; } char CharFromNSNumber(NSNumber* n) { return n.charValue; } NSString* ObjCStringFromCppString(absl::string_view s) { - return [NSString stringWithUTF8String:s.data()]; + return [[NSString alloc] initWithBytes:s.data() length:s.size() encoding:NSUTF8StringEncoding]; } std::string CppStringFromObjCString(NSString* s) { - return std::string([s UTF8String], [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]); + if (!s) return std::string(); + const char* cstr = [s UTF8String]; + if (!cstr) return std::string(); + NSUInteger len = [s lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + return std::string(cstr, len); } NSData* NSDataFromByteArray(ByteArray byteArray) { diff --git a/internal/platform/implementation/apple/webrtc.h b/internal/platform/implementation/apple/webrtc.h deleted file mode 100644 index eb3af040..00000000 --- a/internal/platform/implementation/apple/webrtc.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2025 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_WEBRTC_H_ -#define PLATFORM_IMPL_APPLE_WEBRTC_H_ - -#ifndef NO_WEBRTC - -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/webrtc.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace nearby::apple { - -class WebRtcMedium : public api::WebRtcMedium { - public: - ~WebRtcMedium() override = default; - - // Gets the default two-letter country code associated with current locale. - // For example, en_US locale resolves to "US". - // This follows the ISO 3166-1 Alpha-2 standard. - std::string GetDefaultCountryCode() override; - - // Creates and returns a new webrtc::PeerConnectionInterface object via - // |callback|. - 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 options, - webrtc::PeerConnectionObserver* observer, - PeerConnectionCallback callback) override; - - // Returns a signaling messenger for sending WebRTC signaling messages. - std::unique_ptr GetSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) - override; -}; - -} // namespace nearby::apple - -#endif // #ifndef NO_WEBRTC - -#endif // PLATFORM_IMPL_APPLE_WEBRTC_H_ diff --git a/internal/platform/implementation/apple/webrtc.mm b/internal/platform/implementation/apple/webrtc.mm deleted file mode 100644 index a7a50f79..00000000 --- a/internal/platform/implementation/apple/webrtc.mm +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2025 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 NO_WEBRTC - -#include "internal/platform/implementation/apple/webrtc.h" - -#import - -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/crypto.h" -#include "internal/platform/logging.h" -#include "internal/platform/tachyon_express_signaling_messenger.h" -#include "internal/proto/tachyon.pb.h" -#include "internal/proto/tachyon_enums.proto.h" -#include "webrtc/api/create_modular_peer_connection_factory.h" -#include "webrtc/api/task_queue/default_task_queue_factory.h" - -namespace nearby::apple { - -std::string WebRtcMedium::GetDefaultCountryCode() { - NSString* countryCode = [NSLocale.currentLocale objectForKey:NSLocaleCountryCode]; - if (countryCode) { - return std::string([countryCode UTF8String]); - } - return "US"; -} - -void WebRtcMedium::CreatePeerConnection(webrtc::PeerConnectionObserver* observer, - PeerConnectionCallback callback) { - CreatePeerConnection(std::nullopt, observer, std::move(callback)); -} - -void WebRtcMedium::CreatePeerConnection( - std::optional options, - webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) { - webrtc::PeerConnectionInterface::RTCConfiguration rtc_config; - rtc_config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; - // TODO: b/261663238 - Add the TURN servers and go beyond the default servers. - webrtc::PeerConnectionInterface::IceServer ice_server; - ice_server.urls.emplace_back("stun:stun.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun1.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun2.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun3.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun4.l.google.com:19302"); - rtc_config.servers.push_back(ice_server); - - std::unique_ptr signaling_thread = webrtc::Thread::Create(); - signaling_thread->SetName("signaling_thread", nullptr); - if (!signaling_thread->Start()) { - callback(/*peer_connection=*/nullptr); - return; - } - - webrtc::PeerConnectionDependencies dependencies(observer); - webrtc::PeerConnectionFactoryDependencies factory_dependencies; - factory_dependencies.signaling_thread = signaling_thread.release(); - - webrtc::scoped_refptr peer_connection_factory = - webrtc::CreateModularPeerConnectionFactory(std::move(factory_dependencies)); - if (options.has_value()) { - peer_connection_factory->SetOptions(options.value()); - } - webrtc::RTCErrorOr> - peer_connection_or_error = - peer_connection_factory->CreatePeerConnectionOrError(rtc_config, std::move(dependencies)); - if (peer_connection_or_error.ok()) { - callback(peer_connection_or_error.MoveValue()); - } else { - callback(/*peer_connection=*/nullptr); - } -} - -std::unique_ptr WebRtcMedium::GetSignalingMessenger( - absl::string_view self_id, const location::nearby::connections::LocationHint& location_hint) { - return std::make_unique(self_id, location_hint); -} - -} // namespace nearby::apple - -#endif // #ifndef NO_WEBRTC diff --git a/internal/platform/implementation/apple/webrtc_platform.mm b/internal/platform/implementation/apple/webrtc_platform.mm new file mode 100644 index 00000000..8cc97a86 --- /dev/null +++ b/internal/platform/implementation/apple/webrtc_platform.mm @@ -0,0 +1,39 @@ +// Copyright 2026 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/webrtc_platform.h" + +#import + +#include + +#include "connections/implementation/mediums/webrtc/webrtc_medium_impl.h" + +namespace nearby { +namespace api { + +std::unique_ptr WebRtcImplementationPlatform::CreateWebRtcMedium() { + return std::make_unique(); +} + +std::string WebRtcImplementationPlatform::GetDefaultCountryCode() { + NSString* countryCode = [NSLocale.currentLocale objectForKey:NSLocaleCountryCode]; + if (countryCode) { + return std::string([countryCode UTF8String]); + } + return "US"; +} + +} // namespace api +} // namespace nearby diff --git a/internal/platform/implementation/apple/wifi_hotspot.mm b/internal/platform/implementation/apple/wifi_hotspot.mm index 0ec2e846..d2772330 100644 --- a/internal/platform/implementation/apple/wifi_hotspot.mm +++ b/internal/platform/implementation/apple/wifi_hotspot.mm @@ -23,6 +23,8 @@ #include #include "internal/base/masker.h" #include "internal/platform/cancellation_flag_listener.h" + +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/Hotspot/GNCHotspotMedium.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" @@ -43,12 +45,22 @@ WifiHotspotInputStream::WifiHotspotInputStream(GNCNWFrameworkSocket* socket) : s ExceptionOr WifiHotspotInputStream::Read(std::int64_t size) { NSError* error = nil; - NSData* data = [socket_ readMaxLength:size error:&error]; - if (data == nil) { - GNCLoggerError(@"Error reading socket: %@", error); - return {Exception::kIo}; + if (GNCFeatureFlags.singleCopyEnabled) { + auto result = [socket_ readStringWithMaxLength:size error:&error]; + if (!result.has_value()) { + GNCLoggerError(@"Error reading socket: %@", error); + return {Exception::kIo}; + } + // OPTIMIZATION: Zero-copy transfer from std::string to ByteArray + return ExceptionOr{ByteArray(std::move(result.value()))}; + } else { + NSData* data = [socket_ readMaxLength:size error:&error]; + if (data == nil) { + GNCLoggerError(@"Error reading socket: %@", error); + return {Exception::kIo}; + } + return ExceptionOr{ByteArray((const char*)data.bytes, data.length)}; } - return ExceptionOr{ByteArray((const char*)data.bytes, data.length)}; } Exception WifiHotspotInputStream::Close() { @@ -63,7 +75,15 @@ WifiHotspotOutputStream::WifiHotspotOutputStream(GNCNWFrameworkSocket* socket) : Exception WifiHotspotOutputStream::Write(absl::string_view data) { NSError* error = nil; - BOOL result = [socket_ write:[NSData dataWithBytes:data.data() length:data.size()] error:&error]; + BOOL result = NO; + + if (GNCFeatureFlags.singleCopyEnabled) { + // OPTIMIZATION: Write raw bytes directly, avoiding NSData creation. + result = [socket_ writeBytes:data.data() length:data.size() error:&error]; + } else { + result = [socket_ write:[NSData dataWithBytes:data.data() length:data.size()] error:&error]; + } + if (!result) { GNCLoggerError(@"Error writing socket: %@", error); return {Exception::kIo}; @@ -150,7 +170,7 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( } // 4 bytes IP address format. NSData* host_ip_address = [NSData dataWithBytes:service_address.address.data() - length:service_address.address.size()]; + length:service_address.address.size()]; host = [GNCIPv4Address addressFromData:host_ip_address]; GNCLoggerInfo(@"Connect to Hotspot host server: %@", [host dottedRepresentation]); diff --git a/internal/platform/implementation/apple/wifi_lan.mm b/internal/platform/implementation/apple/wifi_lan.mm index 5f57ba52..984d44de 100644 --- a/internal/platform/implementation/apple/wifi_lan.mm +++ b/internal/platform/implementation/apple/wifi_lan.mm @@ -19,6 +19,7 @@ #include #include +#import "internal/platform/implementation/apple/Flags/GNCFeatureFlags.h" #import "internal/platform/implementation/apple/Log/GNCLogger.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiCommon/GNCNWFramework.h" @@ -35,12 +36,22 @@ WifiLanInputStream::WifiLanInputStream(GNCNWFrameworkSocket* socket) : socket_(s ExceptionOr WifiLanInputStream::Read(std::int64_t size) { NSError* error = nil; - NSData* data = [socket_ readMaxLength:size error:&error]; - if (data == nil) { - GNCLoggerError(@"Error reading socket: %@", error); - return {Exception::kIo}; + if (GNCFeatureFlags.singleCopyEnabled) { + auto result = [socket_ readStringWithMaxLength:size error:&error]; + if (!result.has_value()) { + GNCLoggerError(@"Error reading socket: %@", error); + return {Exception::kIo}; + } + // OPTIMIZATION: Zero-copy transfer from std::string to ByteArray + return ExceptionOr{ByteArray(std::move(result.value()))}; + } else { + NSData* data = [socket_ readMaxLength:size error:&error]; + if (data == nil) { + GNCLoggerError(@"Error reading socket: %@", error); + return {Exception::kIo}; + } + return ExceptionOr{ByteArray((const char*)data.bytes, data.length)}; } - return ExceptionOr{ByteArray((const char*)data.bytes, data.length)}; } Exception WifiLanInputStream::Close() { @@ -55,7 +66,15 @@ WifiLanOutputStream::WifiLanOutputStream(GNCNWFrameworkSocket* socket) : socket_ Exception WifiLanOutputStream::Write(absl::string_view data) { NSError* error = nil; - BOOL result = [socket_ write:[NSData dataWithBytes:data.data() length:data.size()] error:&error]; + BOOL result = NO; + + if (GNCFeatureFlags.singleCopyEnabled) { + // OPTIMIZATION: Write raw bytes directly, avoiding NSData creation. + result = [socket_ writeBytes:data.data() length:data.size() error:&error]; + } else { + result = [socket_ write:[NSData dataWithBytes:data.data() length:data.size()] error:&error]; + } + if (!result) { GNCLoggerError(@"Error writing socket: %@", error); return {Exception::kIo}; diff --git a/internal/platform/implementation/auth_status.h b/internal/platform/implementation/auth_status.h deleted file mode 100644 index 00227836..00000000 --- a/internal/platform/implementation/auth_status.h +++ /dev/null @@ -1,88 +0,0 @@ -// 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_AUTH_STATUS_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_AUTH_STATUS_H_ - -namespace nearby { - -enum AuthStatus { - AUTH_STATUS_UNSPECIFIED = 0, - // Request completed successfully, the results should be in the correct order - // up to the given count. - SUCCESS = 1, - - // Request encountered a generic error. - GENERIC_ERROR = 2, - - // Request as specified is not supported. - UNSUPPORTED = 3, - - // Request failed and should be retried soon. - TEMPORARILY_UNAVAILABLE = 4, - - // Request failed due to an unavailable resource. - UNAVAILABLE_RESOURCE = 5, - - // The request failed due to an invalid argument. - INVALID_ARGUMENT = 6, - - // In case the status could not be retrieved. - UNKNOWN_STATUS = 7, - - // Currently used as a way to signal an ETag mismatch. - PRECONDITION_FAILED = 8, - - // Exclusively used to report when user did not consent to required scopes. - // Do NOT use this for another other scenarios. - PERMISSION_DENIED = 9, - - // The resource exists, but the requested attribute of it does not. - MISSING_ATTRIBUTE = 10, - - // The method was interrupted and the caller should exit the current unit of - // work immediately. - INTERRUPTED = 11, - - // User signed in with an unexpected account. - SIGNED_IN_WITH_WRONG_ACCOUNT = 12, - - // Used when data cannot be parsed properly. - PARSE_ERROR = 13, - - // Used to report that the local HTTP server for receiving the authorization - // code cannot be created. - CANT_CREATE_AUTH_SERVER = 14, - - // Used to report that the system browser for authenticating the user cannot - // be open. - CANT_OPEN_BROWSER_FOR_AUTH = 15, - - // Used to report that the authorization code cannot be received. - CANT_RECEIVE_AUTH_CODE = 16, - - // Used to report that the account is blocked (e.g. CAA). - ACCOUNT_BLOCKED = 17, - - // Receiving the authorization code failed because it took longer than the - // timeout. - AUTH_CODE_TIMEOUT_EXCEEDED = 18, - - // Used to report when user presses the cancel button during login process. - USER_CANCELED = 19, -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_AUTH_STATUS_H_ diff --git a/internal/platform/implementation/ble.h b/internal/platform/implementation/ble.h index 00866e1e..d2f31276 100644 --- a/internal/platform/implementation/ble.h +++ b/internal/platform/implementation/ble.h @@ -29,7 +29,6 @@ #include "absl/status/statusor.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" @@ -155,26 +154,26 @@ struct GattCharacteristic { Property property; // overloading operator for enum class Permission and Property - friend inline Permission operator|(Permission a, Permission b) { + friend Permission operator|(Permission a, Permission b) { return static_cast(static_cast(a) | static_cast(b)); } - friend inline Permission operator&(Permission a, Permission b) { + friend Permission operator&(Permission a, Permission b) { return static_cast(static_cast(a) & static_cast(b)); } - friend inline Permission& operator|=(Permission& a, Permission b) { + friend Permission& operator|=(Permission& a, Permission b) { a = a | b; return a; } - friend inline Property operator|(Property a, Property b) { + friend Property operator|(Property a, Property b) { return static_cast(static_cast(a) | static_cast(b)); } - friend inline Property operator&(Property a, Property b) { + friend Property operator&(Property a, Property b) { return static_cast(static_cast(a) & static_cast(b)); } - friend inline Property& operator|=(Property& a, Property b) { + friend Property& operator|=(Property& a, Property b) { a = a | b; return a; } @@ -231,13 +230,13 @@ class GattClient { // It is okay for duplicate services to exist, as long as the specified // characteristic UUID is unique among all services of the same UUID. // NOLINTNEXTLINE(google3-legacy-absl-backports) - virtual absl::optional GetCharacteristic( + virtual std::optional GetCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#readCharacteristic(android.bluetooth.BluetoothGattCharacteristic) // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#getValue() // NOLINTNEXTLINE(google3-legacy-absl-backports) - virtual absl::optional ReadCharacteristic( + virtual std::optional ReadCharacteristic( const GattCharacteristic& characteristic) = 0; // https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic.html#setValue(byte[]) @@ -248,14 +247,6 @@ class GattClient { virtual bool WriteCharacteristic(const GattCharacteristic& characteristic, absl::string_view value, WriteType type) = 0; - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#setCharacteristicNotification(android.bluetooth.BluetoothGattCharacteristic,%20boolean) - // - // Enable or disable notifications/indications for a given characteristic. - virtual bool SetCharacteristicSubscription( - const GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable - on_characteristic_changed_cb) = 0; - // https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#disconnect() virtual void Disconnect() = 0; }; @@ -281,7 +272,7 @@ class GattServer { // more information about this descriptor, please go to: // https://www.bluetooth.com/specifications/Gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.Gatt.client_characteristic_configuration.xml // NOLINTNEXTLINE(google3-legacy-absl-backports) - virtual absl::optional CreateCharacteristic( + virtual std::optional CreateCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid, GattCharacteristic::Permission permission, GattCharacteristic::Property property) = 0; diff --git a/internal/platform/implementation/device_info.h b/internal/platform/implementation/device_info.h index 19aca037..3d3e859a 100644 --- a/internal/platform/implementation/device_info.h +++ b/internal/platform/implementation/device_info.h @@ -15,12 +15,14 @@ #ifndef PLATFORM_API_DEVICE_INFO_H_ #define PLATFORM_API_DEVICE_INFO_H_ +#include #include #include #include #include "absl/strings/string_view.h" #include "internal/base/file_path.h" +#include "internal/base/files.h" namespace nearby { namespace api { @@ -46,12 +48,15 @@ class DeviceInfo { virtual OsType GetOsType() const = 0; // Gets known paths of current user. - virtual std::optional GetDownloadPath() const = 0; - virtual std::optional GetLocalAppDataPath() const = 0; - virtual std::optional GetCommonAppDataPath() const = 0; - virtual std::optional GetTemporaryPath() const = 0; - virtual std::optional GetLogPath() const = 0; - virtual std::optional GetCrashDumpPath() const = 0; + virtual FilePath GetDownloadPath() const = 0; + virtual FilePath GetLocalAppDataPath(FilePath sub_path) const = 0; + virtual FilePath GetTemporaryPath() const = 0; + virtual FilePath GetLogPath() const = 0; + + virtual std::optional GetAvailableDiskSpaceInBytes( + const FilePath& path) const { + return Files::GetAvailableDiskSpaceInBytes(path); + }; // Monitor screen status virtual bool IsScreenLocked() const = 0; @@ -66,6 +71,24 @@ class DeviceInfo { virtual bool AllowSleep() = 0; }; +template +void AbslStringify(Sink& sink, DeviceInfo::DeviceType device_type) { + switch (device_type) { + case DeviceInfo::DeviceType::kUnknown: + sink.Append("Unknown"); + return; + case DeviceInfo::DeviceType::kPhone: + sink.Append("Phone"); + return; + case DeviceInfo::DeviceType::kTablet: + sink.Append("Tablet"); + return; + case DeviceInfo::DeviceType::kLaptop: + sink.Append("PC"); + return; + } +} + } // namespace api } // namespace nearby diff --git a/presence/device_motion.cc b/internal/platform/implementation/device_info_test.cc similarity index 56% rename from presence/device_motion.cc rename to internal/platform/implementation/device_info_test.cc index 8b79e3f6..cae28209 100644 --- a/presence/device_motion.cc +++ b/internal/platform/implementation/device_info_test.cc @@ -1,4 +1,4 @@ -// Copyright 2020 Google LLC +// Copyright 2026 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,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "presence/device_motion.h" +#include "internal/platform/implementation/device_info.h" -namespace nearby { -namespace presence { +#include "gtest/gtest.h" +#include "absl/strings/str_cat.h" -DeviceMotion::DeviceMotion(MotionType motion_type, float confidence) noexcept - : motion_type_(motion_type), confidence_(confidence) {} -DeviceMotion::MotionType DeviceMotion::GetMotionType() const { - return motion_type_; +namespace nearby::api { +namespace { + +TEST(DeviceInfoTest, DeviceTypeToStringTest) { + DeviceInfo::DeviceType type = DeviceInfo::DeviceType::kPhone; + EXPECT_EQ(absl::StrCat(type), "Phone"); } -float DeviceMotion::GetConfidence() const { return confidence_; } -} // namespace presence -} // namespace nearby +} // namespace +} // namespace nearby::api diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index f2a980a2..6fb81f20 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -85,6 +85,7 @@ cc_library( "bluetooth_adapter.cc", "bluetooth_classic.cc", "credential_storage_impl.cc", + "webrtc.cc", "wifi_direct.cc", "wifi_hotspot.cc", "wifi_lan.cc", @@ -96,6 +97,7 @@ cc_library( "bluetooth_classic.h", "credential_storage_impl.h", "socket_base.h", + "webrtc.h", "wifi.h", "wifi_direct.h", "wifi_hotspot.h", @@ -112,11 +114,14 @@ cc_library( "//internal/platform:types", "//internal/platform:uuid", "//internal/platform/implementation:comm", + "//internal/platform/implementation:webrtc_platform", "//internal/platform/implementation:wifi_utils", "//internal/proto:credential_cc_proto", "//third_party/webrtc/files/stable/webrtc/api:create_modular_peer_connection_factory", - "//third_party/webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", + "//third_party/webrtc/files/stable/webrtc/api:peer_connection_interface", "//third_party/webrtc/files/stable/webrtc/api:scoped_refptr", + "//third_party/webrtc/files/stable/webrtc/rtc_base:checks", + "//third_party/webrtc/files/stable/webrtc/rtc_base:threading", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", @@ -177,8 +182,8 @@ cc_library( testonly = True, srcs = [ "platform.cc", + "webrtc_platform.cc", ], - defines = ["NO_WEBRTC"], visibility = [ "//connections:__subpackages__", "//connections:partners", @@ -191,10 +196,9 @@ cc_library( "//internal/preferences:__subpackages__", "//internal/proto/analytics:__subpackages__", "//internal/weave:__subpackages__", - "//location/nearby/cpp:__subpackages__", "//location/nearby/sharing/sdk:__subpackages__", - "//presence:__subpackages__", "//sharing:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":comm", @@ -208,14 +212,16 @@ cc_library( "//internal/platform/implementation:comm", "//internal/platform/implementation:platform", "//internal/platform/implementation:types", + "//internal/platform/implementation:webrtc_platform", "//internal/platform/implementation/shared:count_down_latch", "//internal/platform/implementation/shared:file", + "//third_party/gloop/thread", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", - "@com_google_nisaba//nisaba/port:thread_pool", ], + alwayslink = 1, ) cc_library( diff --git a/internal/platform/implementation/g3/ble.cc b/internal/platform/implementation/g3/ble.cc index 9e1282b5..573d2cf1 100644 --- a/internal/platform/implementation/g3/ble.cc +++ b/internal/platform/implementation/g3/ble.cc @@ -679,33 +679,6 @@ bool BleMedium::GattClient::WriteCharacteristic( return status.ok(); } -bool BleMedium::GattClient::SetCharacteristicSubscription( - const api::ble::GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable - on_characteristic_changed_cb) { - absl::MutexLock lock(mutex_); - if (!is_connection_alive_) { - return false; - } - Borrowed borrowed = gatt_server_.Borrow(); - if (!borrowed) { - return false; - } - BleMedium::GattServer* gatt_server = - static_cast(*borrowed); - LOG(INFO) << "G3 Ble SetCharacteristicSubscription, characteristic=(" - << characteristic.service_uuid.Get16BitAsString() << "," - << std::string(characteristic.uuid) << "), enable = " << enable; - if (enable) { - return gatt_server->AddCharacteristicSubscription( - peripheral_id_, characteristic, - std::move(on_characteristic_changed_cb)); - } else { - return gatt_server->RemoveCharacteristicSubscription(peripheral_id_, - characteristic); - } -} - void BleMedium::GattClient::Disconnect() { bool was_alive = is_connection_alive_.exchange(false); if (!was_alive) return; diff --git a/internal/platform/implementation/g3/ble.h b/internal/platform/implementation/g3/ble.h index 86c6daf8..e3eacca3 100644 --- a/internal/platform/implementation/g3/ble.h +++ b/internal/platform/implementation/g3/ble.h @@ -282,11 +282,6 @@ class BleMedium : public api::ble::BleMedium { absl::string_view value, api::ble::GattClient::WriteType write_type) override; - bool SetCharacteristicSubscription( - const api::ble::GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable - on_characteristic_changed_cb) override; - void Disconnect() override; void OnServerDisconnected(); diff --git a/internal/platform/implementation/g3/device_info.h b/internal/platform/implementation/g3/device_info.h index 5ff18863..6754d46f 100644 --- a/internal/platform/implementation/g3/device_info.h +++ b/internal/platform/implementation/g3/device_info.h @@ -45,33 +45,24 @@ class DeviceInfo : public api::DeviceInfo { return api::DeviceInfo::OsType::kChromeOs; } - std::optional GetDownloadPath() const override { + FilePath GetDownloadPath() const override { return Files::GetTemporaryDirectory(); } - std::optional GetLocalAppDataPath() const override { + FilePath GetLocalAppDataPath(FilePath sub_path) const override { if (MediumEnvironment::Instance() .GetEnvironmentConfig() .use_temporary_directory_for_app_path) { - return Files::GetTemporaryDirectory(); + return Files::GetTemporaryDirectory().append(sub_path); } - - return GetAppDataPath(); + return GetAppDataPath().append(sub_path); } - std::optional GetCommonAppDataPath() const override { + FilePath GetTemporaryPath() const override { return Files::GetTemporaryDirectory(); } - std::optional GetTemporaryPath() const override { - return Files::GetTemporaryDirectory(); - } - - std::optional GetLogPath() const override { - return Files::GetTemporaryDirectory(); - } - - std::optional GetCrashDumpPath() const override { + FilePath GetLogPath() const override { return Files::GetTemporaryDirectory(); } diff --git a/internal/platform/implementation/g3/platform.cc b/internal/platform/implementation/g3/platform.cc index 02c5afda..dfa62fae 100644 --- a/internal/platform/implementation/g3/platform.cc +++ b/internal/platform/implementation/g3/platform.cc @@ -14,7 +14,6 @@ #include "internal/platform/implementation/platform.h" -#include #include #include #include @@ -25,6 +24,7 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "third_party/gloop/thread/thread.h" #include "internal/base/file_path.h" #include "internal/base/files.h" #include "internal/platform/implementation/app_lifecycle_monitor.h" @@ -55,11 +55,6 @@ #include "internal/platform/logging.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" -#endif #include "internal/platform/implementation/g3/atomic_boolean.h" #include "internal/platform/implementation/g3/atomic_reference.h" #include "internal/platform/implementation/g3/ble.h" @@ -80,7 +75,6 @@ #include "internal/platform/implementation/g3/wifi_lan.h" #include "internal/platform/implementation/shared/file.h" #include "internal/platform/implementation/wifi.h" -#include "internal/platform/medium_environment.h" namespace nearby { namespace api { @@ -219,16 +213,6 @@ ImplementationPlatform::CreateWifiDirectMedium() { return std::make_unique(); } -#ifndef NO_WEBRTC -std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { - if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) { - return std::make_unique(); - } else { - return nullptr; - } -} -#endif - std::unique_ptr ImplementationPlatform::CreateAppLifecycleMonitor( std::function diff --git a/internal/platform/implementation/g3/scheduled_executor.cc b/internal/platform/implementation/g3/scheduled_executor.cc index f82d6f7b..34e7fed9 100644 --- a/internal/platform/implementation/g3/scheduled_executor.cc +++ b/internal/platform/implementation/g3/scheduled_executor.cc @@ -16,16 +16,15 @@ #include #include -#include #include #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/logging.h" #include "internal/platform/medium_environment.h" #include "internal/platform/runnable.h" -#include "internal/test/fake_clock.h" namespace nearby { namespace g3 { @@ -66,20 +65,13 @@ class ScheduledCancelable : public api::Cancelable { } // namespace ScheduledExecutor::ScheduledExecutor() { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - if (fake_clock.has_value()) { - name_ = absl::StrFormat("G3 scheduled executor %p", this); - (*fake_clock)->AddObserver(name_, [this]() { RunReadyTasks(); }); - } + name_ = absl::StrFormat("G3 scheduled executor %p", this); + MediumEnvironment::Instance().AddSimulatedClockObserver( + name_, [this]() { RunReadyTasks(); }); } ScheduledExecutor::~ScheduledExecutor() { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - if (fake_clock.has_value()) { - (*fake_clock)->RemoveObserver(name_); - } + MediumEnvironment::Instance().RemoveSimulatedClockObserver(name_); executor_.Shutdown(); } @@ -96,10 +88,10 @@ std::shared_ptr ScheduledExecutor::Schedule( runnable(); } }; - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - if (fake_clock.has_value()) { - absl::Time trigger_time = (*fake_clock)->Now() + delay; + if (MediumEnvironment::Instance() + .GetEnvironmentConfig() + .use_simulated_clock) { + absl::Time trigger_time = MediumEnvironment::Instance().Now() + delay; absl::MutexLock lock(mutex_); tasks_.insert(std::pair>( trigger_time, std::make_unique(std::move(task)))); @@ -110,15 +102,12 @@ std::shared_ptr ScheduledExecutor::Schedule( } void ScheduledExecutor::RunReadyTasks() { - std::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); if (executor_.InShutdown()) { return; } - if (!fake_clock.has_value()) { - return; - } - absl::Time current_time = (*fake_clock)->Now(); + CHECK( + MediumEnvironment::Instance().GetEnvironmentConfig().use_simulated_clock); + absl::Time current_time = MediumEnvironment::Instance().Now(); absl::MutexLock lock(mutex_); for (auto it = tasks_.begin(); it != tasks_.end();) { if (it->first <= current_time) { diff --git a/internal/platform/implementation/g3/system_clock.cc b/internal/platform/implementation/g3/system_clock.cc index b3cc53c1..430ba5a4 100644 --- a/internal/platform/implementation/g3/system_clock.cc +++ b/internal/platform/implementation/g3/system_clock.cc @@ -15,26 +15,21 @@ #include "internal/platform/implementation/system_clock.h" #include "absl/time/clock.h" +#include "absl/time/time.h" #include "internal/platform/exception.h" #include "internal/platform/medium_environment.h" -#include "internal/test/fake_clock.h" namespace nearby { absl::Time SystemClock::ElapsedRealtime() { - absl::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - if (fake_clock.has_value()) { - return (*fake_clock)->Now(); - } - return absl::Now(); + return MediumEnvironment::Instance().Now(); } Exception SystemClock::Sleep(absl::Duration duration) { - absl::optional fake_clock = - MediumEnvironment::Instance().GetSimulatedClock(); - if (fake_clock.has_value()) { - (*fake_clock)->FastForward(duration); + if (MediumEnvironment::Instance() + .GetEnvironmentConfig() + .use_simulated_clock) { + MediumEnvironment::Instance().FastForward(duration); } else { absl::SleepFor(duration); } diff --git a/internal/platform/implementation/g3/webrtc.cc b/internal/platform/implementation/g3/webrtc.cc index c8385c0c..da43fa31 100644 --- a/internal/platform/implementation/g3/webrtc.cc +++ b/internal/platform/implementation/g3/webrtc.cc @@ -24,10 +24,11 @@ #include "internal/platform/byte_array.h" #include "internal/platform/implementation/webrtc.h" #include "internal/platform/medium_environment.h" -#include "webrtc/api/create_modular_peer_connection_factory.h" -#include "webrtc/api/peer_connection_interface.h" -#include "webrtc/api/scoped_refptr.h" -#include "webrtc/rtc_base/checks.h" +#include "third_party/webrtc/files/stable/webrtc/api/create_modular_peer_connection_factory.h" +#include "third_party/webrtc/files/stable/webrtc/api/peer_connection_interface.h" +#include "third_party/webrtc/files/stable/webrtc/api/scoped_refptr.h" +#include "third_party/webrtc/files/stable/webrtc/rtc_base/checks.h" +#include "third_party/webrtc/files/stable/webrtc/rtc_base/thread.h" namespace nearby { namespace g3 { @@ -60,8 +61,6 @@ void WebRtcSignalingMessenger::StopReceivingMessages() { WebRtcMedium::~WebRtcMedium() { single_thread_executor_.Shutdown(); } -std::string WebRtcMedium::GetDefaultCountryCode() { return "US"; } - void WebRtcMedium::CreatePeerConnection( webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) { CreatePeerConnection(std::nullopt, observer, std::move(callback)); diff --git a/internal/platform/implementation/g3/webrtc.h b/internal/platform/implementation/g3/webrtc.h index 048dabf2..943e27f6 100644 --- a/internal/platform/implementation/g3/webrtc.h +++ b/internal/platform/implementation/g3/webrtc.h @@ -23,7 +23,7 @@ #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" +#include "third_party/webrtc/files/stable/webrtc/api/peer_connection_interface.h" namespace nearby { namespace g3 { @@ -59,8 +59,6 @@ class WebRtcMedium : public api::WebRtcMedium { WebRtcMedium() = default; ~WebRtcMedium() override; - std::string GetDefaultCountryCode() override; - // Creates and returns a new webrtc::PeerConnectionInterface object via // |callback|. void CreatePeerConnection(webrtc::PeerConnectionObserver* observer, diff --git a/internal/platform/implementation/g3/webrtc_platform.cc b/internal/platform/implementation/g3/webrtc_platform.cc new file mode 100644 index 00000000..227f2e69 --- /dev/null +++ b/internal/platform/implementation/g3/webrtc_platform.cc @@ -0,0 +1,39 @@ +// Copyright 2026 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/webrtc_platform.h" + +#include +#include + +#include "internal/platform/implementation/g3/webrtc.h" +#include "internal/platform/implementation/webrtc.h" +#include "internal/platform/medium_environment.h" + +namespace nearby::api { + +std::unique_ptr +WebRtcImplementationPlatform::CreateWebRtcMedium() { + if (MediumEnvironment::Instance().GetEnvironmentConfig().webrtc_enabled) { + return std::make_unique(); + } else { + return nullptr; + } +} + +std::string WebRtcImplementationPlatform::GetDefaultCountryCode() { + return "US"; +} + +} // namespace nearby::api diff --git a/internal/platform/implementation/g3/wifi.h b/internal/platform/implementation/g3/wifi.h index f1439ace..48e287b6 100644 --- a/internal/platform/implementation/g3/wifi.h +++ b/internal/platform/implementation/g3/wifi.h @@ -17,6 +17,9 @@ #include +#include "absl/base/thread_annotations.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" #include "absl/synchronization/mutex.h" #include "internal/platform/implementation/wifi.h" #include "internal/platform/medium_environment.h" diff --git a/internal/platform/implementation/platform.h b/internal/platform/implementation/platform.h index f1ac4ac1..44ee1851 100644 --- a/internal/platform/implementation/platform.h +++ b/internal/platform/implementation/platform.h @@ -39,15 +39,10 @@ #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/submittable_executor.h" #include "internal/platform/implementation/timer.h" -#ifndef NO_WEBRTC -#include "internal/platform/implementation/webrtc.h" -#endif -#ifndef NEARBY_CHROMIUM -#include "internal/platform/implementation/preferences_manager.h" -#endif #include "internal/platform/implementation/wifi.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/wifi_hotspot.h" @@ -136,10 +131,6 @@ class ImplementationPlatform { static std::unique_ptr CreateWifiHotspotMedium(); static std::unique_ptr CreateWifiDirectMedium(); static std::unique_ptr CreateTimer(); - static std::unique_ptr CreateDeviceInfo(); -#ifndef NO_WEBRTC - static std::unique_ptr CreateWebRtcMedium(); -#endif #if defined(NEARBY_CHROMIUM) static std::unique_ptr CreateAppLifecycleMonitor( @@ -147,11 +138,17 @@ class ImplementationPlatform { state_updated_callback) { return nullptr; } + static std::unique_ptr + CreatePreferencesManager(absl::string_view path) { + return nullptr; + } #else static std::unique_ptr CreateAppLifecycleMonitor( std::function state_updated_callback); -#endif + static std::unique_ptr + CreatePreferencesManager(absl::string_view path); + static std::unique_ptr CreateDeviceInfo(); // Gets HTTP response from remote server. // @@ -161,15 +158,6 @@ class ImplementationPlatform { // return WebResponse if HTTP status code between 200 and 300. // other cases will return absl Status in error. static absl::StatusOr SendRequest(const WebRequest& request); - -#if defined(NEARBY_CHROMIUM) - static std::unique_ptr - CreatePreferencesManager(absl::string_view path) { - return nullptr; - } -#else - static std::unique_ptr - CreatePreferencesManager(absl::string_view path); #endif }; diff --git a/presence/presence_advertiser_demo.cc b/internal/platform/implementation/presence_advertiser_demo.cc similarity index 100% rename from presence/presence_advertiser_demo.cc rename to internal/platform/implementation/presence_advertiser_demo.cc diff --git a/presence/presence_scanner_demo.cc b/internal/platform/implementation/presence_scanner_demo.cc similarity index 100% rename from presence/presence_scanner_demo.cc rename to internal/platform/implementation/presence_scanner_demo.cc diff --git a/internal/platform/implementation/shared/file.h b/internal/platform/implementation/shared/file.h index fbf7bfd0..ddc71828 100644 --- a/internal/platform/implementation/shared/file.h +++ b/internal/platform/implementation/shared/file.h @@ -15,7 +15,6 @@ #ifndef PLATFORM_IMPL_SHARED_FILE_H_ #define PLATFORM_IMPL_SHARED_FILE_H_ -#include #include #include #include @@ -23,6 +22,7 @@ #include "absl/strings/string_view.h" #include "absl/time/time.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" @@ -49,7 +49,7 @@ class IOFile final : public api::InputFile, public api::OutputFile { void SetLastModifiedTime(absl::Time last_modified_time) override; private: - explicit IOFile(absl::string_view file_path) : path_(file_path) {}; + explicit IOFile(absl::string_view file_path) : path_(file_path) {} void OpenForRead(); void OpenForWrite(); diff --git a/internal/platform/implementation/signin_attempt.h b/internal/platform/implementation/signin_attempt.h deleted file mode 100644 index aa631a54..00000000 --- a/internal/platform/implementation/signin_attempt.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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_SIGNIN_ATTEMPT_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_SIGNIN_ATTEMPT_H_ - -#include - -#include "absl/functional/any_invocable.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/account_info.h" -#include "internal/platform/implementation/auth_status.h" - -namespace nearby { - -class SigninAttempt { - public: - SigninAttempt() = default; - virtual ~SigninAttempt() = default; - - // Starts a new sign-in attempt. - // `callback` is called with the status of the request, client_id, - // client_secret, and account_info if the request is successful. Returns the - // auth url if the request is successful. - virtual std::string Start( - absl::AnyInvocable - callback) = 0; - - // Tears down the machinery set up to request auth tokens, including the HTTP - // server. - virtual void Close() = 0; -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_SIGNIN_ATTEMPT_H_ diff --git a/internal/platform/implementation/webrtc.h b/internal/platform/implementation/webrtc.h index 57bd14d7..90938bfa 100644 --- a/internal/platform/implementation/webrtc.h +++ b/internal/platform/implementation/webrtc.h @@ -15,17 +15,15 @@ #ifndef PLATFORM_API_WEBRTC_H_ #define PLATFORM_API_WEBRTC_H_ -#ifndef NO_WEBRTC - #include #include -#include #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" -#include "webrtc/api/peer_connection_interface.h" +#include "third_party/webrtc/files/stable/webrtc/api/peer_connection_interface.h" +#include "third_party/webrtc/files/stable/webrtc/api/scoped_refptr.h" namespace nearby { namespace api { @@ -53,10 +51,6 @@ class WebRtcMedium { virtual ~WebRtcMedium() = default; - // Gets the default two-letter country code associated with current locale. - // For example, en_US locale resolves to "US". - virtual std::string GetDefaultCountryCode() = 0; - // Creates and returns a new webrtc::PeerConnectionInterface object via // |callback|. virtual void CreatePeerConnection(webrtc::PeerConnectionObserver* observer, @@ -78,6 +72,4 @@ class WebRtcMedium { } // namespace api } // namespace nearby -#endif - #endif // PLATFORM_API_WEBRTC_H_ diff --git a/internal/platform/implementation/webrtc_platform.h b/internal/platform/implementation/webrtc_platform.h new file mode 100644 index 00000000..a765179f --- /dev/null +++ b/internal/platform/implementation/webrtc_platform.h @@ -0,0 +1,37 @@ +// Copyright 2026 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_WEBRTC_PLATFORM_H_ +#define PLATFORM_API_WEBRTC_PLATFORM_H_ + +#include +#include + +#include "internal/platform/implementation/webrtc.h" + +namespace nearby::api { + +class WebRtcImplementationPlatform { + public: + static std::unique_ptr CreateWebRtcMedium(); + + // Gets the default two-letter country code associated with current locale. + // For example, en_US locale resolves to "US". + // This follows the ISO 3166-1 Alpha-2 standard. + static std::string GetDefaultCountryCode(); +}; + +} // namespace nearby::api + +#endif // PLATFORM_API_WEBRTC_PLATFORM_H_ diff --git a/internal/platform/implementation/wifi_direct.h b/internal/platform/implementation/wifi_direct.h index adfcf55f..6b6112bc 100644 --- a/internal/platform/implementation/wifi_direct.h +++ b/internal/platform/implementation/wifi_direct.h @@ -17,12 +17,12 @@ #include #include +#include #include #include #include #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" #include "internal/platform/input_stream.h" @@ -121,7 +121,7 @@ class WifiDirectMedium { virtual bool DisconnectWifiDirect() = 0; // Returns the port range as a pair of min and max port. - virtual absl::optional> + virtual std::optional> GetDynamicPortRange() = 0; // Returns the supported WifiDirect auth types. diff --git a/internal/platform/implementation/windows/BUILD b/internal/platform/implementation/windows/BUILD index a8357302..94698475 100644 --- a/internal/platform/implementation/windows/BUILD +++ b/internal/platform/implementation/windows/BUILD @@ -74,9 +74,7 @@ cc_library( ], defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"], tags = ["windows"], - visibility = [ - "//sharing/internal/impl/windows:__pkg__", - ], + visibility = ["//visibility:private"], deps = [ ":device_paths", ":string_utils", @@ -151,10 +149,7 @@ cc_library( "WINVER=_WIN32_WINNT_WIN10", ], tags = ["windows"], - visibility = [ - "//:__subpackages__", - "//location/nearby:__subpackages__", - ], + visibility = ["//:__subpackages__"], deps = [ ":socket_address", ":string_utils", @@ -175,10 +170,7 @@ cc_library( ], compatible_with = ["//buildenv/target:non_prod"], tags = ["windows"], - visibility = [ - "//:__subpackages__", - "//location/nearby:__subpackages__", - ], + visibility = ["//location/nearby:__subpackages__"], ) cc_library( @@ -191,10 +183,7 @@ cc_library( ], compatible_with = ["//buildenv/target:non_prod"], tags = ["windows"], - visibility = [ - "//:__subpackages__", - "//location/nearby:__subpackages__", - ], + visibility = ["//location/nearby:__subpackages__"], deps = [ ":scoped_wlan_memory", "//internal/platform:logging", @@ -243,6 +232,18 @@ cc_library( ], ) +cc_library( + name = "webrtc_platform", + srcs = ["webrtc_platform.cc"], + tags = ["windows"], + deps = [ + "//connections/implementation/mediums/webrtc:webrtc_medium_impl", + "//internal/platform:logging", + "//internal/platform/implementation:webrtc_platform", + ], + alwayslink = True, +) + cc_library( name = "windows", srcs = [ @@ -268,7 +269,6 @@ cc_library( "preferences_manager.cc", "preferences_repository.cc", "system_clock.cc", - "webrtc.cc", "wifi_direct_medium.cc", "wifi_direct_server_socket.cc", "wifi_direct_socket.cc", @@ -301,7 +301,6 @@ cc_library( "nearby_server_socket.h", "preferences_manager.h", "preferences_repository.h", - "webrtc.h", "wifi.h", "wifi_direct.h", "wifi_hotspot.h", @@ -316,6 +315,9 @@ cc_library( "-DNO_INTEL_PIE", "-D_WIN32_WINNT=_WIN32_WINNT_WIN10 -DWINVER=_WIN32_WINNT_WIN10", ], + linkopts = [ + "iphlpapi.lib", + ], tags = ["windows"], visibility = [ "//chrome/chromeos/assistant/data_migration/lib:__pkg__", @@ -323,8 +325,8 @@ cc_library( "//connections:partners", "//internal/platform:__subpackages__", "//location/nearby:__subpackages__", - "//presence:__subpackages__", "//sharing:__subpackages__", + "//third_party/nearby/presence:__subpackages__", ], deps = [ ":crypto", # build_cleaner: keep @@ -358,11 +360,6 @@ cc_library( "//internal/platform/implementation/shared:count_down_latch", "//internal/platform/implementation/windows/generated:types", "//third_party/intel/pie", - "//third_party/webrtc/files/stable/webrtc/api:create_modular_peer_connection_factory", - "//third_party/webrtc/files/stable/webrtc/api:libjingle_peerconnection_api", - "//third_party/webrtc/files/stable/webrtc/api:rtc_error", - "//third_party/webrtc/files/stable/webrtc/api:scoped_refptr", - "//third_party/webrtc/files/stable/webrtc/rtc_base:threading", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/container:flat_hash_map", @@ -374,7 +371,6 @@ cc_library( "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", - "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:span", "@com_google_protobuf//:protobuf", "@com_google_protobuf//json", @@ -396,9 +392,7 @@ cc_library( "WINVER=_WIN32_WINNT_WIN10", ], tags = ["windows"], - visibility = [ - "//:__subpackages__", - ], + visibility = ["//visibility:private"], deps = [ "//internal/platform:base", "//internal/platform:logging", @@ -460,7 +454,6 @@ cc_test( "thread_pool_test.cc", "timer_test.cc", "utils_test.cc", - "webrtc_test.cc", "wifi_direct_test.cc", "wifi_hotspot_test.cc", "wifi_medium_test.cc", diff --git a/internal/platform/implementation/windows/ble_gatt_client.cc b/internal/platform/implementation/windows/ble_gatt_client.cc index 83ed7695..78244f1b 100644 --- a/internal/platform/implementation/windows/ble_gatt_client.cc +++ b/internal/platform/implementation/windows/ble_gatt_client.cc @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -30,7 +29,6 @@ #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" -#include "absl/types/optional.h" #include "internal/platform/implementation/ble.h" #include "internal/platform/implementation/windows/bluetooth_adapter.h" #include "internal/platform/implementation/windows/utils.h" @@ -261,7 +259,7 @@ bool BleGattClient::DiscoverServiceAndCharacteristics( return false; } -absl::optional BleGattClient::GetCharacteristic( +std::optional BleGattClient::GetCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid) { absl::MutexLock lock(mutex_); VLOG(1) << __func__ << ": Stared to get characteristic UUID=" @@ -273,7 +271,7 @@ absl::optional BleGattClient::GetCharacteristic( if (!gatt_characteristic.has_value()) { LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic."; - return absl::nullopt; + return std::nullopt; } api::ble::GattCharacteristic result; @@ -323,10 +321,10 @@ absl::optional BleGattClient::GetCharacteristic( << error.code() << ": " << winrt::to_string(error.message()); } - return absl::nullopt; + return std::nullopt; } -absl::optional BleGattClient::ReadCharacteristic( +std::optional BleGattClient::ReadCharacteristic( const api::ble::GattCharacteristic& characteristic) { absl::MutexLock lock(mutex_); VLOG(1) << __func__ @@ -338,7 +336,7 @@ absl::optional BleGattClient::ReadCharacteristic( if (!gatt_characteristic.has_value()) { LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic."; - return absl::nullopt; + return std::nullopt; } GattReadResult result = @@ -347,7 +345,7 @@ absl::optional BleGattClient::ReadCharacteristic( LOG(ERROR) << __func__ << ": Failed to read GATT characteristic with error: " << GattCommunicationStatusToString(result.Status()); - return absl::nullopt; + return std::nullopt; } IBuffer buffer = result.Value(); @@ -377,7 +375,7 @@ absl::optional BleGattClient::ReadCharacteristic( << error.code() << ": " << winrt::to_string(error.message()); } - return absl::nullopt; + return std::nullopt; } bool BleGattClient::WriteCharacteristic( @@ -431,80 +429,6 @@ bool BleGattClient::WriteCharacteristic( return false; } -bool BleGattClient::SetCharacteristicSubscription( - const api::ble::GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable - on_characteristic_changed_cb) { - absl::MutexLock lock(mutex_); - VLOG(1) << __func__ << ": Started to set Characteristic Subscription."; - GattClientCharacteristicConfigurationDescriptorValue gcccd_value = - GattClientCharacteristicConfigurationDescriptorValue::None; - if ((characteristic.property & Property::kNotify) != Property::kNone) { - gcccd_value = GattClientCharacteristicConfigurationDescriptorValue::Notify; - } else if ((characteristic.property & Property::kIndicate) != - Property::kNone) { - gcccd_value = - GattClientCharacteristicConfigurationDescriptorValue::Indicate; - } else { - LOG(WARNING) << "Characeristic: " << std::string(characteristic.uuid) - << " supports neither notifications nor indications."; - return false; - } - - std::optional gatt_characteristic; - - gatt_characteristic = - native_characteristic_map_[characteristic].native_characteristic; - - if (!gatt_characteristic.has_value()) { - LOG(ERROR) << __func__ << ": Failed to get native GATT characteristic."; - return false; - } - - // Write characteristic configuration descriptor - if (!WriteCharacteristicConfigurationDescriptor( - gatt_characteristic.value(), - enable - ? gcccd_value - : GattClientCharacteristicConfigurationDescriptorValue::None)) { - return false; - } - - // Set value changed handler - try { - if (enable) { - native_characteristic_map_[characteristic].on_characteristic_changed_cb = - std::move(on_characteristic_changed_cb); - native_characteristic_map_[characteristic].notification_token = - gatt_characteristic->ValueChanged( - [&](GattCharacteristic const& native_characteristic, - GattValueChangedEventArgs args) { - BleGattClient::OnCharacteristicValueChanged(characteristic, - args); - }); - - if (!native_characteristic_map_[characteristic].notification_token) { - 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, {})); - } - LOG(ERROR) << __func__ << ": Successfully set Characteristic Subscription."; - return true; - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Failed to set Characteristic Subscription." - << exception.what(); - } catch (const winrt::hresult_error& error) { - LOG(ERROR) << __func__ - << ": Failed to set Characteristic Subscription." - " WinRT exception: " - << error.code() << ": " << winrt::to_string(error.message()); - } - return false; -} - void BleGattClient::Disconnect() { absl::MutexLock lock(mutex_); try { @@ -533,12 +457,12 @@ std::optional BleGattClient::GetNativeCharacteristic( try { if (ble_device_ == nullptr) { LOG(ERROR) << __func__ << ": BLE device is disconnected."; - return absl::nullopt; + return std::nullopt; } if (gatt_devices_services_result_ == nullptr) { LOG(ERROR) << __func__ << ": No available GATT services."; - return absl::nullopt; + return std::nullopt; } for (const auto& service : gatt_devices_services_result_.Services()) { @@ -579,7 +503,7 @@ std::optional BleGattClient::GetNativeCharacteristic( << error.code() << ": " << winrt::to_string(error.message()); } - return absl::nullopt; + return std::nullopt; } bool BleGattClient::WriteCharacteristicConfigurationDescriptor( diff --git a/internal/platform/implementation/windows/ble_gatt_client.h b/internal/platform/implementation/windows/ble_gatt_client.h index 651001e1..2f14eca1 100644 --- a/internal/platform/implementation/windows/ble_gatt_client.h +++ b/internal/platform/implementation/windows/ble_gatt_client.h @@ -17,8 +17,6 @@ #include -#include -#include #include #include #include @@ -28,8 +26,6 @@ #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.h" #include "internal/platform/uuid.h" #include "winrt/Windows.Devices.Bluetooth.GenericAttributeProfile.h" @@ -50,11 +46,11 @@ class BleGattClient : public api::ble::GattClient { const std::vector& characteristic_uuids) override ABSL_LOCKS_EXCLUDED(mutex_); - absl::optional GetCharacteristic( + std::optional GetCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid) override ABSL_LOCKS_EXCLUDED(mutex_); - absl::optional ReadCharacteristic( + std::optional ReadCharacteristic( const api::ble::GattCharacteristic& characteristic) override ABSL_LOCKS_EXCLUDED(mutex_); @@ -63,11 +59,6 @@ class BleGattClient : public api::ble::GattClient { api::ble::GattClient::WriteType write_type) override ABSL_LOCKS_EXCLUDED(mutex_); - bool SetCharacteristicSubscription( - const api::ble::GattCharacteristic& characteristic, bool enable, - absl::AnyInvocable - on_characteristic_changed_cb) override ABSL_LOCKS_EXCLUDED(mutex_); - void Disconnect() override ABSL_LOCKS_EXCLUDED(mutex_); private: diff --git a/internal/platform/implementation/windows/ble_gatt_server.cc b/internal/platform/implementation/windows/ble_gatt_server.cc index d3c2a939..cbb540a7 100644 --- a/internal/platform/implementation/windows/ble_gatt_server.cc +++ b/internal/platform/implementation/windows/ble_gatt_server.cc @@ -31,7 +31,6 @@ #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.h" #include "internal/platform/implementation/bluetooth_adapter.h" @@ -114,7 +113,7 @@ BleGattServer::BleGattServer(api::BluetoothAdapter* adapter, DCHECK(adapter_ != nullptr); } -absl::optional +std::optional BleGattServer::CreateCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid, api::ble::GattCharacteristic::Permission permission, @@ -126,7 +125,7 @@ BleGattServer::CreateCharacteristic( if (!service_uuid_.IsEmpty() && service_uuid_ != service_uuid) { LOG(ERROR) << __func__ << ": Only support one GATT service for now."; - return absl::nullopt; + return std::nullopt; } service_uuid_ = service_uuid; diff --git a/internal/platform/implementation/windows/ble_gatt_server.h b/internal/platform/implementation/windows/ble_gatt_server.h index 78ed86b1..52832a9e 100644 --- a/internal/platform/implementation/windows/ble_gatt_server.h +++ b/internal/platform/implementation/windows/ble_gatt_server.h @@ -18,6 +18,7 @@ #include #include +#include #include #include "absl/base/thread_annotations.h" @@ -27,7 +28,6 @@ #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.h" #include "internal/platform/implementation/bluetooth_adapter.h" @@ -47,7 +47,7 @@ class BleGattServer : public api::ble::GattServer { BleGattServer(api::BluetoothAdapter* adapter, api::ble::ServerGattConnectionCallback callback); ~BleGattServer() override = default; - absl::optional CreateCharacteristic( + std::optional CreateCharacteristic( const Uuid& service_uuid, const Uuid& characteristic_uuid, api::ble::GattCharacteristic::Permission permission, api::ble::GattCharacteristic::Property property) override diff --git a/internal/platform/implementation/windows/bluetooth_classic_medium.cc b/internal/platform/implementation/windows/bluetooth_classic_medium.cc index 7dbaf96a..87a80ffd 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/windows/bluetooth_classic_medium.cc @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -39,7 +40,6 @@ #include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.h" #include "internal/platform/implementation/windows/generated/winrt/base.h" #include "internal/platform/implementation/windows/utils.h" -#include "internal/platform/implementation/windows/wifi_lan.h" #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" @@ -72,6 +72,16 @@ constexpr wchar_t kBluetoothSelector[] = L"System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}" L"\""; +// The Id of the Service Name SDP attribute +constexpr uint16_t SdpServiceNameAttributeId = 0x100; + +// The SDP Type of the Service Name SDP attribute. +// The first byte in the SDP Attribute encodes the SDP Attribute Type as +// follows: +// - the Attribute Type size in the least significant 3 bits, +// - the SDP Attribute Type value in the most significant 5 bits. +constexpr char SdpServiceNameAttributeType = (4 << 3) | 5; + void DumpDeviceInformation( const IMapView& properties) { if (!kEnableDumpDeviceInfomation) { @@ -462,17 +472,17 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requested_service) { } auto attributes = requested_service.GetSdpRawAttributesAsync().get(); - if (!attributes.HasKey(Constants::SdpServiceNameAttributeId)) { + if (!attributes.HasKey(SdpServiceNameAttributeId)) { LOG(ERROR) << __func__ << ": Missing SdpServiceNameAttributeId."; return false; } - auto attribute_reader = DataReader::FromBuffer( - attributes.Lookup(Constants::SdpServiceNameAttributeId)); + auto attribute_reader = + DataReader::FromBuffer(attributes.Lookup(SdpServiceNameAttributeId)); auto attribute_type = attribute_reader.ReadByte(); - if (attribute_type != Constants::SdpServiceNameAttributeType) { + if (attribute_type != SdpServiceNameAttributeType) { LOG(ERROR) << __func__ << ": Missing SdpServiceNameAttributeType."; return false; } @@ -958,7 +968,7 @@ bool BluetoothClassicMedium::InitializeServiceSdpAttributes( auto sdp_writer = DataWriter(); // Write the Service Name Attribute. - sdp_writer.WriteByte(Constants::SdpServiceNameAttributeType); + sdp_writer.WriteByte(SdpServiceNameAttributeType); // The length of the UTF-8 encoded Service Name SDP Attribute. sdp_writer.WriteByte(service_name.size()); @@ -968,8 +978,8 @@ bool BluetoothClassicMedium::InitializeServiceSdpAttributes( sdp_writer.WriteString(winrt::to_hstring(service_name)); // Set the SDP Attribute on the RFCOMM Service Provider. - rfcomm_provider.SdpRawAttributes().Insert( - Constants::SdpServiceNameAttributeId, sdp_writer.DetachBuffer()); + rfcomm_provider.SdpRawAttributes().Insert(SdpServiceNameAttributeId, + sdp_writer.DetachBuffer()); return true; } catch (...) { diff --git a/internal/platform/implementation/windows/device_info.cc b/internal/platform/implementation/windows/device_info.cc index ba05e5d3..348f7ce6 100644 --- a/internal/platform/implementation/windows/device_info.cc +++ b/internal/platform/implementation/windows/device_info.cc @@ -30,27 +30,11 @@ #include "internal/platform/implementation/windows/device_paths.h" #include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/implementation/windows/utils.h" -#include "winrt/Windows.Foundation.Collections.h" -#include "winrt/Windows.Foundation.h" -#include "winrt/Windows.System.h" namespace nearby::windows { -using IInspectable = winrt::Windows::Foundation::IInspectable; -using KnownUserProperties = winrt::Windows::System::KnownUserProperties; -using User = winrt::Windows::System::User; -using UserType = winrt::Windows::System::UserType; -using UserAuthenticationStatus = - winrt::Windows::System::UserAuthenticationStatus; - using ::nearby::windows::string_utils::WideStringToString; -template -using IVectorView = winrt::Windows::Foundation::Collections::IVectorView; - -template -using IAsyncOperation = winrt::Windows::Foundation::IAsyncOperation; - std::optional DeviceInfo::GetOsDeviceName() const { std::optional device_name = GetDnsHostName(); if (device_name.has_value()) { @@ -60,7 +44,6 @@ std::optional DeviceInfo::GetOsDeviceName() const { } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { - // TODO(b/230132370): return correct device type on the Windows platform. return api::DeviceInfo::DeviceType::kLaptop; } @@ -68,7 +51,7 @@ api::DeviceInfo::OsType DeviceInfo::GetOsType() const { return api::DeviceInfo::OsType::kWindows; } -std::optional DeviceInfo::GetDownloadPath() const { +FilePath DeviceInfo::GetDownloadPath() const { PWSTR path; HRESULT result = SHGetKnownFolderPath(FOLDERID_Downloads, KF_FLAG_DEFAULT, nullptr, &path); @@ -79,37 +62,19 @@ std::optional DeviceInfo::GetDownloadPath() const { } CoTaskMemFree(path); - return std::nullopt; -} - -std::optional DeviceInfo::GetLocalAppDataPath() const { - return nearby::platform::windows::GetLocalAppDataPath(FilePath()); -} - -std::optional DeviceInfo::GetCommonAppDataPath() const { - PWSTR path; - HRESULT result = SHGetKnownFolderPath(FOLDERID_ProgramData, KF_FLAG_DEFAULT, - /*hToken=*/nullptr, &path); - if (result == S_OK) { - std::wstring common_app_data_path{path}; - CoTaskMemFree(path); - return FilePath(std::wstring_view(common_app_data_path)); - } - - CoTaskMemFree(path); - return std::nullopt; -} - -std::optional DeviceInfo::GetTemporaryPath() const { return Files::GetTemporaryDirectory(); } -std::optional DeviceInfo::GetLogPath() const { - return nearby::platform::windows::GetLogPath(); +FilePath DeviceInfo::GetLocalAppDataPath(FilePath sub_path) const { + return nearby::platform::windows::GetLocalAppDataPath(sub_path); } -std::optional DeviceInfo::GetCrashDumpPath() const { - return nearby::platform::windows::GetCrashDumpPath(); +FilePath DeviceInfo::GetTemporaryPath() const { + return Files::GetTemporaryDirectory(); +} + +FilePath DeviceInfo::GetLogPath() const { + return nearby::platform::windows::GetLogPath(); } bool DeviceInfo::IsScreenLocked() const { diff --git a/internal/platform/implementation/windows/device_info.h b/internal/platform/implementation/windows/device_info.h index 1b4cfe99..8de0d388 100644 --- a/internal/platform/implementation/windows/device_info.h +++ b/internal/platform/implementation/windows/device_info.h @@ -37,12 +37,10 @@ class DeviceInfo : public api::DeviceInfo { api::DeviceInfo::DeviceType GetDeviceType() const override; api::DeviceInfo::OsType GetOsType() const override; - std::optional GetDownloadPath() const override; - std::optional GetLocalAppDataPath() const override; - std::optional GetCommonAppDataPath() const override; - std::optional GetTemporaryPath() const override; - std::optional GetLogPath() const override; - std::optional GetCrashDumpPath() const override; + FilePath GetDownloadPath() const override; + FilePath GetLocalAppDataPath(FilePath sub_path) const override; + FilePath GetTemporaryPath() const override; + FilePath GetLogPath() const override; bool IsScreenLocked() const override; void RegisterScreenLockedListener( diff --git a/internal/platform/implementation/windows/device_info_test.cc b/internal/platform/implementation/windows/device_info_test.cc index 6431e5ea..295992a6 100644 --- a/internal/platform/implementation/windows/device_info_test.cc +++ b/internal/platform/implementation/windows/device_info_test.cc @@ -40,23 +40,20 @@ TEST(DeviceInfo, GetOsType) { } TEST(DeviceInfo, DISABLED_GetLocalAppDataPath) { - EXPECT_TRUE(DeviceInfo().GetLocalAppDataPath().has_value()); + EXPECT_FALSE( + DeviceInfo().GetLocalAppDataPath(FilePath("sub_path")).IsEmpty()); } TEST(DeviceInfo, DISABLED_GetDownloadPath) { - EXPECT_TRUE(DeviceInfo().GetDownloadPath().has_value()); + EXPECT_FALSE(DeviceInfo().GetDownloadPath().IsEmpty()); } TEST(DeviceInfo, DISABLED_GetTemporaryPath) { - EXPECT_TRUE(DeviceInfo().GetTemporaryPath().has_value()); + EXPECT_FALSE(DeviceInfo().GetTemporaryPath().IsEmpty()); } TEST(DeviceInfo, DISABLED_GetLogPath) { - EXPECT_TRUE(DeviceInfo().GetLogPath().has_value()); -} - -TEST(DeviceInfo, DISABLED_GetCrashDumpPath) { - EXPECT_TRUE(DeviceInfo().GetCrashDumpPath().has_value()); + EXPECT_FALSE(DeviceInfo().GetLogPath().IsEmpty()); } TEST(DeviceInfo, DISABLED_IsScreenLocked) { diff --git a/internal/platform/implementation/windows/platform.cc b/internal/platform/implementation/windows/platform.cc index 4d896be9..20004c26 100644 --- a/internal/platform/implementation/windows/platform.cc +++ b/internal/platform/implementation/windows/platform.cc @@ -259,10 +259,6 @@ ImplementationPlatform::CreateWifiDirectMedium() { return std::make_unique(); } -std::unique_ptr ImplementationPlatform::CreateWebRtcMedium() { - return nullptr; -} - std::unique_ptr ImplementationPlatform::CreateAppLifecycleMonitor( std::function diff --git a/internal/platform/implementation/windows/preferences_repository_test.cc b/internal/platform/implementation/windows/preferences_repository_test.cc index 0ef8de90..473e5105 100644 --- a/internal/platform/implementation/windows/preferences_repository_test.cc +++ b/internal/platform/implementation/windows/preferences_repository_test.cc @@ -44,7 +44,8 @@ TEST(PreferencesRepository, LoadWithBadPath) { TEST(PreferencesRepository, RecoverFromBadPreferences) { std::optional app_data_path = - api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath( + FilePath()); ASSERT_TRUE(app_data_path.has_value()); FilePath full_path = app_data_path->append(FilePath(kPreferencesPath)); FilePath full_name = app_data_path->append(FilePath(kPreferencesFileName)); @@ -63,7 +64,8 @@ TEST(PreferencesRepository, RecoverFromBadPreferences) { TEST(PreferencesRepository, SaveAndLoadPreferences) { std::optional app_data_path = - api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath( + FilePath()); ASSERT_TRUE(app_data_path.has_value()); FilePath full_path = app_data_path->append(FilePath(kPreferencesPath)); FilePath full_name = app_data_path->append(FilePath(kPreferencesFileName)); @@ -86,7 +88,8 @@ TEST(PreferencesRepository, SaveAndLoadPreferences) { TEST(PreferencesRepository, LoadFromBackup) { std::optional app_data_path = - api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath( + FilePath()); ASSERT_TRUE(app_data_path.has_value()); FilePath full_path = app_data_path->append(FilePath(kPreferencesPath)); FilePath full_name = app_data_path->append(FilePath(kPreferencesFileName)); @@ -123,7 +126,8 @@ TEST(PreferencesRepository, LoadFromBackup) { TEST(PreferencesRepository, RecoverFromCorruption) { std::optional app_data_path = - api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath( + FilePath()); ASSERT_TRUE(app_data_path.has_value()); FilePath full_path = app_data_path->append(FilePath(kPreferencesPath)); FilePath full_name = app_data_path->append(FilePath(kPreferencesFileName)); diff --git a/internal/platform/implementation/windows/scheduled_executor.cc b/internal/platform/implementation/windows/scheduled_executor.cc index d1bcbf12..87792ff8 100644 --- a/internal/platform/implementation/windows/scheduled_executor.cc +++ b/internal/platform/implementation/windows/scheduled_executor.cc @@ -45,17 +45,7 @@ std::shared_ptr ScheduledExecutor::Schedule( return nullptr; } - if (NearbyFlags::GetInstance().GetBoolFlag( - platform::config_package_nearby::nearby_platform_feature:: - kRunScheduledExecutorCallbackOnExecutorThread)) { - return task_scheduler_.Schedule( - [this, runnable = std::move(runnable)]() mutable { - Execute(std::move(runnable)); - }, - duration); - } else { - return task_scheduler_.Schedule(std::move(runnable), duration); - } + return task_scheduler_.Schedule(std::move(runnable), duration); } void ScheduledExecutor::Execute(Runnable&& runnable) { diff --git a/internal/platform/implementation/windows/utils.cc b/internal/platform/implementation/windows/utils.cc index 62fa4562..ff166f7d 100644 --- a/internal/platform/implementation/windows/utils.cc +++ b/internal/platform/implementation/windows/utils.cc @@ -16,9 +16,6 @@ // clang-format off #include -#include -#include -#include #include #include // clang-format on @@ -33,9 +30,6 @@ #include // Nearby connections headers -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/implementation/crypto.h" #include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/logging.h" #include "internal/platform/uuid.h" @@ -44,127 +38,8 @@ #include "winrt/base.h" namespace nearby::windows { -namespace { -void AddIpUnicastAddresses(IP_ADAPTER_UNICAST_ADDRESS* unicast_addresses, - std::vector& addresses) { - std::string address; - while (unicast_addresses != nullptr) { - DWORD size = INET6_ADDRSTRLEN; // Max IP address length. - address.resize(size); - if (WSAAddressToStringA(unicast_addresses->Address.lpSockaddr, - unicast_addresses->Address.iSockaddrLength, - /*lpProtocolInfo=*/nullptr, address.data(), - &size) != 0) { - LOG(ERROR) << __func__ << ": Cannot convert address to string."; - continue; - } - address.resize(size); - addresses.push_back(address); - unicast_addresses = unicast_addresses->Next; - } -} - -void GetIpAddresses(int family, std::vector& wifi_addresses, - std::vector& ethernet_addresses, - std::vector& other_addresses) { - static constexpr int kDefaultBufferSize = 15 * 1024; // default to 15K buffer - static constexpr int kMaxBufferSize = - 45 * 1024; // Try to increase buffer 2 times. - static constexpr ULONG kDefaultFlags = - GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; - ULONG buffer_size = 0; - // A string to own the memory for IP_ADAPTER_ADDRESSES. - std::string address_buffer; - ULONG error_code = ERROR_NO_DATA; - IP_ADAPTER_ADDRESSES* addresses = nullptr; - do { - buffer_size += kDefaultBufferSize; - address_buffer.reserve(buffer_size); - addresses = reinterpret_cast(address_buffer.data()); - error_code = GetAdaptersAddresses( - family, kDefaultFlags, /*reserved=*/nullptr, addresses, &buffer_size); - } while (error_code == ERROR_BUFFER_OVERFLOW && - buffer_size <= kMaxBufferSize); - if (error_code != ERROR_NO_DATA && error_code != NO_ERROR) { - LOG(ERROR) << __func__ - << ": Cannot get adapter addresses. Error code: " << error_code; - return; - } - if (error_code == ERROR_NO_DATA) { - LOG(INFO) << __func__ << ": No IPv4 addresses found."; - return; - } - IP_ADAPTER_ADDRESSES* next_address = addresses; - while (next_address != nullptr) { - if (next_address->OperStatus == IfOperStatusUp) { - if (next_address->IfType == IF_TYPE_ETHERNET_CSMACD) { - VLOG(1) << "Found ethernet adater: " << next_address->AdapterName - << " index: " << next_address->IfIndex - << " v6 index: " << next_address->Ipv6IfIndex; - AddIpUnicastAddresses(next_address->FirstUnicastAddress, - ethernet_addresses); - } else if (next_address->IfType == IF_TYPE_IEEE80211) { - VLOG(1) << "Found wifi adapter: " << next_address->AdapterName - << " index: " << next_address->IfIndex - << " v6 index: " << next_address->Ipv6IfIndex; - AddIpUnicastAddresses(next_address->FirstUnicastAddress, - wifi_addresses); - } else if (next_address->IfType != IF_TYPE_SOFTWARE_LOOPBACK) { - // Skip loopback interfaces. - VLOG(1) << "Found other adapter: " << next_address->AdapterName; - AddIpUnicastAddresses(next_address->FirstUnicastAddress, - other_addresses); - } - } - next_address = next_address->Next; - } -} - -} // namespace - -std::string ipaddr_4bytes_to_dotdecimal_string( - absl::string_view ipaddr_4bytes) { - if (ipaddr_4bytes.size() != 4) { - return {}; - } - - in_addr address; - address.S_un.S_un_b.s_b1 = ipaddr_4bytes[0]; - address.S_un.S_un_b.s_b2 = ipaddr_4bytes[1]; - address.S_un.S_un_b.s_b3 = ipaddr_4bytes[2]; - address.S_un.S_un_b.s_b4 = ipaddr_4bytes[3]; - char* ipv4_address = inet_ntoa(address); - if (ipv4_address == nullptr) { - return {}; - } - - return std::string(ipv4_address); -} - -std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s) { - if (ipv4_s.empty()) { - return {}; - } - - in_addr address; - address.S_un.S_addr = inet_addr(ipv4_s.c_str()); - char ipv4_b[5]; - ipv4_b[0] = address.S_un.S_un_b.s_b1; - ipv4_b[1] = address.S_un.S_un_b.s_b2; - ipv4_b[2] = address.S_un.S_un_b.s_b3; - ipv4_b[3] = address.S_un.S_un_b.s_b4; - ipv4_b[4] = 0; - - return std::string(ipv4_b, 4); -} - -std::vector GetIpv4Addresses() { - std::vector result; - GetIpAddresses(AF_INET, result, result, result); - return result; -} +using winrt::Windows::Foundation::IInspectable; Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid) { int64_t data1 = guid.Data1; @@ -209,11 +84,6 @@ bool is_nearby_uuid_equal_to_winrt_guid(const Uuid& uuid, return uuid == winrt_guid_to_nearby_uuid(guid); } -ByteArray Sha256(absl::string_view input, size_t size) { - ByteArray hash = nearby::Crypto::Sha256(input); - return ByteArray{hash.data(), size}; -} - bool InspectableReader::ReadBoolean(IInspectable inspectable) { if (inspectable == nullptr) { return false; diff --git a/internal/platform/implementation/windows/utils.h b/internal/platform/implementation/windows/utils.h index 52483dd9..b3910c6a 100644 --- a/internal/platform/implementation/windows/utils.h +++ b/internal/platform/implementation/windows/utils.h @@ -23,8 +23,6 @@ #include #include -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" #include "internal/platform/uuid.h" #include "winrt/Windows.Foundation.h" #include "winrt/base.h" @@ -32,17 +30,6 @@ namespace nearby { namespace windows { -using winrt::Windows::Foundation::IInspectable; - -std::string ipaddr_4bytes_to_dotdecimal_string(absl::string_view ipaddr_4bytes); -std::string ipaddr_dotdecimal_to_4bytes_string(std::string ipv4_s); - -// Helpers to windows platform -ByteArray Sha256(absl::string_view input, size_t size); - -// Reads the IPv4 addresses -std::vector GetIpv4Addresses(); - // Help methods to convert between Uuid and winrt::guid Uuid winrt_guid_to_nearby_uuid(const ::winrt::guid& guid); winrt::guid nearby_uuid_to_winrt_guid(Uuid uuid); @@ -57,31 +44,18 @@ std::optional GetDnsHostName(); // Returns true if the system has an Intel Wi-Fi adapter. bool IsIntelWifiAdapter(); -namespace Constants { -// The Id of the Service Name SDP attribute -const uint16_t SdpServiceNameAttributeId = 0x100; - -// The SDP Type of the Service Name SDP attribute. -// The first byte in the SDP Attribute encodes the SDP Attribute Type as -// follows: -// - the Attribute Type size in the least significant 3 bits, -// - the SDP Attribute Type value in the most significant 5 bits. -const char SdpServiceNameAttributeType = (4 << 3) | 5; - -// Possible values for the adapter type. Refer to: -// https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_info -const uint16_t kInterfaceTypeEthernet = 6; -const uint16_t kInterfaceTypeWifi = 71; -} // namespace Constants - class InspectableReader { public: - static bool ReadBoolean(IInspectable inspectable); - static uint16_t ReadUint16(IInspectable inspectable); - static uint32_t ReadUint32(IInspectable inspectable); - static std::string ReadString(IInspectable inspectable); - static std::vector ReadStringArray(IInspectable inspectable); - static GUID ReadGuid(IInspectable inspectable); + static bool ReadBoolean(winrt::Windows::Foundation::IInspectable inspectable); + static uint16_t ReadUint16( + winrt::Windows::Foundation::IInspectable inspectable); + static uint32_t ReadUint32( + winrt::Windows::Foundation::IInspectable inspectable); + static std::string ReadString( + winrt::Windows::Foundation::IInspectable inspectable); + static std::vector ReadStringArray( + winrt::Windows::Foundation::IInspectable inspectable); + static GUID ReadGuid(winrt::Windows::Foundation::IInspectable inspectable); }; } // namespace windows diff --git a/internal/platform/implementation/windows/utils_test.cc b/internal/platform/implementation/windows/utils_test.cc index 54bb7bea..5ee19153 100644 --- a/internal/platform/implementation/windows/utils_test.cc +++ b/internal/platform/implementation/windows/utils_test.cc @@ -24,8 +24,6 @@ #include #include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" #include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/logging.h" #include "internal/platform/uuid.h" @@ -38,62 +36,8 @@ namespace { using ::winrt::Windows::Foundation::IInspectable; using ::winrt::Windows::Foundation::PropertyValue; -constexpr absl::string_view kIpDotdecimal{"192.168.1.37"}; -constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37}; - } // namespace -TEST(UtilsTests, Ip4BytesToDotdecimal) { - std::string result = - ipaddr_4bytes_to_dotdecimal_string(absl::string_view(kIp4Bytes, 4)); - - EXPECT_EQ(result, kIpDotdecimal); -} - -TEST(UtilsTests, Ip4BytesToDotdecimalInvalid) { - std::string result = ipaddr_4bytes_to_dotdecimal_string(absl::string_view()); - EXPECT_TRUE(result.empty()); -} - -TEST(UtilsTests, IpDotdecimalTo4Bytes) { - std::string result = - ipaddr_dotdecimal_to_4bytes_string(std::string(kIpDotdecimal)); - - EXPECT_EQ(result, std::string(kIp4Bytes, 4)); -} - -TEST(UtilsTests, IpDotdecimalTo4BytesEmpty) { - std::string result = ipaddr_dotdecimal_to_4bytes_string(""); - EXPECT_TRUE(result.empty()); -} - -TEST(UtilsTests, IpDotdecimalTo4BytesInvalid) { - std::string result = ipaddr_dotdecimal_to_4bytes_string("192.168.1.256"); - // inet_addr returns INADDR_NONE for invalid address. - char expected[] = {(char)255, (char)255, (char)255, (char)255}; - EXPECT_EQ(result, std::string(expected, 4)); -} - -TEST(UtilsTests, Sha256) { - std::string input = "Hello World"; - // sha256("Hello World") - const char expected_sha256[] = { - (char)0xa5, (char)0x91, (char)0xa6, (char)0xd4, (char)0x0b, (char)0xf4, - (char)0x20, (char)0x40, (char)0x4a, (char)0x01, (char)0x17, (char)0x33, - (char)0xcf, (char)0xb7, (char)0xb1, (char)0x90, (char)0xd6, (char)0x2c, - (char)0x65, (char)0xbf, (char)0x0b, (char)0xcd, (char)0xa3, (char)0x2b, - (char)0x57, (char)0xb2, (char)0x77, (char)0xd9, (char)0xad, (char)0x9f, - (char)0x14, (char)0x6e}; - - ByteArray result = Sha256(input, 32); - EXPECT_EQ(result.size(), 32); - EXPECT_EQ(memcmp(result.data(), expected_sha256, 32), 0); - - result = Sha256(input, 16); - EXPECT_EQ(result.size(), 16); - EXPECT_EQ(memcmp(result.data(), expected_sha256, 16), 0); -} - TEST(UtilsTests, ConvertBetweenWinrtGuidAndNearbyUuidSuccessfully) { Uuid uuid(0x123e4567e89b12d3, 0xa456426614174000); winrt::guid guid("{123e4567-e89b-12d3-a456-426614174000}"); @@ -157,16 +101,6 @@ TEST(UtilsTests, InspectableReader_ReadStringArray) { std::invalid_argument); } -TEST(UtilsTests, GetIpv4Addresses) { - LOG(ERROR) << "GetIpv4Addresses"; - std::vector addresses = GetIpv4Addresses(); - EXPECT_FALSE(addresses.empty()); - for (const auto& address : addresses) { - LOG(ERROR) << "address: " << address; - } - LOG(ERROR) << "GetIpv4Addresses done"; -} - TEST(UtilsTests, GetDnsHostName) { std::optional host_name = GetDnsHostName(); ASSERT_TRUE(host_name.has_value()); diff --git a/internal/platform/implementation/windows/webrtc.cc b/internal/platform/implementation/windows/webrtc.cc deleted file mode 100644 index 85fa989d..00000000 --- a/internal/platform/implementation/windows/webrtc.cc +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 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. -// 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/webrtc.h" - -#include - -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/webrtc.h" -#include "internal/platform/logging.h" -#include "internal/platform/tachyon_express_signaling_messenger.h" -#include "webrtc/api/create_modular_peer_connection_factory.h" -#include "webrtc/api/peer_connection_interface.h" -#include "webrtc/api/rtc_error.h" -#include "webrtc/api/scoped_refptr.h" -#include "webrtc/rtc_base/thread.h" - -namespace nearby::windows { - -std::string WebRtcMedium::GetDefaultCountryCode() { - wchar_t systemGeoName[LOCALE_NAME_MAX_LENGTH]; - - if (!GetUserDefaultGeoName(systemGeoName, LOCALE_NAME_MAX_LENGTH)) { - LOG(ERROR) << __func__ - << ": Failed to GetUserDefaultGeoName: " << ". Fall back to US."; - return "US"; - } - std::wstring wideGeo(systemGeoName); - std::string systemGeoNameString(wideGeo.begin(), wideGeo.end()); - VLOG(1) << "GetUserDefaultGeoName() returns: " << systemGeoNameString; - return systemGeoNameString; -} - -void WebRtcMedium::CreatePeerConnection( - webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) { - CreatePeerConnection(std::nullopt, observer, std::move(callback)); -} - -void WebRtcMedium::CreatePeerConnection( - std::optional options, - webrtc::PeerConnectionObserver* observer, PeerConnectionCallback callback) { - webrtc::PeerConnectionInterface::RTCConfiguration rtc_config; - rtc_config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; - // TODO: b/261663238 - Add the TURN servers and go beyond the default servers. - webrtc::PeerConnectionInterface::IceServer ice_server; - ice_server.urls.emplace_back("stun:stun.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun1.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun2.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun3.l.google.com:19302"); - ice_server.urls.emplace_back("stun:stun4.l.google.com:19302"); - rtc_config.servers.push_back(ice_server); - - std::unique_ptr signaling_thread = webrtc::Thread::Create(); - signaling_thread->SetName("signaling_thread", nullptr); - if (!signaling_thread->Start()) { - callback(/*peer_connection=*/nullptr); - return; - } - - webrtc::PeerConnectionDependencies dependencies(observer); - webrtc::PeerConnectionFactoryDependencies factory_dependencies; - factory_dependencies.signaling_thread = signaling_thread.release(); - - webrtc::scoped_refptr - peer_connection_factory = webrtc::CreateModularPeerConnectionFactory( - std::move(factory_dependencies)); - if (options.has_value()) { - peer_connection_factory->SetOptions(options.value()); - } - webrtc::RTCErrorOr> - peer_connection_or_error = - peer_connection_factory->CreatePeerConnectionOrError( - rtc_config, std::move(dependencies)); - if (peer_connection_or_error.ok()) { - callback(peer_connection_or_error.MoveValue()); - } else { - callback(/*peer_connection=*/nullptr); - } -} - -std::unique_ptr -WebRtcMedium::GetSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) { - return std::make_unique(self_id, - location_hint); -} - -} // namespace nearby::windows diff --git a/internal/platform/implementation/windows/webrtc.h b/internal/platform/implementation/windows/webrtc.h deleted file mode 100644 index 2c5b3fb3..00000000 --- a/internal/platform/implementation/windows/webrtc.h +++ /dev/null @@ -1,58 +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_WEBRTC_H_ -#define PLATFORM_IMPL_WINDOWS_WEBRTC_H_ - -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/webrtc.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace nearby::windows { - -class WebRtcMedium : public api::WebRtcMedium { - public: - ~WebRtcMedium() override = default; - - // Gets the default two-letter country code associated with current locale. - // For example, en_US locale resolves to "US". - // This follows the ISO 3166-1 Alpha-2 standard. - std::string GetDefaultCountryCode() override; - - // Creates and returns a new webrtc::PeerConnectionInterface object via - // |callback|. - 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 options, - webrtc::PeerConnectionObserver* observer, - PeerConnectionCallback callback) override; - - // Returns a signaling messenger for sending WebRTC signaling messages. - std::unique_ptr GetSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) - override; -}; - -} // namespace nearby::windows - -#endif // PLATFORM_IMPL_WINDOWS_WEBRTC_H_ diff --git a/internal/platform/implementation/windows/webrtc_platform.cc b/internal/platform/implementation/windows/webrtc_platform.cc new file mode 100644 index 00000000..fe7bc8fa --- /dev/null +++ b/internal/platform/implementation/windows/webrtc_platform.cc @@ -0,0 +1,47 @@ +// Copyright 2026 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/webrtc_platform.h" + +#include + +#include +#include + +#include "internal/platform/logging.h" +#include "internal/platform/implementation/webrtc.h" +#include "connections/implementation/mediums/webrtc/webrtc_medium_impl.h" + +namespace nearby::api { + +std::unique_ptr +WebRtcImplementationPlatform::CreateWebRtcMedium() { + return std::make_unique(); +} + +std::string WebRtcImplementationPlatform::GetDefaultCountryCode() { + wchar_t systemGeoName[LOCALE_NAME_MAX_LENGTH]; + + if (!GetUserDefaultGeoName(systemGeoName, LOCALE_NAME_MAX_LENGTH)) { + LOG(ERROR) << __func__ + << ": Failed to GetUserDefaultGeoName: " << ". Fall back to US."; + return "US"; + } + std::wstring wideGeo(systemGeoName); + std::string systemGeoNameString(wideGeo.begin(), wideGeo.end()); + VLOG(1) << "GetUserDefaultGeoName() returns: " << systemGeoNameString; + return systemGeoNameString; +} + +} // namespace nearby::api diff --git a/internal/platform/implementation/windows/webrtc_test.cc b/internal/platform/implementation/windows/webrtc_test.cc deleted file mode 100644 index 708e0efc..00000000 --- a/internal/platform/implementation/windows/webrtc_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 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. -// 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/webrtc.h" - -#include -#include -#include - -#include "gtest/gtest.h" -#include "internal/platform/implementation/webrtc.h" -#include "webrtc/api/data_channel_interface.h" -#include "webrtc/api/jsep.h" -#include "webrtc/api/peer_connection_interface.h" -#include "webrtc/api/scoped_refptr.h" - -namespace nearby { -namespace windows { - -class MockPeerConnectionObserver : public webrtc::PeerConnectionObserver { - public: - void OnSignalingChange( - webrtc::PeerConnectionInterface::SignalingState new_state) override {} - - void OnDataChannel(webrtc::scoped_refptr - data_channel) override {} - - void OnIceGatheringChange( - webrtc::PeerConnectionInterface::IceGatheringState new_state) override {} - - void OnIceCandidate(const webrtc::IceCandidate* candidate) override {} -}; - -location::nearby::connections::LocationHint GetCountryCodeLocationHint( - const std::string& country_code) { - auto location_hint = location::nearby::connections::LocationHint(); - location_hint.set_location(country_code); - location_hint.set_format( - location::nearby::connections::LocationStandard::ISO_3166_1_ALPHA_2); - return location_hint; -} - -TEST(WebrtcTest, CountryCodeDefault) { - WebRtcMedium medium; - std::string result = medium.GetDefaultCountryCode(); - EXPECT_EQ(result, "US"); -} - -TEST(WebrtcTest, CreatePeerConnectionSucceeds) { - auto observer = std::make_unique(); - WebRtcMedium medium; - medium.CreatePeerConnection( - std::nullopt, observer.get(), - [](webrtc::scoped_refptr - peer_connection) mutable { - if (!peer_connection) { - FAIL() << "Peer connection should have been non-null"; - return; - } - }); -} - -TEST(WebrtcTest, GetSignalingMessengerSucceeds) { - WebRtcMedium medium; - std::unique_ptr messenger = - medium.GetSignalingMessenger("US", GetCountryCodeLocationHint("US")); - EXPECT_TRUE(messenger); -} - -} // namespace windows -} // namespace nearby diff --git a/internal/platform/implementation/windows/wifi_direct_medium.cc b/internal/platform/implementation/windows/wifi_direct_medium.cc index 1783c3c9..00e390eb 100644 --- a/internal/platform/implementation/windows/wifi_direct_medium.cc +++ b/internal/platform/implementation/windows/wifi_direct_medium.cc @@ -20,6 +20,7 @@ #include #include +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" @@ -41,6 +42,15 @@ namespace nearby { namespace windows { namespace { constexpr int kWaitingForConnectionTimeoutSeconds = 90; // seconds +// The prefix of the service name. +// Fully Qualified Service Name (FQSN) must follow reverse-DNS notation to +// ensure uniqueness and cross-platform compatibility. Otherwise, Windows +// prefixes the service name with "org.wi-fi.wfds.", which prevents Android +// devices from discovering the service. +// https://www.wi-fi.org/file-member/wi-fi-peer-to-peer-services-technical-specification-package +// Wi-Fi_Peer-to-Peer_Services_Technical_Specification_v1.2.pdf chapter 3.2 +constexpr absl::string_view kServiceNamePrefix = + "com.google.nearby.connection."; } // namespace WifiDirectMedium::WifiDirectMedium() { @@ -294,7 +304,8 @@ bool WifiDirectMedium::StartWifiDirect( std::string pin = absl::StrFormat("%04x", prng.NextUint32()); credentials_go_->SetPin(pin); - std::string service_name = "NC-" + std::to_string(prng.NextUint32()); + std::string service_name = + absl::StrCat(kServiceNamePrefix, std::to_string(prng.NextUint32())); credentials_go_->SetServiceName(service_name); LOG(INFO) << "service_name:pin " << service_name << ":" << pin; diff --git a/internal/platform/implementation/windows/wifi_direct_test.cc b/internal/platform/implementation/windows/wifi_direct_test.cc index 9be5e148..b6d91c1f 100644 --- a/internal/platform/implementation/windows/wifi_direct_test.cc +++ b/internal/platform/implementation/windows/wifi_direct_test.cc @@ -19,6 +19,8 @@ #include #include "gtest/gtest.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "internal/platform/implementation/wifi_direct.h" @@ -28,7 +30,13 @@ namespace nearby { namespace windows { namespace { - +constexpr absl::string_view kServiceNamePrefix = + "com.google.nearby.connection."; +// Tests are prefixed with DISABLED_ for several reasons: 1. They require user +// interaction, 2. They have access to Windows APIs and physical WiFi hardware. +// These tests are intended for validation on actual Windows machines, 3. By +// using the DISABLED_ prefix, we can Keep the code in the repo and prevent CI +// failures. TEST(WifiDirectMedium, DISABLED_StartWifiDirect) { int run_test; LOG(INFO) << "Run StartWifiDirect test case? input 0 or 1:"; @@ -72,7 +80,9 @@ TEST(WifiDirectMedium, DISABLED_ConnectWifiDirect) { LOG(INFO) << "Enter pin: "; std::string pin; std::cin >> pin; - credentials.SetServiceName(service_name); + std::string service_name_with_prefix = + absl::StrCat(kServiceNamePrefix, service_name); + credentials.SetServiceName(service_name_with_prefix); credentials.SetPin(pin); EXPECT_TRUE(wifi_direct_medium.ConnectWifiDirect(credentials)); @@ -147,7 +157,9 @@ TEST(WifiDirectMedium, DISABLED_WifiDirectConnectToServiceServer) { LOG(INFO) << "Enter pin: "; std::string pin; std::cin >> pin; - credentials.SetServiceName(service_name); + std::string service_name_with_prefix = + absl::StrCat(kServiceNamePrefix, service_name); + credentials.SetServiceName(service_name_with_prefix); credentials.SetPin(pin); EXPECT_TRUE(wifi_direct_medium.ConnectWifiDirect(credentials)); diff --git a/internal/platform/implementation/windows/wifi_hotspot.h b/internal/platform/implementation/windows/wifi_hotspot.h index c6b4c34a..b68926ec 100644 --- a/internal/platform/implementation/windows/wifi_hotspot.h +++ b/internal/platform/implementation/windows/wifi_hotspot.h @@ -111,7 +111,7 @@ class WifiHotspotMedium : public api::WifiHotspotMedium { WiFiDirectConnectionListener listener_{nullptr}; // The list of WiFiDirectDevice is used to keep hotspot connection alive. - std::list wifi_direct_devices_; + std::list wifi_direct_devices_ ABSL_GUARDED_BY(mutex_); fire_and_forget OnStatusChanged( WiFiDirectAdvertisementPublisher sender, diff --git a/internal/platform/implementation/windows/wifi_hotspot_medium.cc b/internal/platform/implementation/windows/wifi_hotspot_medium.cc index 288efe14..e6ca86bd 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_medium.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_medium.cc @@ -349,7 +349,10 @@ fire_and_forget WifiHotspotMedium::OnConnectionRequested( auto wifi_direct_device = WiFiDirectDevice::FromIdAsync( connection_request.DeviceInformation().Id()) .get(); - wifi_direct_devices_.push_back(wifi_direct_device); + { + absl::MutexLock lock(mutex_); + wifi_direct_devices_.push_back(wifi_direct_device); + } LOG(INFO) << "Registered the device " << winrt::to_string(device_name) << " in WLAN-AutoConfig"; } catch (...) { diff --git a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc index 434d7a09..700e5f2f 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_server_socket.cc @@ -15,28 +15,16 @@ #include #include -#include -#include #include -#include #include #include -// ABSL headers -#include "absl/functional/any_invocable.h" -#include "absl/strings/match.h" - // Nearby connections headers -#include "absl/synchronization/mutex.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/flags/nearby_platform_feature_flags.h" #include "internal/platform/implementation/wifi_hotspot.h" -#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.h" -#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Connectivity.h" -#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h" #include "internal/platform/implementation/windows/network_info.h" #include "internal/platform/implementation/windows/socket_address.h" -#include "internal/platform/implementation/windows/utils.h" #include "internal/platform/implementation/windows/wifi_hotspot_server_socket.h" #include "internal/platform/implementation/windows/wifi_hotspot_socket.h" #include "internal/platform/logging.h" @@ -44,11 +32,6 @@ #include "internal/platform/wifi_credential.h" namespace nearby::windows { -namespace { -using ::winrt::Windows::Networking::Connectivity::NetworkInformation; -using ::winrt::Windows::Networking::HostNameType; -using ::winrt::Windows::Networking::Sockets::SocketQualityOfService; -} // namespace std::unique_ptr WifiHotspotServerSocket::Accept() { auto client_socket = server_socket_.Accept(); @@ -62,9 +45,6 @@ std::unique_ptr WifiHotspotServerSocket::Accept() { void WifiHotspotServerSocket::PopulateHotspotCredentials( HotspotCredentials& hotspot_credentials) { - bool use_address_candidates = NearbyFlags::GetInstance().GetBoolFlag( - platform::config_package_nearby::nearby_platform_feature:: - kEnableHotspotAddressCandidates); int64_t ip_address_max_retries = NearbyFlags::GetInstance().GetInt64Flag( platform::config_package_nearby::nearby_platform_feature:: kWifiHotspotCheckIpMaxRetries); @@ -72,46 +52,13 @@ void WifiHotspotServerSocket::PopulateHotspotCredentials( NearbyFlags::GetInstance().GetInt64Flag( platform::config_package_nearby::nearby_platform_feature:: kWifiHotspotCheckIpIntervalMillis); - if (!use_address_candidates) { - // Get current IP addresses of the device. - VLOG(1) << "maximum IP check retries=" << ip_address_max_retries - << ", IP check interval=" << ip_address_retry_interval_millis - << "ms"; - std::string hotspot_ipaddr; - for (int i = 0; i < ip_address_max_retries; i++) { - hotspot_ipaddr = GetHotspotIpAddress(); - if (hotspot_ipaddr.empty()) { - LOG(WARNING) << "Failed to find Hotspot's IP addr for the try: " - << i + 1 << ". Wait " << ip_address_retry_interval_millis - << "ms snd try again"; - Sleep(ip_address_retry_interval_millis); - } else { - break; - } - } - if (hotspot_ipaddr.empty()) { - LOG(WARNING) << "Failed to start accepting connection without IP " - "addresses configured on computer."; - return; - } - - std::vector hotspot_ipaddr_bytes; - uint32_t address_int = inet_addr(hotspot_ipaddr.c_str()); - if (address_int != INADDR_NONE) { - hotspot_ipaddr_bytes.resize(4); - std::memcpy(hotspot_ipaddr_bytes.data(), - reinterpret_cast(&address_int), 4); - } - ServiceAddress service_address = { - .address = hotspot_ipaddr_bytes, - .port = static_cast(GetPort()), - }; - hotspot_credentials.SetAddressCandidates({service_address}); - return; - } std::vector service_addresses; bool has_ipv4_address = false; for (int i = 0; i < ip_address_max_retries; i++) { + // Force refresh network info since assignment of the well known + // static IP address to the hotspot interface does not trigger the IP + // interface change notification in network_monitor.cc. + NetworkInfo::GetNetworkInfo().Refresh(); for (const auto& net_interface : NetworkInfo::GetNetworkInfo().GetInterfaces()) { // service_addresses should only have addresses from a single interface. @@ -120,11 +67,13 @@ void WifiHotspotServerSocket::PopulateHotspotCredentials( LOG(INFO) << "Found Wifi Hotspot interface, index: " << net_interface.index; for (const SocketAddress& ipaddress : net_interface.ipv6_addresses) { + VLOG(1) << "Found ipv6 address: " << ipaddress.ToString(); // IPv6 link-local addresses are allowed and preferred since it skips // the DHCP wait time. service_addresses.push_back(ipaddress.ToServiceAddress(GetPort())); } for (const SocketAddress& ipaddress : net_interface.ipv4_addresses) { + VLOG(1) << "Found ipv4 address: " << ipaddress.ToString(); // Skip link-local IPv4 addresses. if (ipaddress.IsV4LinkLocal()) { continue; @@ -164,43 +113,4 @@ bool WifiHotspotServerSocket::Listen(int port) { return true; } -std::string WifiHotspotServerSocket::GetHotspotIpAddress() const { - try { - auto host_names = NetworkInformation::GetHostNames(); - std::vector ip_candidates; - for (auto host_name : host_names) { - if (host_name.IPInformation() != nullptr && - host_name.IPInformation().NetworkAdapter() != nullptr && - host_name.Type() == HostNameType::Ipv4) { - std::string ipv4_s = winrt::to_string(host_name.ToString()); - if (absl::EndsWith(ipv4_s, ".1")) { - ip_candidates.push_back(ipv4_s); - } - } - } - if (ip_candidates.empty()) { - return ""; - } - // Windows always creates Hotspot at address "192.168.137.1". - for (auto &ip_candidate : ip_candidates) { - if (ip_candidate == "192.168.137.1") { - LOG(INFO) << "Found Hotspot IP: " << ip_candidate; - return ip_candidate; - } - } - LOG(INFO) << "Found Hotspot IP: " << ip_candidates.front(); - return ip_candidates.front(); - } catch (std::exception exception) { - LOG(ERROR) << __func__ << ": Exception: " << exception.what(); - return {}; - } catch (const winrt::hresult_error &error) { - LOG(ERROR) << __func__ << ": WinRT exception: " << error.code() << ": " - << winrt::to_string(error.message()); - return ""; - } catch (...) { - LOG(ERROR) << __func__ << ": Unknown exception."; - return ""; - } -} - } // namespace nearby::windows diff --git a/internal/platform/implementation/windows/wifi_hotspot_server_socket.h b/internal/platform/implementation/windows/wifi_hotspot_server_socket.h index 61d4fa0d..8878d2f9 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_server_socket.h +++ b/internal/platform/implementation/windows/wifi_hotspot_server_socket.h @@ -79,8 +79,6 @@ class WifiHotspotServerSocket : public api::WifiHotspotServerSocket { bool Listen(int port); private: - // Retrieves hotspot IP address from local machine - std::string GetHotspotIpAddress() const; NearbyServerSocket server_socket_; }; diff --git a/internal/platform/implementation/windows/wifi_lan_medium.cc b/internal/platform/implementation/windows/wifi_lan_medium.cc index f7ab9504..01200bef 100644 --- a/internal/platform/implementation/windows/wifi_lan_medium.cc +++ b/internal/platform/implementation/windows/wifi_lan_medium.cc @@ -64,6 +64,7 @@ using ::winrt::Windows::Devices::Enumeration::DeviceInformationKind; using ::winrt::Windows::Devices::Enumeration::DeviceInformationUpdate; using ::winrt::Windows::Devices::Enumeration::DeviceWatcher; using ::winrt::Windows::Foundation::Collections::IMapView; +using ::winrt::Windows::Foundation::IInspectable; using ::winrt::Windows::Networking::Connectivity::NetworkInformation; // mDNS text attributes diff --git a/internal/platform/implementation/windows/wifi_lan_server_socket.cc b/internal/platform/implementation/windows/wifi_lan_server_socket.cc index 81a39950..ea09e691 100644 --- a/internal/platform/implementation/windows/wifi_lan_server_socket.cc +++ b/internal/platform/implementation/windows/wifi_lan_server_socket.cc @@ -24,22 +24,35 @@ #include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_lan.h" #include "internal/platform/implementation/windows/nearby_server_socket.h" +#include "internal/platform/implementation/windows/network_info.h" #include "internal/platform/implementation/windows/socket_address.h" -#include "internal/platform/implementation/windows/utils.h" #include "internal/platform/implementation/windows/wifi_lan.h" #include "internal/platform/logging.h" +#include "internal/platform/service_address.h" namespace nearby::windows { -// Returns the first IP address. +// Returns the first IPv4 address. std::string WifiLanServerSocket::GetIPAddress() const { // Just pick an IP address from the list of available addresses. - std::vector ip_addresses = GetIpv4Addresses(); - if (ip_addresses.empty()) { - LOG(ERROR) << "No IP addresses found."; - return ""; + const NetworkInfo& network_info = NetworkInfo::GetNetworkInfo(); + for (const NetworkInfo::InterfaceInfo& net_interface : + network_info.GetInterfaces()) { + if (net_interface.type != InterfaceType::kWifi && + net_interface.type != InterfaceType::kEthernet) { + continue; + } + for (const SocketAddress& v4_address : net_interface.ipv4_addresses) { + // Ignore link local addresses. + if (v4_address.IsV4LinkLocal()) { + continue; + } + ServiceAddress service_address = v4_address.ToServiceAddress(0); + return std::string(service_address.address.begin(), + service_address.address.end()); + } } - return ipaddr_dotdecimal_to_4bytes_string(ip_addresses.front()); + return ""; } // Blocks until either: diff --git a/internal/platform/medium_environment.cc b/internal/platform/medium_environment.cc index f932bfc4..b0e9b98c 100644 --- a/internal/platform/medium_environment.cc +++ b/internal/platform/medium_environment.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "absl/status/status.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/time/clock.h" #include "absl/time/time.h" #include "internal/platform/borrowable.h" #include "internal/platform/byte_array.h" @@ -46,6 +48,7 @@ #include "internal/platform/nsd_service_info.h" #include "internal/platform/prng.h" #include "internal/platform/runnable.h" +#include "internal/platform/service_address.h" #include "internal/platform/uuid.h" #include "internal/platform/wifi_credential.h" #include "internal/test/fake_clock.h" @@ -69,10 +72,14 @@ MediumEnvironment& MediumEnvironment::Instance() { void MediumEnvironment::Start(EnvironmentConfig config) { if (!enabled_.exchange(true)) { LOG(INFO) << "MediumEnvironment::Start()"; - config_ = std::move(config); - if (config_.use_simulated_clock) { + { MutexLock lock(&mutex_); - simulated_clock_ = std::make_unique(); + config_ = std::move(config); + if (config_.use_simulated_clock) { + simulated_clock_ = std::make_shared(); + } else { + simulated_clock_.reset(); + } } Reset(); } @@ -82,8 +89,8 @@ void MediumEnvironment::Stop() { if (enabled_.exchange(false)) { LOG(INFO) << "MediumEnvironment::Stop()"; Sync(false); + MutexLock lock(&mutex_); if (config_.use_simulated_clock) { - MutexLock lock(&mutex_); simulated_clock_.reset(); } config_ = {}; @@ -96,10 +103,8 @@ void MediumEnvironment::Reset() { bluetooth_adapters_.clear(); bluetooth_mediums_.clear(); ble_mediums_.clear(); -#ifndef NO_WEBRTC webrtc_signaling_message_callback_.clear(); webrtc_signaling_complete_callback_.clear(); -#endif wifi_lan_mediums_.clear(); awdl_mediums_.clear(); { @@ -132,7 +137,8 @@ void MediumEnvironment::Sync(bool enable_notifications) { LOG(INFO) << "MediumEnvironment::Sync(): done [count=" << count << "]"; } -const EnvironmentConfig& MediumEnvironment::GetEnvironmentConfig() { +EnvironmentConfig MediumEnvironment::GetEnvironmentConfig() { + MutexLock lock(&mutex_); return config_; } @@ -667,7 +673,6 @@ MediumEnvironment::GetBleMediumStatus(const api::ble::BleMedium& medium) { return result; } -#ifndef NO_WEBRTC void MediumEnvironment::RegisterWebRtcSignalingMessenger( absl::string_view self_id, OnSignalingMessageCallback message_callback, OnSignalingCompleteCallback complete_callback) { @@ -725,7 +730,7 @@ void MediumEnvironment::SendWebRtcSignalingComplete(absl::string_view peer_id, item->second(success); }); } -#endif + void MediumEnvironment::SetUseValidPeerConnection( bool use_valid_peer_connection) { use_valid_peer_connection_ = use_valid_peer_connection; @@ -1150,12 +1155,43 @@ void MediumEnvironment::SetFeatureFlags(const FeatureFlags::Flags& flags) { FeatureFlags::GetMutableInstanceForTesting().SetFlags(flags); } -std::optional MediumEnvironment::GetSimulatedClock() { +absl::Time MediumEnvironment::Now() { MutexLock lock(&mutex_); if (simulated_clock_) { - return std::optional(simulated_clock_.get()); + return simulated_clock_->Now(); + } + return absl::Now(); +} + +// If simulated_clock_ is valid, it will be advanced by the given duration. +// If simulated_clock_ is not valid, this method will do nothing. +void MediumEnvironment::FastForward(absl::Duration duration) { + std::shared_ptr sim_clock; + { + MutexLock lock(&mutex_); + if (simulated_clock_) { + sim_clock = simulated_clock_; + } + } + if (sim_clock) { + // Mutex is unlocked before calling FastForward to prevent deadlocks. + sim_clock->FastForward(duration); + } +} + +void MediumEnvironment::AddSimulatedClockObserver( + const std::string& name, std::function observer) { + MutexLock lock(&mutex_); + if (simulated_clock_) { + simulated_clock_->AddObserver(name, std::move(observer)); + } +} + +void MediumEnvironment::RemoveSimulatedClockObserver(const std::string& name) { + MutexLock lock(&mutex_); + if (simulated_clock_) { + simulated_clock_->RemoveObserver(name); } - return std::nullopt; } void MediumEnvironment::RegisterGattServer( diff --git a/internal/platform/medium_environment.h b/internal/platform/medium_environment.h index a5bf530d..8a4d7e14 100644 --- a/internal/platform/medium_environment.h +++ b/internal/platform/medium_environment.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -36,9 +37,7 @@ #include "internal/platform/runnable.h" #include "internal/platform/uuid.h" #include "internal/test/fake_clock.h" -#ifndef NO_WEBRTC #include "internal/platform/implementation/webrtc.h" -#endif #include "internal/platform/byte_array.h" #include "internal/platform/feature_flags.h" #include "internal/platform/implementation/wifi_direct.h" @@ -79,12 +78,10 @@ class MediumEnvironment { using BluetoothDiscoveryCallback = api::BluetoothClassicMedium::DiscoveryCallback; using BleScanCallback = api::ble::BleMedium::ScanningCallback; -#ifndef NO_WEBRTC using OnSignalingMessageCallback = api::WebRtcSignalingMessenger::OnSignalingMessageCallback; using OnSignalingCompleteCallback = api::WebRtcSignalingMessenger::OnSignalingCompleteCallback; -#endif using WifiLanDiscoveredServiceCallback = api::WifiLanMedium::DiscoveredServiceCallback; using AwdlDiscoveredServiceCallback = @@ -162,8 +159,7 @@ class MediumEnvironment { // Returns a Bluetooth Device object matching given mac address to nullptr. api::BluetoothDevice* FindBluetoothDevice(MacAddress mac_address); - const EnvironmentConfig& GetEnvironmentConfig(); -#ifndef NO_WEBRTC + EnvironmentConfig GetEnvironmentConfig(); // Registers |message_callback| to receive messages sent to device with id // |self_id|, and |complete_callback| to notify when signaling is complete. void RegisterWebRtcSignalingMessenger( @@ -180,7 +176,6 @@ class MediumEnvironment { // Simulates sending an "signaling complete" signal to the WebRTC medium. void SendWebRtcSignalingComplete(absl::string_view peer_id, bool success); -#endif // Used to set if WebRtcMedium should use a valid peer connection or nullptr // in tests. void SetUseValidPeerConnection(bool use_valid_peer_connection); @@ -334,7 +329,11 @@ class MediumEnvironment { void SetFeatureFlags(const FeatureFlags::Flags& flags); - std::optional GetSimulatedClock(); + absl::Time Now(); + void FastForward(absl::Duration duration); + void AddSimulatedClockObserver(const std::string& name, + std::function observer); + void RemoveSimulatedClockObserver(const std::string& name); api::ble::BleMedium* FindBleMedium(api::ble::BlePeripheral::UniqueId id); @@ -492,7 +491,6 @@ class MediumEnvironment { absl::flat_hash_map ble_mediums_; absl::flat_hash_map devices_pairing_contexts_; -#ifndef NO_WEBRTC // Maps peer id to callback for receiving signaling messages. absl::flat_hash_map webrtc_signaling_message_callback_; @@ -500,7 +498,6 @@ class MediumEnvironment { // Maps peer id to callback for signaling complete events. absl::flat_hash_map webrtc_signaling_complete_callback_; -#endif absl::flat_hash_map wifi_lan_mediums_; @@ -516,7 +513,7 @@ class MediumEnvironment { bool use_valid_peer_connection_ = true; absl::Duration peer_connection_latency_ = absl::ZeroDuration(); - std::unique_ptr simulated_clock_ ABSL_GUARDED_BY(mutex_); + std::shared_ptr simulated_clock_ ABSL_GUARDED_BY(mutex_); ObserverList observers_; bool ble_extended_advertisements_available_ = false; }; diff --git a/internal/platform/scheduled_executor_test.cc b/internal/platform/scheduled_executor_test.cc index efc9f77a..80d79c25 100644 --- a/internal/platform/scheduled_executor_test.cc +++ b/internal/platform/scheduled_executor_test.cc @@ -25,13 +25,12 @@ #include "internal/platform/cancelable.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" -#include "internal/test/fake_clock.h" namespace nearby { // kShortDelay must be significant enough to guarantee that OS under heavy load // should be able to execute the non-blocking test paths within this time. -absl::Duration kShortDelay = absl::Milliseconds(100); +absl::Duration kShortDelay = absl::Milliseconds(200); // kLongDelay must be long enough to make sure that under OS under heavy load // will let kShortDelay fire and jobs scheduled before the kLongDelay fires. @@ -212,8 +211,6 @@ TEST(ScheduledExecutorTest, ExecuteDuringShutdownFails) { TEST(ScheduledExecutorTest, SimulatedClockCanSchedule) { MediumEnvironment::Instance().Start({.use_simulated_clock = true}); - FakeClock* fake_clock = - MediumEnvironment::Instance().GetSimulatedClock().value(); ScheduledExecutor executor; std::atomic_int value = 0; CountDownLatch first_task_latch(1); @@ -235,24 +232,23 @@ TEST(ScheduledExecutorTest, SimulatedClockCanSchedule) { }, kShortDelay); EXPECT_EQ(value, 0); - fake_clock->FastForward(kShortDelay - absl::Milliseconds(1)); + MediumEnvironment::Instance().FastForward(kShortDelay - + absl::Milliseconds(1)); EXPECT_EQ(value, 0); - fake_clock->FastForward(absl::Milliseconds(1)); + MediumEnvironment::Instance().FastForward(absl::Milliseconds(1)); second_task_latch.Await(); EXPECT_EQ(value, 1); - fake_clock->FastForward(kLongDelay - kShortDelay); + MediumEnvironment::Instance().FastForward(kLongDelay - kShortDelay); first_task_latch.Await(); EXPECT_EQ(value, 5); // Very long sleep to make sure that the sleep is truly simulated. - fake_clock->FastForward(absl::Minutes(30)); + MediumEnvironment::Instance().FastForward(absl::Minutes(30)); MediumEnvironment::Instance().Stop(); } TEST(ScheduledExecutorTest, DestroyExecutorWithSimulatedClockIgnoresPendingTasks) { MediumEnvironment::Instance().Start({.use_simulated_clock = true}); - FakeClock* fake_clock = - MediumEnvironment::Instance().GetSimulatedClock().value(); { ScheduledExecutor executor; executor.Schedule( @@ -262,7 +258,7 @@ TEST(ScheduledExecutorTest, }, kShortDelay); } - fake_clock->FastForward(absl::Minutes(30)); + MediumEnvironment::Instance().FastForward(absl::Minutes(30)); MediumEnvironment::Instance().Stop(); } @@ -403,8 +399,6 @@ TEST(ScheduledExecutorTest, CanCancelOneOfTwoRepeatedTasks) { TEST(ScheduledExecutorTest, SimulatedClockCanScheduleRepeatedly) { MediumEnvironment::Instance().Start({.use_simulated_clock = true}); - FakeClock* fake_clock = - MediumEnvironment::Instance().GetSimulatedClock().value(); ScheduledExecutor executor; std::atomic_int value = 0; std::atomic_int i = 0; @@ -419,11 +413,12 @@ TEST(ScheduledExecutorTest, SimulatedClockCanScheduleRepeatedly) { EXPECT_EQ(value, 0); // Advance to just before the first execution. - fake_clock->FastForward(kShortDelay - absl::Milliseconds(1)); + MediumEnvironment::Instance().FastForward(kShortDelay - + absl::Milliseconds(1)); EXPECT_EQ(value, 0); // Advance past the first execution. - fake_clock->FastForward(absl::Milliseconds(1)); + MediumEnvironment::Instance().FastForward(absl::Milliseconds(1)); latch[0].Await(absl::Seconds(1)); EXPECT_EQ(value, 1); @@ -431,11 +426,12 @@ TEST(ScheduledExecutorTest, SimulatedClockCanScheduleRepeatedly) { absl::SleepFor(kShortDelay); // Advance to just before the second execution. - fake_clock->FastForward(kShortDelay - absl::Milliseconds(1)); + MediumEnvironment::Instance().FastForward(kShortDelay - + absl::Milliseconds(1)); EXPECT_EQ(value, 1); // Advance past the second execution. - fake_clock->FastForward(absl::Milliseconds(1)); + MediumEnvironment::Instance().FastForward(absl::Milliseconds(1)); latch[1].Await(absl::Seconds(1)); EXPECT_EQ(value, 2); @@ -443,7 +439,7 @@ TEST(ScheduledExecutorTest, SimulatedClockCanScheduleRepeatedly) { cancelable.Cancel(); // Advance a long time and make sure it doesn't run again. - fake_clock->FastForward(kLongDelay * 5); + MediumEnvironment::Instance().FastForward(kLongDelay * 5); EXPECT_EQ(value, 2); MediumEnvironment::Instance().Stop(); diff --git a/internal/platform/service_address.h b/internal/platform/service_address.h index dfc6d83b..887e0b18 100644 --- a/internal/platform/service_address.h +++ b/internal/platform/service_address.h @@ -16,6 +16,7 @@ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_SERVICE_ADDRESS_H_ #include +#include #include #include @@ -44,6 +45,18 @@ void AbslStringify(Sink& sink, const ServiceAddress& service_address) { service_address.port); } +#ifdef NEARBY_CHROMIUM +// Support logging of ServiceAddress (Chromium does not use absl log). +inline std::ostream& operator<<(std::ostream& os, + const ServiceAddress& service_address) { + return os << "[" + << WifiUtils::GetHumanReadableIpAddress( + std::string(service_address.address.begin(), + service_address.address.end())) + << "]:" << service_address.port; +} +#endif + void ServiceAddressToProto( const ServiceAddress& service_address, location::nearby::connections::ServiceAddress& proto); diff --git a/internal/platform/tachyon_express_signaling_messenger.cc b/internal/platform/tachyon_express_signaling_messenger.cc deleted file mode 100644 index fc93df70..00000000 --- a/internal/platform/tachyon_express_signaling_messenger.cc +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright 2025 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 NO_WEBRTC - -#include "internal/platform/tachyon_express_signaling_messenger.h" - -#include -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" -#include "absl/time/time.h" -#include "third_party/grpc/include/grpc/support/time.h" -#include "third_party/grpc/include/grpcpp/channel.h" -#include "third_party/grpc/include/grpcpp/client_context.h" -#include "third_party/grpc/include/grpcpp/create_channel.h" -#include "third_party/grpc/include/grpcpp/security/credentials.h" -#include "third_party/grpc/include/grpcpp/support/client_callback.h" -#include "third_party/grpc/include/grpcpp/support/status.h" -#include "internal/account/account_manager_impl.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/implementation/webrtc.h" -#include "internal/platform/logging.h" -#include "internal/proto/messaging.grpc.pb.h" -#include "internal/proto/tachyon.proto.h" -#include "internal/proto/tachyon_common.proto.h" -#include "internal/proto/tachyon_enums.proto.h" -#include "internal/rpc/utils.h" -#include "util/random/mt_random.h" -#include "util/random/util.h" - -namespace nearby { - -namespace { -using ::google::internal::communications::instantmessaging::v1::ClientInfo; -using ::google::internal::communications::instantmessaging::v1::Id; -using ::google::internal::communications::instantmessaging::v1:: - LocationStandard; -using ::google::internal::communications::instantmessaging::v1:: - ReceiveMessagesResponse; -using ::google::internal::communications::instantmessaging::v1::RequestHeader; -using ::google::internal::communications::instantmessaging::v1:: - SendMessageExpressRequest; -using ::google::internal::communications::instantmessaging::v1:: - SendMessageExpressResponse; - -constexpr absl::string_view kApp = "Nearby"; -constexpr absl::string_view kTachyonAddress = - "instantmessaging-pa.googleapis.com:443"; - -// It is unclear to me where these magic numbers are from but they are used -// across both the Android and CrOS implementations. -// See: -// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/nearby_sharing/tachyon_ice_config_fetcher.cc;l=53 -constexpr int kMajorVersion = 1; -constexpr int kMinorVersion = 24; -constexpr int kPointVersion = 0; - -void InitId(Id& id, absl::string_view id_str, - const location::nearby::connections::LocationHint& location_hint) { - id.set_id(id_str); - id.set_app(kApp); - id.set_type(google::internal::communications::instantmessaging::v1::IdType:: - NEARBY_ID); - auto* request_location_hint = id.mutable_location_hint(); - request_location_hint->set_location(location_hint.location()); - if (location_hint.format() == - location::nearby::connections::LocationStandard::E164_CALLING) { - request_location_hint->set_format(LocationStandard::E164_CALLING); - } else if (location_hint.format() == - location::nearby::connections::LocationStandard:: - ISO_3166_1_ALPHA_2) { - request_location_hint->set_format(LocationStandard::ISO_3166_1_ALPHA_2); - } else { - request_location_hint->set_format(LocationStandard::UNKNOWN); - } -} - -void InitRequestHeader( - RequestHeader& header, absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) { - ClientInfo* client_info = header.mutable_client_info(); - client_info->set_platform_type(google::internal::communications:: - instantmessaging::v1::Platform::DESKTOP); - - client_info->set_major(kMajorVersion); - client_info->set_minor(kMinorVersion); - client_info->set_point(kPointVersion); - - client_info->set_api_version( - google::internal::communications::instantmessaging::v1::ApiVersion::V4); - - // Generate a random message identifier. - MTRandom rand; - header.set_request_id(util_random::RandomString(&rand, /*length=*/13, - util::random::kWebsafe64)); - header.set_app(kApp); - - InitId(*header.mutable_requester_id(), self_id, location_hint); -} - -} // namespace - -bool TachyonExpressSignalingMessenger::ReceiveMessagesReader::Start( - google::internal::communications::instantmessaging::v1::grpc::Messaging:: - StubInterface* stub, - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint, - absl::string_view access_token, - absl::AnyInvocable on_fast_path_ready_callback, - absl::AnyInvocable on_inbox_message_callback, - absl::AnyInvocable on_complete_callback) { - { - absl::MutexLock lock(mutex_); - if (is_receiving_messages_) { - return false; - } - is_receiving_messages_ = true; - } - - on_fast_path_ready_callback_ = std::move(on_fast_path_ready_callback); - on_inbox_message_callback_ = std::move(on_inbox_message_callback); - on_complete_callback_ = std::move(on_complete_callback); - const std::shared_ptr call_creds = - grpc::AccessTokenCredentials(std::string(access_token)); - context_.set_credentials(call_creds); - gpr_timespec deadline = gpr_now(GPR_CLOCK_MONOTONIC); - timespec timespec = absl::ToTimespec(absl::Seconds(30)); - deadline.tv_sec += timespec.tv_sec; - deadline.tv_nsec += timespec.tv_nsec; - context_.set_deadline(deadline); - - InitRequestHeader(*request_.mutable_header(), self_id, location_hint); - stub->async()->ReceiveMessagesExpress(&context_, &request_, this); - StartRead(&response_); - StartCall(); - return true; -} - -void TachyonExpressSignalingMessenger::ReceiveMessagesReader::OnReadDone( - bool ok) { - { - absl::MutexLock lock(mutex_); - if (!is_receiving_messages_) { - return; - } - } - if (ok) { - switch (response_.body_case()) { - case ReceiveMessagesResponse::kFastPathReady: - on_fast_path_ready_callback_(); - break; - case ReceiveMessagesResponse::kInboxMessage: - on_inbox_message_callback_( - ByteArray(response_.inbox_message().message())); - break; - default: - break; - } - StartRead(&response_); - } -} - -void TachyonExpressSignalingMessenger::ReceiveMessagesReader::OnDone( - const grpc::Status& s) { - { - absl::MutexLock lock(mutex_); - if (!is_receiving_messages_) { - return; - } - } - if (!s.ok()) { - LOG(ERROR) << "ReceiveMessagesExpress failed: " - << rpc::GrpcStatusToAbslStatus(s); - } - on_complete_callback_(s.ok()); -} - -void TachyonExpressSignalingMessenger::ReceiveMessagesReader::TryCancel() { - { - absl::MutexLock lock(mutex_); - if (!is_receiving_messages_) { - return; - } - is_receiving_messages_ = false; - } - context_.TryCancel(); -} - -TachyonExpressSignalingMessenger::TachyonExpressSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) - : self_id_(self_id), - location_hint_(location_hint), - account_manager_(AccountManagerImpl::Factory::instance()) { - std::shared_ptr channel = - grpc::CreateChannel(std::string(kTachyonAddress), - grpc::SslCredentials(grpc::SslCredentialsOptions())); - messaging_stub_ = google::internal::communications::instantmessaging::v1:: - grpc::Messaging::NewStub(channel); -} - -struct StartState { - CountDownLatch latch{1}; - bool success = false; -}; - -bool TachyonExpressSignalingMessenger::StartReceivingMessages( - OnSignalingMessageCallback on_message_callback, - OnSignalingCompleteCallback on_complete_callback) { - auto state = std::make_shared(); - - account_manager_->GetAccessToken( - [this, state, on_message_callback = std::move(on_message_callback), - on_complete_callback = std::move(on_complete_callback)]( - absl::StatusOr token) mutable { - if (!token.ok()) { - state->success = false; - state->latch.CountDown(); - return; - } - auto reader = std::make_shared(); - - reader_ = reader; - - std::weak_ptr weak_state = state; - - bool started = reader->Start( - messaging_stub_.get(), self_id_, location_hint_, token.value(), - /*on_fast_path_ready_callback=*/ - [state] { - LOG(INFO) << "Received fast path ready message from tachyon."; - state->success = true; - state->latch.CountDown(); - }, - std::move(on_message_callback), - [reader, weak_state, - cb = std::move(on_complete_callback)](bool s) mutable { - LOG(INFO) << "Finished receiving messages from tachyon."; - cb(s); - if (auto state = weak_state.lock()) { - state->success = false; - state->latch.CountDown(); - } - }); - - if (!started) { - state->success = false; - state->latch.CountDown(); - } - }); - state->latch.Await(); - if (state->success) { - LOG(INFO) << "Receiving messages from tachyon."; - } else { - LOG(ERROR) << "Failed to start receiving messages from tachyon."; - reader_.reset(); - } - return state->success; -} - -void TachyonExpressSignalingMessenger::StopReceivingMessages() { - if (reader_) { - reader_->TryCancel(); - reader_.reset(); - } -} - -bool TachyonExpressSignalingMessenger::SendMessage(absl::string_view peer_id, - const ByteArray& message) { - auto rpc_state = - std::make_shared>(); - - InitRequestHeader(*rpc_state->request.mutable_header(), self_id_, - location_hint_); - InitId(*rpc_state->request.mutable_dest_id(), peer_id, location_hint_); - - auto* request_message = rpc_state->request.mutable_message(); - request_message->set_message(message.string_data()); - request_message->set_message_type( - google::internal::communications::instantmessaging::v1::InboxMessage:: - BASIC); - request_message->set_message_class( - google::internal::communications::instantmessaging::v1::InboxMessage:: - EPHEMERAL); - MTRandom rand; - request_message->set_message_id(util_random::RandomString( - &rand, /*length=*/13, util::random::kWebsafe64)); - - CountDownLatch latch(1); - bool success = false; - account_manager_->GetAccessToken( - [this, &latch, &success, rpc_state](absl::StatusOr token) { - if (!token.ok()) { - success = false; - latch.CountDown(); - return; - } - - const std::shared_ptr call_creds = - grpc::AccessTokenCredentials(token.value()); - rpc_state->context.set_credentials(call_creds); - gpr_timespec deadline = gpr_now(GPR_CLOCK_MONOTONIC); - timespec timespec = absl::ToTimespec(absl::Seconds(30)); - deadline.tv_sec += timespec.tv_sec; - deadline.tv_nsec += timespec.tv_nsec; - rpc_state->context.set_deadline(deadline); - - // `rpc_state` is captured to ensure its lifetime is valid until the - // callback is executed. - messaging_stub_->async()->SendMessageExpress( - &rpc_state->context, &rpc_state->request, &rpc_state->response, - [&success, &latch, rpc_state](grpc::Status status) { - if (!status.ok()) { - LOG(ERROR) << "SendMessageExpress failed: " - << rpc::GrpcStatusToAbslStatus(status); - } - success = status.ok(); - latch.CountDown(); - }); - }); - latch.Await(); - return success; -} - -} // namespace nearby - -#endif // #ifndef NO_WEBRTC diff --git a/internal/platform/tachyon_express_signaling_messenger.h b/internal/platform/tachyon_express_signaling_messenger.h deleted file mode 100644 index 872f95b9..00000000 --- a/internal/platform/tachyon_express_signaling_messenger.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2025 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_TACHYON_MESSAGING_CLIENT_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_TACHYON_MESSAGING_CLIENT_H_ - -#ifndef NO_WEBRTC - -#include - -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/functional/any_invocable.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" -#include "third_party/grpc/include/grpcpp/client_context.h" -#include "third_party/grpc/include/grpcpp/support/client_callback.h" -#include "third_party/grpc/include/grpcpp/support/status.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/implementation/webrtc.h" -#include "internal/proto/messaging.grpc.pb.h" - -namespace nearby { - -// Interface for the messaging Tachyon service. See -// third_party/nearby/internal/proto/messaging.proto -class TachyonExpressSignalingMessenger : public api::WebRtcSignalingMessenger { - public: - explicit TachyonExpressSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint); - - class ReceiveMessagesReader - : public grpc::ClientReadReactor< - google::internal::communications::instantmessaging::v1:: - ReceiveMessagesResponse> { - public: - ReceiveMessagesReader() = default; - - void OnReadDone(bool ok) override; - void OnDone(const grpc::Status& s) override; - - bool Start( - google::internal::communications::instantmessaging::v1::grpc:: - Messaging::StubInterface* stub, - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint, - absl::string_view access_token, - absl::AnyInvocable on_fast_path_ready_callback, - absl::AnyInvocable on_inbox_message_callback, - absl::AnyInvocable on_complete_callback); - void TryCancel(); - - private: - grpc::ClientContext context_; - google::internal::communications::instantmessaging::v1:: - ReceiveMessagesExpressRequest request_; - google::internal::communications::instantmessaging::v1:: - ReceiveMessagesResponse response_; - absl::AnyInvocable on_fast_path_ready_callback_; - absl::AnyInvocable on_inbox_message_callback_; - absl::AnyInvocable on_complete_callback_; - - absl::Mutex mutex_; - bool is_receiving_messages_ ABSL_GUARDED_BY(mutex_) = false; - }; - - bool SendMessage(absl::string_view peer_id, - const ByteArray& message) override; - - bool StartReceivingMessages( - OnSignalingMessageCallback on_message_callback, - OnSignalingCompleteCallback on_complete_callback) override; - - void StopReceivingMessages() override; - - private: - std::string self_id_; - location::nearby::connections::LocationHint location_hint_; - std::unique_ptr - messaging_stub_; - AccountManager* const account_manager_; - std::shared_ptr reader_ = nullptr; -}; - -} // namespace nearby - -#endif // #ifndef NO_WEBRTC - -#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_TACHYON_MESSAGING_CLIENT_H_ diff --git a/internal/platform/webrtc.h b/internal/platform/webrtc.h deleted file mode 100644 index 1eef3d26..00000000 --- a/internal/platform/webrtc.h +++ /dev/null @@ -1,119 +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_PUBLIC_WEBRTC_H_ -#define PLATFORM_PUBLIC_WEBRTC_H_ - -#ifndef NO_WEBRTC - -#include -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/implementation/platform.h" -#include "internal/platform/implementation/webrtc.h" -#include "webrtc/api/peer_connection_interface.h" - -namespace nearby { - -class WebRtcSignalingMessenger { - public: - using OnSignalingMessageCallback = - api::WebRtcSignalingMessenger::OnSignalingMessageCallback; - using OnSignalingCompleteCallback = - api::WebRtcSignalingMessenger::OnSignalingCompleteCallback; - - explicit WebRtcSignalingMessenger( - std::unique_ptr messenger) - : impl_(std::move(messenger)) {} - virtual ~WebRtcSignalingMessenger() = default; - WebRtcSignalingMessenger(WebRtcSignalingMessenger&&) = default; - WebRtcSignalingMessenger operator=(WebRtcSignalingMessenger&&) = delete; - - virtual bool SendMessage(absl::string_view peer_id, - const ByteArray& message) { - return impl_->SendMessage(peer_id, message); - } - - virtual bool StartReceivingMessages( - OnSignalingMessageCallback on_message_callback, - OnSignalingCompleteCallback on_complete_callback) { - return impl_->StartReceivingMessages(std::move(on_message_callback), - std::move(on_complete_callback)); - } - - virtual void StopReceivingMessages() { impl_->StopReceivingMessages(); } - - virtual bool IsValid() const { return impl_ != nullptr; } - - private: - std::unique_ptr impl_; -}; - -class WebRtcMedium { - public: - using PeerConnectionCallback = api::WebRtcMedium::PeerConnectionCallback; - - WebRtcMedium() : impl_(api::ImplementationPlatform::CreateWebRtcMedium()) {} - virtual ~WebRtcMedium() = default; - WebRtcMedium(WebRtcMedium&&) = delete; - WebRtcMedium& operator=(WebRtcMedium&&) = delete; - - // Gets the default two-letter country code associated with current locale. - // For example, en_US locale resolves to "US". - std::string GetDefaultCountryCode() { return impl_->GetDefaultCountryCode(); } - - void SetNonCellular(bool non_cellular) { - non_cellular_ = non_cellular; - } - - // Creates and returns a new webrtc::PeerConnectionInterface object via - // |callback|. - void CreatePeerConnection(webrtc::PeerConnectionObserver* observer, - PeerConnectionCallback callback) { - if (FeatureFlags::GetInstance() - .GetFlags() - .support_web_rtc_non_cellular_medium && non_cellular_) { - std::optional options; - options->network_ignore_mask |= webrtc::ADAPTER_TYPE_CELLULAR; - impl_->CreatePeerConnection(options, observer, std::move(callback)); - } else { - impl_->CreatePeerConnection(observer, std::move(callback)); - } - } - - // Returns a signaling messenger for sending WebRTC signaling messages. - virtual std::unique_ptr GetSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) { - return std::make_unique( - impl_->GetSignalingMessenger(self_id, location_hint)); - } - - virtual bool IsValid() const { return impl_ != nullptr; } - - private: - std::unique_ptr impl_; - bool non_cellular_ = false; -}; - -} // namespace nearby - -#endif - -#endif // PLATFORM_PUBLIC_WEBRTC_H_ diff --git a/internal/platform/wifi_direct.h b/internal/platform/wifi_direct.h index f78339e4..a8296da0 100644 --- a/internal/platform/wifi_direct.h +++ b/internal/platform/wifi_direct.h @@ -17,13 +17,12 @@ #include #include -#include +#include #include #include #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "connections/implementation/flags/nearby_connections_feature_flags.h" #include "internal/flags/nearby_flags.h" #include "internal/platform/cancellation_flag.h" @@ -178,7 +177,7 @@ class WifiDirectMedium { } // Returns the port range as a pair of min and max port. - absl::optional> GetDynamicPortRange() { + std::optional> GetDynamicPortRange() { return impl_->GetDynamicPortRange(); } diff --git a/internal/platform/wifi_lan.h b/internal/platform/wifi_lan.h index e46a39f6..2f9fc2ed 100644 --- a/internal/platform/wifi_lan.h +++ b/internal/platform/wifi_lan.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -24,7 +25,6 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/functional/any_invocable.h" -#include "absl/types/optional.h" #include "internal/platform/blocking_queue_stream.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" @@ -254,7 +254,7 @@ class WifiLanMedium { } // Returns the port range as a pair of min and max port. - absl::optional> GetDynamicPortRange() { + std::optional> GetDynamicPortRange() { return impl_->GetDynamicPortRange(); } diff --git a/internal/proto/analytics/BUILD b/internal/proto/analytics/BUILD deleted file mode 100644 index 352db000..00000000 --- a/internal/proto/analytics/BUILD +++ /dev/null @@ -1,60 +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. - -load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") -load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") - -licenses(["notice"]) - -package(default_visibility = ["//visibility:public"]) - -proto_library( - name = "connections_log_proto", - srcs = [ - "connections_log.proto", - ], - deps = [ - "//proto:connections_enums_proto", - "//proto/errorcode:error_code_enums_proto", - ], -) - -cc_proto_library( - name = "connections_log_cc_proto", - visibility = [ - "//connections:__subpackages__", - "//internal/analytics:__pkg__", - "//location/nearby/analytics/cpp:__subpackages__", - ], - deps = [":connections_log_proto"], -) - -cc_test( - name = "proto_analytics_test", - size = "small", - srcs = [ - "connections_log_test.cc", - ], - shard_count = 16, - deps = [ - ":connections_log_cc_proto", - "//internal/platform:logging", - "//internal/platform/implementation/g3", # build_cleaner: keep - "//proto:connections_enums_cc_proto", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_googletest//:gtest_main", - "@com_google_protobuf//:protobuf", - ], -) diff --git a/internal/proto/analytics/connections_log.proto b/internal/proto/analytics/connections_log.proto deleted file mode 100644 index 6dea3e48..00000000 --- a/internal/proto/analytics/connections_log.proto +++ /dev/null @@ -1,733 +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. - -syntax = "proto2"; - -package location.nearby.analytics.proto; - -// import "storage/datapol/annotations/proto/semantic_annotations.proto"; -import "proto/connections_enums.proto"; -import "proto/errorcode/error_code_enums.proto"; - -option optimize_for = LITE_RUNTIME; -option java_package = "com.google.location.nearby.analytics.proto"; -option java_outer_classname = "ConnectionsLogProto"; -option objc_class_prefix = "GNCP"; - -// Top-level log proto for Nearby Connections. -// LINT.IfChange(ConnectionsLog) -// Next Tag: 7 -message ConnectionsLog { - // The type of this log. - optional location.nearby.proto.connections.EventType event_type = 1; - - // Non-null for EventType.CLIENT_SESSION. - // Encapsulates all client activity between connecting to and disconnecting - // from the Nearby Connections API via Client. - optional ClientSession client_session = 2; - - // The version of Nearby Connections. E.g. "v1.0.4". - optional string version = 3 /* type = ST_SOFTWARE_ID */; - - // For EventType.ERROR_CODE - optional ErrorCode error_code = 4; - - // Indicates the source of the log. - optional location.nearby.proto.connections.LogSource log_source = 5; - - // This is a temporary logging field for FilesGo migration phase based on - // device geolocation. Example values are "P1", "P2", "PA" etc. - // In files migration, we have different phases to rollout Files-> Nearby - // migration on different list of countries. For example, at phase A (PA), - // the migration happens in Asian countries; P1 for Europe countries; P2 - // for North and South Americas. - // Reference: http://shortn/_9smZZ8CTD6, http://shortn/_Y08gVwZRKc - optional string files_migration_phase = 6; - - // Encapsulates one session of a client connected to Nearby Connections API. - message ClientSession { - // Elapsed time in milliseconds between Client connect and - // disconnect. - optional int64 duration_millis = 1; - - // Zero or more StrategySessions. - repeated StrategySession strategy_session = 2; - - // The client session flow id. - optional int64 client_flow_id = 3 /* type = ST_SESSION_ID */; - - // All the connection tokens used in this client session. - optional string connection_token = 4 - /* type = ST_SESSION_ID */; - - reserved 5; // device type isdeprecated and moved to StrategySession - } - - message OperationResult { - // The category of the operation result - optional location.nearby.proto.connections.OperationResultCategory - result_category = 1; - - // The result code of the operation result - optional location.nearby.proto.connections.OperationResultCode result_code = - 2; - } - - message OperationResultWithMedium { - optional location.nearby.proto.connections.Medium medium = 1; - - // Indicate which mediums belong to the same update API Call. - optional int32 update_index = 2; - - // The category of the operation result - optional location.nearby.proto.connections.OperationResultCategory - result_category = 3; - - // The result code of the operation result - optional location.nearby.proto.connections.OperationResultCode result_code = - 4; - - // The connection mode. - optional location.nearby.proto.connections.ConnectionMode connection_mode = - 5; - } - - // One round of a particular Strategy done by a client. - message StrategySession { - // Elapsed time in milliseconds between a call to startAdvertising/Discovery - // and the end of this particular Strategy. A StrategySession may end due to - // - the client disconnecting from Client; - // - a call to stopAllEndpoints, which disconnects all endpoints and - // stops any advertising/discovery; - // - a new call to startAdvertising/Discovery. - optional int64 duration_millis = 1; - - // The Strategy used for this session. - optional location.nearby.proto.connections.ConnectionsStrategy strategy = 2; - - // The role(s) played by this device during this StrategySession. - repeated location.nearby.proto.connections.SessionRole role = 3; - - // One or more of the following *Phase is present, depending on the role(s). - - // Encapsulates discovery information. - repeated DiscoveryPhase discovery_phase = 4; - // Encapsulates advertising information. - repeated AdvertisingPhase advertising_phase = 5; - - // Attempts at establishing a connection to another device. - repeated ConnectionAttempt connection_attempt = 6; - - // Successful and accepted connections to another device. - repeated EstablishedConnection established_connection = 7; - - // Attempts to upgrade a connection from one medium to another. - repeated BandwidthUpgradeAttempt upgrade_attempt = 9; - - // The build version of the user's device (Same value as the Build number in - // Settings -> about phone). - optional string build_version = 10 - /* type = ST_SOFTWARE_ID */; - } - - // Encapsulates activity during a period of discovery. - message DiscoveryPhase { - // Elapsed time in milliseconds between startDiscovery and stopDiscovery. - optional int64 duration_millis = 1; - - // The Medium(s) used for discovery. - repeated location.nearby.proto.connections.Medium medium = 2; - - // Discovered endpoints during this round of discovery. - repeated DiscoveredEndpoint discovered_endpoint = 3; - - // Attempted ConnectionRequests (requested by the client). They may or - // may not reach the other endpoint. - repeated ConnectionRequest sent_connection_request = 4; - - // UWB ranging related data during discovery (May range with multiple - // endpoints) - repeated UwbRangingProcess uwb_ranging = 5; - - // The SendingEvent flow id. - optional int64 client_flow_id = 6 /* type = ST_SESSION_ID */; - - // Encapsulates additional discovery information. - optional DiscoveryMetadata discovery_metadata = 7; - - // Collect the discovery results of the mediums - repeated OperationResultWithMedium adv_dis_result = 8; - - // The readon of stopping discoverying - optional location.nearby.proto.connections.StopDiscoveringReason - stop_reason = 9; - - // The type of the device. - optional location.nearby.proto.connections.DeviceType device_type = 10; - - // The supported service. - optional location.nearby.proto.connections.SupportedService - supported_service = 11; - } - - // An endpoint discovered on a particular medium during discovery. - message DiscoveredEndpoint { - // The medium on which this endpoint was discovered. - optional location.nearby.proto.connections.Medium medium = 1; - - // Elapsed time between the call to startDiscovery() and the time at which - // this endpoint was discovered. - optional int64 latency_millis = 2; - } - - // Encapsulates activity during UWB ranging. - message UwbRangingProcess { - // Elapsed time in milliseconds between startRanging and stopRanging. - optional int64 duration_millis = 1; - - // UWB raw ranging data received during discovery. This is optional. Only - // certain devices (Debug/Testing etc.) will log the raw data. - repeated RawUwbRangingEvent uwb_ranging_data = 2; - - // Number of ranging data received - optional int32 number_of_ranging_data = 3; - - // The minimum distance during a UWB ranging session - optional int32 distance_min = 4; - - // The maximum distance during a UWB ranging session - optional int32 distance_max = 5; - - // The average distance during a UWB ranging session - optional int32 distance_ave = 6; - - // The distance variance during a UWB ranging session - optional int32 distance_variance = 7; - - // The minimum AoA during a UWB ranging session - optional int32 azimuth_min = 8; - - // The maximum AoA during a UWB ranging session - optional int32 azimuth_max = 9; - - // The average AoA during a UWB ranging session - optional int32 azimuth_ave = 10; - - // The AoA variance during a UWB ranging session - optional int32 azimuth_variance = 11; - } - - // Ranging data received during discovery phase. - message RawUwbRangingEvent { - // Distance in cm - optional int32 distance = 1; - - // Azimuth angle in degree - optional int32 azimuth_angle = 2; - - // Polar angle in degree (0 if the device doesn't support it) - optional int32 polar_angle = 3; - } - - // Encapsulates activity during a period of advertising. - message AdvertisingPhase { - // Elapsed time in milliseconds between startAdvertising and - // stopAdvertising. - optional int64 duration_millis = 1; - - // The Medium(s) used for advertising. - repeated location.nearby.proto.connections.Medium medium = 2; - - // Received ConnectionRequests from remote endpoints. - repeated ConnectionRequest received_connection_request = 3; - - // The ReceivingEvent flow id. - optional int64 client_flow_id = 4 /* type = ST_SESSION_ID */; - - // Encapsulates additional advertising information. - optional AdvertisingMetadata advertising_metadata = 5; - - // Collect the discovery results of the mediums - repeated OperationResultWithMedium adv_dis_result = 6; - - // The readon of stopping advertising - optional location.nearby.proto.connections.StopAdvertisingReason - stop_reason = 7; - - // The type of the device. - optional location.nearby.proto.connections.DeviceType device_type = 8; - - // The supported service. - optional location.nearby.proto.connections.SupportedService - supported_service = 9; - } - - // A request to connect, corresponding to the API's concept of - // request/accept/rejectConnection(). - message ConnectionRequest { - // Elapsed time in milliseconds between the connection request being - // initiated and the responses being received. - optional int64 duration_millis = 1; - - // Elapsed time in milliseconds between the start of the containing - // Advertising/DiscoveryPhase and the start of this ConnectionRequest, i.e. - // the time at which the request is sent (on the discoverer, at the request - // of the client) or received (on the advertiser, over the wire from the - // remote endpoint). - optional int64 request_delay_millis = 2; - - // The local endpoint's response to this connection request. - optional location.nearby.proto.connections.ConnectionRequestResponse - local_response = 3; - - // The remote endpoint's response to this connection request. - optional location.nearby.proto.connections.ConnectionRequestResponse - remote_response = 4; - - // The SendingEvent flow id. - optional int64 client_flow_id = 5 /* type = ST_SESSION_ID */; - } - - // An attempt to connect to an endpoint over a particular medium. - message ConnectionAttempt { - // Elapsed time in milliseconds between starting the connection attempt - // and succeeding/failing. - optional int64 duration_millis = 1; - - // The type of connection attempt. - optional location.nearby.proto.connections.ConnectionAttemptType type = 2; - - // The direction (incoming vs outgoing) of this attempt. - optional location.nearby.proto.connections.ConnectionAttemptDirection - direction = 3; - - // The Medium of this connection attempt. - optional location.nearby.proto.connections.Medium medium = 4; - - // The result of the connection attempt. - optional location.nearby.proto.connections.ConnectionAttemptResult - attempt_result = 5; - - // The ReceivingEvent flow id. - optional int64 client_flow_id = 6 /* type = ST_SESSION_ID */; - - // The token used to identify this connection pair. - optional string connection_token = 7 - /* type = ST_SESSION_ID */; - - // Encapsulates additional connection information. - optional ConnectionAttemptMetadata connection_attempt_metadata = 8; - - // The result code of this connection attempt - optional OperationResult operation_result = 9; - - // The connection mode. - optional location.nearby.proto.connections.ConnectionMode connection_mode = - 10; - - // The type of the device. - optional location.nearby.proto.connections.DeviceType device_type = 11; - - // The supported service. - optional location.nearby.proto.connections.SupportedService - supported_service = 12; - - // The latency of the wifi connection in milliseconds, starting from when - // the wifi credentials are received from the remote device, to the moment - // wifi connection is established with internet access. - optional int64 wifi_connection_latency_millis = 13; - - // The latency of the device attestation in milliseconds, starting from when - // the device attestation is initiated, to the moment the device attestation - // is finished. - optional int64 device_attestation_latency_millis = 14; - - // The error code returned by Play Integrity API during device attestation. - optional int64 play_integrity_error_code = 15; - } - - message DeviceInfo { - enum Platform { - UNKNOWN = 0; - ANDROID = 1; - IOS = 2; - CROS = 3; - WINDOWS = 4; - } - optional string device_model = 1; - optional Platform device_platform = 2; - optional string country_code = 3; - optional string manufacturer = 4; - } - - message DisconnectionReasonDetail { - enum DisconnectionReason { - UNKNOWN_DISCONNECTION_REASON = 0; - DCT_ERROR_MDNS_DISCOVERY_TIMEOUT = 1; - DCT_ERROR_MDNS_REGISTER_SERVICE = 2; - DCT_ERROR_SUBSEQUENT_TLS_SPAKE = 3; - DCT_ERROR_REQUEST_FAILED = 4; - DCT_ERROR_RESPONSE_FAILED = 5; - DCT_ERROR_CONTROL_MESSAGE_EXCHANGE = 6; - DCT_ERROR_CAPABILITY_MISMATCH = 7; - DCT_ERROR_HIGH_SPEED_MEDIUM_UNAVAILABLE = 8; - DCT_ERROR_WIFI_DISABLED = 9; - DCT_ERROR_WIFI_DISCONNECTED = 10; - DCT_ERROR_WIFI_CREDENTIAL_TRANSFER = 11; - DCT_ERROR_WIFI_INTERNET_CONNECTION = 12; - DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED = 13; - DCT_ERROR_USER_CANCELLED = 14; - DCT_ERROR_SERVICE_CANCELLED = 15; - DCT_ERROR_UNVERIFIED_INTEGRITY = 16; - SESSION_SUCCESS = 17; - } - optional bool is_local_disconnection = 1; - optional DisconnectionReason disconnection_reason = 2; - } - - // A successfully-established connection over a particular medium. - message EstablishedConnection { - enum SafeDisconnectionResult { - UNKNOWN_SAFE_DISCONNECTION_RESULT = 0; - SAFE_DISCONNECTION = 1; - UNSAFE_DISCONNECTION = 2; - } - - // Elapsed time in milliseconds that the connection is active. - optional int64 duration_millis = 1; - - // The Medium of this connection. - optional location.nearby.proto.connections.Medium medium = 2; - - // Payloads sent over this connection. - repeated Payload sent_payload = 3; - - // Payloads received over this connection. - repeated Payload received_payload = 4; - - // The reason this connection was disconnected. - optional location.nearby.proto.connections.DisconnectionReason - disconnection_reason = 5; - - // The SendingEvent flow id. - optional int64 client_flow_id = 6 /* type = ST_SESSION_ID */; - - // The token use to identify this established connection. - optional string connection_token = 7 - /* type = ST_SESSION_ID */; - - // The type of established connection. - optional location.nearby.proto.connections.ConnectionAttemptType type = 8; - - // If this is a safe disconnection. - optional SafeDisconnectionResult safe_disconnection_result = 9; - - // The result code of this established connection - optional OperationResult operation_result = 10; - - // The remote device info - optional DeviceInfo remote_device_info = 11; - - // The disconnection reason details - optional DisconnectionReasonDetail disconnection_reason_detail = 12; - - // The type of the device. - optional location.nearby.proto.connections.DeviceType device_type = 13; - - // The supported service. - optional location.nearby.proto.connections.SupportedService - supported_service = 14; - - // The speed test report. - optional SpeedTestReport speed_test_report = 15; - } - - message SpeedTestReport { - // The throughput in kbytes per second. - optional int32 throughput_kbytes_per_sec = 1; - - // Whether the throughput is incoming or outgoing. - optional bool is_incoming = 2; - } - - // Contains the transfer statistics for a DCT payload. - message DctPayloadTransferStats { - // The type of the DCT payload. - // Note: For legacy payloads, the type is logged in the Payload message - // instead. - optional location.nearby.proto.connections.DctPayloadType type = 1; - - // Indicates whether the payload was sent using the multipart protocol. - // True if multipart was used, false otherwise. - optional bool is_multipart = 2; - - // The number of parts that were successfully transferred. - // This field is only meaningful when is_multipart is true. - // The counting method differs for outgoing and incoming multipart payloads: - // - OUTGOING: All parts associated with the same request are treated as one - // payload. This field increments by 1 if the payload transfers - // successfully. - // - INCOMING: Each part of the incoming multipart payload is logged - // individually. This field increments for each successfully received - // part. - optional int32 num_parts_success = 3; - - // The number of parts that failed to transfer. - // This field is only meaningful when is_multipart is true. - // The counting method differs for outgoing and incoming multipart payloads: - // - OUTGOING: All parts associated with the same request are treated as one - // payload. This field increments by 1 if the payload fails to transfer. - // - INCOMING: Each part of the incoming multipart payload is logged - // individually. This field increments for each part that fails to be - // received. - optional int32 num_parts_failure = 4; - - // True if this payload transfer is an attempt to resume an interrupted - // payload after a reconnection. False if it's a new payload transfer. - optional bool is_resumption = 5; - - // The data speed report in kbyte per second using global bytes counter - optional int32 data_speed_report_kbyte_per_sec = 6; - } - - // A Payload transferred (or attempted to be transferred) between devices. - message Payload { - // Elapsed time in milliseconds that num_bytes_transferred took to transfer. - optional int64 duration_millis = 1; - - // The type of this payload. - optional location.nearby.proto.connections.PayloadType type = 2; - - // Total size of the payload in bytes. - optional int64 total_size_bytes = 3; - - // Total number of bytes transferred successfully. - optional int64 num_bytes_transferred = 4; - - // The number of chunks used to transfer num_bytes_transferred. - optional int32 num_chunks = 5; - - // The end status of the payload transfer. - optional location.nearby.proto.connections.PayloadStatus status = 6; - - // The number of successful auto resume. - optional int32 num_successful_auto_resume = 7; - - // The result code of this sent payload - optional OperationResult operation_result = 8; - - // The number of failed auto resume attempts. - optional int32 num_failed_auto_resume = 9; - - // Statistics for DCT payloads, e.g., type, multipart details. Populated - // only for DCT payloads. - optional DctPayloadTransferStats dct_payload_transfer_stats = 10; - } - - // An attempt to upgrade an existing connection from one medium to another. - message BandwidthUpgradeAttempt { - // The direction (incoming vs outgoing) of the upgrade attempt. - optional location.nearby.proto.connections.ConnectionAttemptDirection - direction = 1; - - // Elapsed time in milliseconds of the upgrade attempt. - optional int64 duration_millis = 2; - - // The original medium (e.g. bluetooth). - optional location.nearby.proto.connections.Medium from_medium = 3; - - // The new medium that we're hoping to upgrade to (e.g. wifi). - optional location.nearby.proto.connections.Medium to_medium = 4; - - // The result of the upgrade attempt. - optional location.nearby.proto.connections.BandwidthUpgradeResult - upgrade_result = 5; - - // If upgrade_result is not success, the stage at which the error occurred. - optional location.nearby.proto.connections.BandwidthUpgradeErrorStage - error_stage = 6; - - // The SendingEvent flow id. - optional int64 client_flow_id = 7 /* type = ST_SESSION_ID */; - - // The token used to identify this upgrade pair. - optional string connection_token = 8 - /* type = ST_SESSION_ID */; - - // The result code of this upgrade attempt - optional OperationResult operation_result = 9; - - optional location.nearby.proto.connections.DeviceType device_type = 10; - - // The supported service. - optional location.nearby.proto.connections.SupportedService - supported_service = 11; - - // The number of network interfaces on the device for the upgrade medium - // that can be used for bandwidth upgrade. - optional int32 num_interfaces = 12; - // The number of network interfaces on the device for the upgrade medium - // that can be used for bandwidth upgrade and are IPv6 only. - optional int32 num_ipv6_only_interfaces = 13; - } - - // Next Id: 22 - message ErrorCode { - // The direction (incoming vs outgoing) of this error. - optional location.nearby.proto.connections.ConnectionAttemptDirection - direction = 1; - optional string service_id = 2; - // The error medium (e.g. bluetooth). - optional location.nearby.proto.connections.Medium medium = 3; - // The event which the error occurs on. - optional location.nearby.errorcode.proto.Event event = 4; - // The error description. - optional location.nearby.errorcode.proto.Description description = 5; - // The flow id which the error occurs on. - optional int64 flow_id = 6 /* type = ST_SESSION_ID */; - - // Error code value - oneof ErrorCodeDetail { - location.nearby.errorcode.proto.CommonError common_error = 7; - location.nearby.errorcode.proto.StartAdvertisingError - start_advertising_error = 8; - location.nearby.errorcode.proto.StartDiscoveringError - start_discovering_error = 9; - location.nearby.errorcode.proto.StopAdvertisingError - stop_advertising_error = 10; - location.nearby.errorcode.proto.StopDiscoveringError - stop_discovering_error = 11; - location.nearby.errorcode.proto.StartListeningIncomingConnectionError - start_listening_incoming_connection_error = 12; - location.nearby.errorcode.proto.StopListeningIncomingConnectionError - stop_listening_incoming_connection_error = 13; - location.nearby.errorcode.proto.ConnectError connect_error = 14; - location.nearby.errorcode.proto.DisconnectError disconnect_error = 15; - location.nearby.errorcode.proto.SendPayloadError send_payload_error = 17; - location.nearby.errorcode.proto.ReceivePayloadError - receive_payload_error = 18; - location.nearby.errorcode.proto.UpgradeError upgrade_error = 19; - location.nearby.errorcode.proto.AcceptConnectionError - accept_connection_error = 20; - location.nearby.errorcode.proto.RejectConnectionError - reject_connection_error = 21; - } - - // The token use to identify this established connection. - optional string connection_token = 16 - /* type = ST_SESSION_ID */; - } - - // Some additional information to keep with the advertising phase. - message AdvertisingMetadata { - // The bluetooth low energy extended advertisement support status. - optional bool supports_extended_ble_advertisements = 1; - - // The frequency of the connected WiFi AP. - optional int32 connected_ap_frequency = 2; - - // The NFC (Near Field Communication) support status - optional bool supports_nfc_technology = 3; - - // The Bluetooth multiple advertisement support status. - optional bool multiple_advertisement_supported = 4; - - // The power level of this advertising - optional location.nearby.proto.connections.PowerLevel power_level = 5; - - // The dual band support status - optional bool supports_dual_band = 6; - - // The wifi aware support status - optional bool supports_wifi_aware = 7; - - // The endpoint info size - optional int32 endpoint_info_size = 8; - } - - // Some additional information to keep with the discovery phase. - message DiscoveryMetadata { - // The bluetooth low energy extended advertisement support status. - optional bool supports_extended_ble_advertisements = 1; - - // The frequency of the connected WiFi AP. - optional int32 connected_ap_frequency = 2; - - // The NFC (Near Field Communication) support status - optional bool supports_nfc_technology = 3; - - // The power level of this discovering - optional location.nearby.proto.connections.PowerLevel power_level = 4; - } - - // Some additional information to keep with the connection attempt. - message ConnectionAttemptMetadata { - // The technology used by the mediums. - optional location.nearby.proto.connections.ConnectionTechnology technology = - 1; - - // The wifi band used by the wifi mediums. - optional location.nearby.proto.connections.ConnectionBand band = 2; - - // The frequency used by the wifi mediums. - optional int32 frequency = 3; - - // The MCC (Mobile country code) MNC (Mobile network code) of the network - // operator. - optional string network_operator = 4 - /* type = ST_LOCATION */; - - // The upper-case ISO 3166-1 alpha-2 country code of: - // 1. the current connected WiFi network - // 2. or the current registered operator's MCC (Mobile Country Code) - // 3. or empty string. - optional string country_code = 5 /* type = ST_LOCATION */; - - // The TDLS status used by the wifi lan medium, - // TDLS, shortened from Tunneled Direct Link Setup, is "a seamless way to - // stream media and other data faster between devices already on the same - // Wi-Fi network." Devices using it communicate directly with one another, - // without involving the wireless network's router. - optional bool is_tdls_used = 6; - - // The try times for this hosted group or connection operation. - optional int32 try_counts = 7; - - // The enabled status of the wifi hotspot(tethering) when doing this - // connection attempt. - optional bool wifi_hotspot_status = 8; - - // The MAX supported TX link speed (Mbps). - optional int32 max_tx_speed = 9; - - // The MAX supported RX link speed (Mbps). - optional int32 max_rx_speed = 10; - - // The connected wifi channel width. - optional int32 wifi_channel_width = 11; - - // The send buffer size of the created socket - optional int32 send_buffer_size = 12; - - // The receive buffer size of the created socket - optional int32 receive_buffer_size = 13; - - // The frequency of the connected WiFi AP. - optional int32 connected_ap_frequency = 14; - - // The connectivity MCC mode - optional bool is_mcc_mode = 15; - } -} -// LINT.ThenChange() diff --git a/internal/proto/analytics/connections_log_test.cc b/internal/proto/analytics/connections_log_test.cc deleted file mode 100644 index 53048875..00000000 --- a/internal/proto/analytics/connections_log_test.cc +++ /dev/null @@ -1,124 +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 "logs/proto/location/nearby/nearby_client_log.proto.h" -#include "google/protobuf/descriptor.h" -#include "gtest/gtest.h" -#include "internal/platform/logging.h" -#include "internal/proto/analytics/connections_log.pb.h" -#include "proto/connections_enums.pb.h" - -namespace nearby { -namespace analytics { -namespace proto { - -namespace { - -using G3ConnectionsLog = ::location::nearby::analytics::proto::ConnectionsLog; -using P3ConnectionsLog = ::location::nearby::analytics::proto::ConnectionsLog; - -using ::proto2::Descriptor; -using ::proto2::FieldDescriptor; - -// Forward declaration. -bool Compare(const Descriptor* desc1, const Descriptor* desc2); - -// Compares the two field descriptors and return false if name, number, label, -// or type is different. -bool Compare(const FieldDescriptor* field1, const FieldDescriptor* field2) { - if (field1->name() != field2->name()) { - LOG(WARNING) << "Field name diff: " << field1->name() << " <=> " - << field2->name(); - return false; - } - if (field1->number() != field2->number()) { - LOG(WARNING) << "Field " << field1->name() - << " number diff: " << field1->number() << " <=> " - << field2->number(); - return false; - } - if (field1->label() != field2->label()) { - LOG(WARNING) << "Field " << field1->name() - << " label diff: " << field1->label() << " <=> " - << field2->label(); - return false; - } - bool bRet = false; - if (field1->type() != field2->type()) { - LOG(WARNING) << "Field " << field1->name() - << " type diff: " << field1->type() << " <=> " - << field2->type(); - return bRet; - } else if (field1->type() == FieldDescriptor::TYPE_MESSAGE) { - const Descriptor* msg1 = field1->message_type(); - const Descriptor* msg2 = field2->message_type(); - - bRet = Compare(msg1, msg2); - } else { - bRet = true; - } - - return bRet; -} - -// Compares the two descriptors and return false immediately if different. -bool Compare(const Descriptor* desc1, const Descriptor* desc2) { - LOG(INFO) << "Descriptor1 full name: " << desc1->full_name() << " <=> " - << desc2->full_name(); - for (int i = 0; i < desc1->field_count(); ++i) { - const FieldDescriptor* field1 = desc1->field(i); - const FieldDescriptor* field2 = desc2->FindFieldByName(field1->name()); - - bool bRet = false; - if (field2) { - bRet = Compare(field1, field2); - } else { - LOG(ERROR) << "Descriptor1 full name: " << desc1->full_name() - << "=> Extra field1 name=" << field1->name() - << ", number=" << field1->number() - << ", label=" << field1->label() - << ", type=" << field1->type(); - } - if (!bRet) { - return false; - } - } - for (int i = 0; i < desc2->field_count(); ++i) { - const FieldDescriptor* field2 = desc2->field(i); - const FieldDescriptor* field1 = desc1->FindFieldByName(field2->name()); - if (!field1) { - LOG(ERROR) << "Descriptor2 full name: " << desc2->full_name() - << "=> Extra field2 name=" << field2->name() - << ", number=" << field2->number() - << ", label=" << field2->label() - << ", type=" << field2->type(); - return false; - } - } - - return true; -} - -TEST(ConnectionsLogTest, TwoMessagesAreIdentical) { - const proto2::Descriptor* descriptor1 = G3ConnectionsLog::descriptor(); - const proto2::Descriptor* descriptor2 = P3ConnectionsLog::descriptor(); - - EXPECT_TRUE(Compare(descriptor1, descriptor2)); -} - -} // namespace - -} // namespace proto -} // namespace analytics -} // namespace nearby diff --git a/internal/test/BUILD b/internal/test/BUILD index da7d9bcf..7046cd8d 100644 --- a/internal/test/BUILD +++ b/internal/test/BUILD @@ -17,36 +17,15 @@ load("@rules_cc//cc:cc_test.bzl", "cc_test") licenses(["notice"]) -cc_library( - name = "mocks", - testonly = 1, - hdrs = [ - "mock_account_manager.h", - "mock_account_observer.h", - ], - visibility = ["//visibility:public"], - deps = [ - "//internal/platform/implementation:account_manager", - "//internal/platform/implementation:signin_attempt", - "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/status", - "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings:string_view", - "@com_google_googletest//:gtest_for_library_testonly", - ], -) - cc_library( name = "test", srcs = [ - "fake_account_manager.cc", "fake_clock.cc", "fake_single_thread_executor.cc", "fake_task_runner.cc", "fake_timer.cc", ], hdrs = [ - "fake_account_manager.h", "fake_clock.h", "fake_device_info.h", "fake_http_client.h", @@ -60,20 +39,15 @@ cc_library( ], visibility = ["//visibility:public"], deps = [ - "//internal/base", "//internal/base:file_path", "//internal/base:files", "//internal/network:types", - "//internal/platform:comm", "//internal/platform:logging", "//internal/platform:types", - "//internal/platform/implementation:account_manager", - "//internal/platform/implementation:signin_attempt", "//internal/platform/implementation:types", "@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", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", diff --git a/internal/test/fake_account_manager.cc b/internal/test/fake_account_manager.cc deleted file mode 100644 index c6e919f8..00000000 --- a/internal/test/fake_account_manager.cc +++ /dev/null @@ -1,101 +0,0 @@ -// 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/test/fake_account_manager.h" - -#include -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/implementation/signin_attempt.h" - -namespace nearby { - -std::optional FakeAccountManager::GetCurrentAccount() { - return account_; -} - -std::unique_ptr FakeAccountManager::Login( - absl::string_view client_id, absl::string_view client_secret) { - return nullptr; -} - -void FakeAccountManager::Logout( - absl::AnyInvocable logout_callback) { - if (is_logout_success_) { - std::string account_id = account_->id; - SetAccount(std::nullopt); - NotifyLogout(account_id, /*credential_error=*/false); - // Invoke callback after all operations have been performed since test cases - // may rely on the callback for synchronization. - logout_callback(absl::OkStatus()); - return; - } - - logout_callback(absl::NotFoundError("No account login.")); -} - -bool FakeAccountManager::GetAccessToken( - absl::AnyInvocable)> callback) { - if (!callback) { - return false; - } - if (!account_.has_value()) { - callback(absl::UnavailableError("No current user.")); - return true; - } - callback("FAKE_ACCESS_TOKEN"); - return true; -} - -std::pair -FakeAccountManager::GetOAuthClientCredential() { - return {"", ""}; -} - -void FakeAccountManager::SetAccount(std::optional account) { - account_ = account; -} - -void FakeAccountManager::AddObserver(Observer* observer) { - observers_.AddObserver(observer); -} - -void FakeAccountManager::RemoveObserver(Observer* observer) { - if (!observers_.HasObserver(observer)) { - return; - } - observers_.RemoveObserver(observer); -} - -void FakeAccountManager::NotifyLogin(absl::string_view account_id) { - for (const auto& observer : observers_.GetObservers()) { - observer->OnLoginSucceeded(account_id); - } -} - -void FakeAccountManager::NotifyLogout(absl::string_view account_id, - bool credential_error) { - for (const auto& observer : observers_.GetObservers()) { - observer->OnLogoutSucceeded(account_id, credential_error); - } -} - -} // namespace nearby diff --git a/internal/test/fake_account_manager.h b/internal/test/fake_account_manager.h deleted file mode 100644 index 346663cf..00000000 --- a/internal/test/fake_account_manager.h +++ /dev/null @@ -1,81 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_ACCOUNT_MANAGER_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_ACCOUNT_MANAGER_H_ - -#include -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/base/observer_list.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/implementation/signin_attempt.h" - -namespace nearby { - -// A fake implementation of FakeAccountManager, along with a fake -// factory, to be used in tests. -class FakeAccountManager : public AccountManager { - public: - FakeAccountManager() = default; - ~FakeAccountManager() override = default; - - std::optional GetCurrentAccount() override; - - std::unique_ptr Login( - absl::string_view client_id, absl::string_view client_secret) override; - - void Logout(absl::AnyInvocable logout_callback) override; - - bool GetAccessToken( - absl::AnyInvocable)> callback) override; - std::pair GetOAuthClientCredential() override; - void AddObserver(Observer* observer) override; - void RemoveObserver(Observer* observer) override; - - void SaveAccountPrefs(absl::string_view user_id, absl::string_view client_id, - absl::string_view client_secret) override {} - - // Methods to set API response. - void SetAccount(std::optional account); - - void SetLogoutSuccess(bool is_logout_success) { - is_logout_success_ = is_logout_success; - } - - void NotifyCredentialError() { - NotifyLogout(account_->id, /*credential_error=*/true); - } - - void NotifyLogin(absl::string_view account_id); - void NotifyLogout(absl::string_view account_id, bool credential_error); - - private: - // Login will fail when account_ is empty. - std::optional account_; - - // Logout will fail when is_logout_success_ is false; - bool is_logout_success_ = true; - nearby::ObserverList observers_; -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_ACCOUNT_MANAGER_H_ diff --git a/internal/test/fake_clock.cc b/internal/test/fake_clock.cc index edb26a7f..8df56432 100644 --- a/internal/test/fake_clock.cc +++ b/internal/test/fake_clock.cc @@ -19,6 +19,10 @@ #include #include +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/time.h" + namespace nearby { FakeClock::~FakeClock() { diff --git a/internal/test/fake_clock.h b/internal/test/fake_clock.h index 5b7a9af8..b5fbeea6 100644 --- a/internal/test/fake_clock.h +++ b/internal/test/fake_clock.h @@ -53,6 +53,7 @@ class FakeClock : public Clock { absl::flat_hash_map> observers_ ABSL_GUARDED_BY(mutex_); }; + } // namespace nearby #endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_CLOCK_H_ diff --git a/internal/test/fake_clock_test.cc b/internal/test/fake_clock_test.cc index 0f57ce56..770f78ed 100644 --- a/internal/test/fake_clock_test.cc +++ b/internal/test/fake_clock_test.cc @@ -14,9 +14,8 @@ #include "internal/test/fake_clock.h" -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/time/time.h" namespace nearby { namespace { diff --git a/internal/test/fake_device_info.h b/internal/test/fake_device_info.h index 22d491da..f79476f1 100644 --- a/internal/test/fake_device_info.h +++ b/internal/test/fake_device_info.h @@ -27,14 +27,15 @@ #include "absl/strings/string_view.h" #include "internal/base/file_path.h" #include "internal/base/files.h" -#include "internal/platform/device_info.h" #include "internal/platform/implementation/device_info.h" namespace nearby { -class FakeDeviceInfo : public DeviceInfo { +class FakeDeviceInfo : public api::DeviceInfo { public: - std::string GetOsDeviceName() const override { return device_name_; } + std::optional GetOsDeviceName() const override { + return device_name_; + } api::DeviceInfo::DeviceType GetDeviceType() const override { return device_type_; @@ -46,8 +47,10 @@ class FakeDeviceInfo : public DeviceInfo { return download_path_; } - FilePath GetAppDataPath() const override { - return app_data_path_; + FilePath GetLocalAppDataPath(FilePath sub_path) const override { + FilePath path = app_data_path_; + path.append(sub_path); + return path; } FilePath GetTemporaryPath() const override { return temp_path_; } diff --git a/internal/test/fake_device_info_test.cc b/internal/test/fake_device_info_test.cc index 4e7c936e..5c2e8fb2 100644 --- a/internal/test/fake_device_info_test.cc +++ b/internal/test/fake_device_info_test.cc @@ -51,13 +51,16 @@ TEST(FakeDeviceInfo, GetDownloadPath) { Files::GetTemporaryDirectory().append(FilePath("test"))); } -TEST(FakeDeviceInfo, GetAppDataPath) { +TEST(FakeDeviceInfo, GetLocalAppDataPath) { FakeDeviceInfo device_info; - EXPECT_EQ(device_info.GetAppDataPath(), Files::GetTemporaryDirectory()); + EXPECT_EQ(device_info.GetLocalAppDataPath(FilePath("abc")), + Files::GetTemporaryDirectory().append(FilePath("abc"))); device_info.SetAppDataPath( Files::GetTemporaryDirectory().append(FilePath("test"))); - EXPECT_EQ(device_info.GetAppDataPath(), - Files::GetTemporaryDirectory().append(FilePath("test"))); + EXPECT_EQ(device_info.GetLocalAppDataPath(FilePath("def")), + Files::GetTemporaryDirectory() + .append(FilePath("test")) + .append(FilePath("def"))); } TEST(FakeDeviceInfo, GetTemporaryPath) { @@ -76,7 +79,8 @@ TEST(FakeDeviceInfo, GetAvailableDiskSpaceInBytes) { device_info.SetTemporaryPath(FilePath("temp")); device_info.SetAvailableDiskSpaceInBytes(device_info.GetDownloadPath(), 10); - device_info.SetAvailableDiskSpaceInBytes(device_info.GetAppDataPath(), 100); + device_info.SetAvailableDiskSpaceInBytes( + device_info.GetLocalAppDataPath(FilePath()), 100); device_info.SetAvailableDiskSpaceInBytes(device_info.GetTemporaryPath(), 1000); @@ -84,7 +88,8 @@ TEST(FakeDeviceInfo, GetAvailableDiskSpaceInBytes) { device_info.GetAvailableDiskSpaceInBytes(device_info.GetDownloadPath()), 10); EXPECT_EQ( - device_info.GetAvailableDiskSpaceInBytes(device_info.GetAppDataPath()), + device_info.GetAvailableDiskSpaceInBytes( + device_info.GetLocalAppDataPath(FilePath())), 100); EXPECT_EQ( device_info.GetAvailableDiskSpaceInBytes(device_info.GetTemporaryPath()), diff --git a/internal/test/fake_webrtc.cc b/internal/test/fake_webrtc.cc deleted file mode 100644 index e3850c86..00000000 --- a/internal/test/fake_webrtc.cc +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 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. -// 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/test/fake_webrtc.h" - -#include - -namespace nearby { - -FakeWebRtcMedium::FakeWebRtcMedium(CancellationFlag* flag) - : WebRtcMedium(), flag_(flag) {} - -FakeWebRtcMedium::~FakeWebRtcMedium() = default; - -std::unique_ptr -FakeWebRtcMedium::GetSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) { - if (cancel_during_get_signaling_messenger_) { - flag_->Cancel(); - } - - return WebRtcMedium::GetSignalingMessenger(self_id, location_hint); -} - -} // namespace nearby diff --git a/internal/test/fake_webrtc.h b/internal/test/fake_webrtc.h deleted file mode 100644 index b1f54c5c..00000000 --- a/internal/test/fake_webrtc.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 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. -// 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_TEST_FAKE_WEBRTC_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_WEBRTC_H_ - -#include - -#include "internal/platform/webrtc.h" - -namespace nearby { - -class FakeWebRtcMedium : public WebRtcMedium { - public: - explicit FakeWebRtcMedium(CancellationFlag* flag); - FakeWebRtcMedium(FakeWebRtcMedium&&) = delete; - FakeWebRtcMedium& operator=(FakeWebRtcMedium&&) = delete; - ~FakeWebRtcMedium() override; - - // WebRtcMedium: - bool IsValid() const override { return is_valid_; } - - std::unique_ptr GetSignalingMessenger( - absl::string_view self_id, - const location::nearby::connections::LocationHint& location_hint) - override; - - void TriggerCancellationDuringGetSignalingMessenger() { - cancel_during_get_signaling_messenger_ = true; - } - - void SetIsValid(bool is_valid) { is_valid_ = is_valid; } - - private: - CancellationFlag* flag_ = nullptr; - bool is_valid_ = true; - bool cancel_during_get_signaling_messenger_ = false; -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_FAKE_WEBRTC_H_ diff --git a/internal/test/mock_account_manager.h b/internal/test/mock_account_manager.h deleted file mode 100644 index 778aa7aa..00000000 --- a/internal/test/mock_account_manager.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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_TEST_MOCK_ACCOUNT_MANAGER_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_TEST_MOCK_ACCOUNT_MANAGER_H_ - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "absl/functional/any_invocable.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/implementation/signin_attempt.h" - -namespace nearby { - -class MockAccountManager : public AccountManager { - public: - MOCK_METHOD(std::optional, GetCurrentAccount, (), (override)); - MOCK_METHOD(std::unique_ptr, Login, - (absl::string_view client_id, absl::string_view client_secret), - (override)); - MOCK_METHOD(void, Logout, - (absl::AnyInvocable logout_callback), - (override)); - MOCK_METHOD(bool, GetAccessToken, - (absl::AnyInvocable)> callback), - (override)); - MOCK_METHOD((std::pair), GetOAuthClientCredential, - (), (override)); - MOCK_METHOD(void, AddObserver, (Observer * observer), (override)); - MOCK_METHOD(void, RemoveObserver, (Observer * observer), (override)); - MOCK_METHOD(void, SaveAccountPrefs, - (absl::string_view user_id, absl::string_view client_id, - absl::string_view client_secret), - (override)); -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_MOCK_ACCOUNT_MANAGER_H_ diff --git a/internal/test/mock_account_observer.h b/internal/test/mock_account_observer.h deleted file mode 100644 index bf4da0e6..00000000 --- a/internal/test/mock_account_observer.h +++ /dev/null @@ -1,38 +0,0 @@ -// 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_TEST_MOCK_ACCOUNT_OBSERVER_H_ -#define THIRD_PARTY_NEARBY_INTERNAL_TEST_MOCK_ACCOUNT_OBSERVER_H_ - -#include "gmock/gmock.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/account_manager.h" - -namespace nearby { - -class MockAccountObserver : public AccountManager::Observer { - public: - ~MockAccountObserver() override = default; - - MOCK_METHOD(void, OnLoginSucceeded, (absl::string_view account_id), - (override)); - - MOCK_METHOD(void, OnLogoutSucceeded, - (absl::string_view account_id, bool credential_error), - (override)); -}; - -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_INTERNAL_TEST_MOCK_ACCOUNT_OBSERVER_H_ diff --git a/presence/broadcast_options.h b/presence/broadcast_options.h deleted file mode 100644 index 18d11440..00000000 --- a/presence/broadcast_options.h +++ /dev/null @@ -1,36 +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 THIRD_PARTY_NEARBY_PRESENCE_BROADCAST_OPTIONS_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_BROADCAST_OPTIONS_H_ - -#include -namespace nearby { -namespace presence { -struct BroadcastOptions { - const std::int64_t reporting_interval_millis; -}; - -inline bool operator==(const BroadcastOptions& o1, const BroadcastOptions& o2) { - return o1.reporting_interval_millis == o2.reporting_interval_millis; -} - -inline bool operator!=(const BroadcastOptions& o1, const BroadcastOptions& o2) { - return !(o1 == o2); -} - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_BROADCAST_OPTIONS_H_ diff --git a/presence/broadcast_options_test.cc b/presence/broadcast_options_test.cc deleted file mode 100644 index e2e5c381..00000000 --- a/presence/broadcast_options_test.cc +++ /dev/null @@ -1,53 +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 "presence/broadcast_options.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" - -namespace nearby { -namespace presence { -namespace { - -constexpr std::int64_t kReportingIntervalMillis1 = 1000; -constexpr std::int64_t kReportingIntervalMillis2 = 2000; -TEST(BroadcastOptionsTest, NoDefaultConstructor) { - EXPECT_FALSE(std::is_trivially_constructible::value); -} - -TEST(BroadcastOptionsTest, ExplicitInitEquals) { - BroadcastOptions option1 = {kReportingIntervalMillis1}; - BroadcastOptions option2 = {kReportingIntervalMillis1}; - EXPECT_EQ(option1, option2); - EXPECT_EQ(option1.reporting_interval_millis, kReportingIntervalMillis1); -} - -TEST(BroadcastOptionsTest, ExplicitInitNotEquals) { - BroadcastOptions option1 = {kReportingIntervalMillis1}; - BroadcastOptions option2 = {kReportingIntervalMillis2}; - EXPECT_NE(option1, option2); -} - -TEST(BroadcastOptionsTest, CopyInitEquals) { - BroadcastOptions option1 = {kReportingIntervalMillis1}; - BroadcastOptions option2 = {option1}; - - EXPECT_EQ(option1, option2); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/broadcast_request.h b/presence/broadcast_request.h deleted file mode 100644 index 598ffdf3..00000000 --- a/presence/broadcast_request.h +++ /dev/null @@ -1,77 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_BROADCAST_REQUEST_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_BROADCAST_REQUEST_H_ - -#include -#include - -#include "absl/types/variant.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/power_mode.h" - -namespace nearby { -namespace presence { - -// Broadcast parameter for presence features. -struct PresenceBroadcast { - struct BroadcastSection { - // Presence identity type. - ::nearby::internal::IdentityType identity = - ::nearby::internal::IdentityType::IDENTITY_TYPE_UNSPECIFIED; - - // Additional Data Elements. - // The Presence SDK generates: - // - Salt, - // - (Private/Trusted/Public/Provisioned) Identity, - // - TX power, - // - Advertisement signature - // Data Elements when they are required in the advertisement. Other Data - // Elements are provided by the client application. - // Nearby SDK encrypts Data ELements before broadcasting if a non-public - // `PresenceIdentity` is provided. - std::vector extended_properties; - - // Account name used to select private credentials. - std::string account_name; - - // Manager app id, used to select private credentials. - std::string manager_app_id; - }; - - std::vector sections; -}; - -// Broadcast request for legacy Android T, which needs to provide credential -// and salt in the broadcast parameters. -// TODO(b/243443813) - Support Legacy Broadcast Request -struct LegacyPresenceBroadcast {}; - -// Nearby Presence advertisement request options. -struct BroadcastRequest { - // Calibrated TX power. The broadcast recipient uses it to calculate the - // distance between both devices. - int tx_power; - - // The broadcast frequency hint. - PowerMode power_mode; - - absl::variant variant; -}; - -} // namespace presence -} // namespace nearby -#endif // THIRD_PARTY_NEARBY_PRESENCE_BROADCAST_REQUEST_H_ diff --git a/presence/credential_test.cc b/presence/credential_test.cc deleted file mode 100644 index 8b1ba211..00000000 --- a/presence/credential_test.cc +++ /dev/null @@ -1,79 +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 -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "internal/platform/uuid.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" - -namespace nearby { -namespace presence { -namespace { -using ::nearby::internal::LocalCredential; -using ::nearby::internal::SharedCredential; -using ::nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; - -using ::protobuf_matchers::EqualsProto; - -TEST(CredentialsTest, NoDefaultConstructor) { - EXPECT_FALSE(std::is_trivially_constructible::value); - EXPECT_FALSE(std::is_trivially_constructible::value); -} - -TEST(CredentialsTest, InitSharedCredential) { - SharedCredential pc1 = {}; - SharedCredential pc2 = {}; - EXPECT_THAT(pc1, EqualsProto(pc2)); - pc1.set_identity_type(IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_THAT(pc1, ::testing::Not(EqualsProto(pc2))); - pc2.set_identity_type(IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_THAT(pc1, EqualsProto(pc2)); -} - -TEST(CredentialsTest, InitLocalCredential) { - LocalCredential pc1 = {}; - LocalCredential pc2 = {}; - EXPECT_THAT(pc1, EqualsProto(pc2)); - pc1.set_identity_type(IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_THAT(pc1, ::testing::Not(EqualsProto(pc2))); - pc2.set_identity_type(IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_THAT(pc1, EqualsProto(pc2)); -} - -TEST(CredentialsTest, CopyLocalCredential) { - LocalCredential pc1 = {}; - pc1.set_identity_type(IDENTITY_TYPE_PRIVATE_GROUP); - auto salts = pc1.mutable_consumed_salts(); - salts->insert(std::pair(15, true)); - LocalCredential pc1_copy = {pc1}; - EXPECT_THAT(pc1, EqualsProto(pc1_copy)); -} - -TEST(CredentialsTest, CopySharedCredential) { - SharedCredential pc1 = {}; - pc1.set_identity_type(IDENTITY_TYPE_PRIVATE_GROUP); - for (const uint8_t byte : nearby::Uuid().data()) { - pc1.mutable_secret_id()->push_back(byte); - } - SharedCredential pc1_copy = {pc1}; - EXPECT_THAT(pc1, EqualsProto(pc1_copy)); -} -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/data_element.h b/presence/data_element.h deleted file mode 100644 index eb2ffebb..00000000 --- a/presence/data_element.h +++ /dev/null @@ -1,111 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_DATA_ELEMENT_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_DATA_ELEMENT_H_ - -#include - -#include -#include -#include - -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -namespace nearby { -namespace presence { - -// Reserved Action types when the field type is kActionFieldType. -// The values are bit numbers in BE ordering. -// TODO(b/338107166): these are out of date, need to be updated to latest spec -enum class ActionBit { - kCallTransferAction = 4, - kActiveUnlockAction = 8, - kNearbyShareAction = 9, - kInstantTetheringAction = 10, - kPhoneHubAction = 11, - kPresenceManagerAction = 12, - kFinderAction = 13, - kFastPairSassAction = 14, - kTapToTransferAction = 15, - kLastAction -}; - -// helpful for enumerating overall all possible action bit types, this must be -// kept in sync with the above enum -constexpr std::initializer_list kAllActionBits = { - ActionBit::kCallTransferAction, ActionBit::kActiveUnlockAction, - ActionBit::kNearbyShareAction, ActionBit::kInstantTetheringAction, - ActionBit::kPhoneHubAction, ActionBit::kPresenceManagerAction, - ActionBit::kFinderAction, ActionBit::kFastPairSassAction, - ActionBit::kTapToTransferAction}; - -/** Describes a custom Data element in NP advertisement. */ -class DataElement { - public: - // The field types listed below require special processing when generating and - // parsing NP advertisements. - static constexpr int kSaltFieldType = 0; - static constexpr int kPrivateGroupIdentityFieldType = 1; - static constexpr int kContactsGroupIdentityFieldType = 2; - static constexpr int kPublicIdentityFieldType = 3; - static constexpr int kTxPowerFieldType = 5; - static constexpr int kActionFieldType = 6; - static constexpr int kModelIdFieldType = 7; - static constexpr int kEddystoneIdFieldType = 8; - static constexpr int kAccountKeyDataFieldType = 9; - static constexpr int kConnectionStatusFieldType = 10; - static constexpr int kBatteryFieldType = 11; - static constexpr int kAdvertisementSignature = 12; - static constexpr int kContextTimestampFieldType = 13; - // Maximum allowed Data Element's value length - static constexpr int kMaxDataElementLength = 15; - // Maximum allowed Data Element's type - static constexpr int kMaxDataElementType = 15; - // The DE header is (length << kDataElementLengthShift | type) - static constexpr int kDataElementLengthShift = 4; - - DataElement(uint16_t type, absl::string_view value) - : type_(type), value_(value) {} - - DataElement(uint16_t type, uint8_t value) - : type_(type), - value_(reinterpret_cast(&value), sizeof(value)) {} - - explicit DataElement(ActionBit action) - : DataElement(kActionFieldType, static_cast(action)) {} - - ~DataElement() = default; - - uint16_t GetType() const { return type_; } - absl::string_view GetValue() const { return value_; } - - private: - uint16_t type_; - std::string value_; -}; - -inline bool operator==(const DataElement& i1, const DataElement& i2) { - return i1.GetType() == i2.GetType() && i1.GetValue() == i2.GetValue(); -} - -inline std::ostream& operator<<(std::ostream& os, const DataElement& elem) { - return os << "DataElement(" << elem.GetType() << ", " - << absl::BytesToHexString(elem.GetValue()) << ")"; -} - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_DATA_ELEMENT_H_ diff --git a/presence/data_types.h b/presence/data_types.h deleted file mode 100644 index 48fdde74..00000000 --- a/presence/data_types.h +++ /dev/null @@ -1,64 +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 THIRD_PARTY_NEARBY_PRESENCE_SCAN_CALLBACK_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_SCAN_CALLBACK_H_ - -#include - -#include "absl/functional/any_invocable.h" -#include "internal/platform/logging.h" -#include "presence/presence_device.h" - -namespace nearby { -namespace presence { - -// Unique Scan Session Identifier. -using ScanSessionId = uint64_t; - -// Callers would provide the implementation of these callbacks. If callers -// don't need these signal updates, they can skip with the provided default -// empty functions. -struct ScanCallback { - // Updates client with the result of start scanning. - absl::AnyInvocable start_scan_cb = [](absl::Status) {}; - - // Reports a {@link PresenceDevice} being discovered. - absl::AnyInvocable on_discovered_cb = - [](PresenceDevice) {}; - - // Reports a {@link PresenceDevice} information(distance, and etc) - // changed. - absl::AnyInvocable on_updated_cb = [](PresenceDevice) { - }; - - // Reports a {@link PresenceDevice} is no longer within range. - absl::AnyInvocable on_lost_cb = [](PresenceDevice) {}; -}; - -// Unique Broadcast Session Identifier. -using BroadcastSessionId = uint64_t; - -// Callers would provide the implementation of these callbacks. If callers -// don't need these signal updates, they can skip with the provided default -// empty functions. -struct BroadcastCallback { - absl::AnyInvocable start_broadcast_cb = [](absl::Status) { - }; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_SCAN_CALLBACK_H_ diff --git a/presence/device_motion.h b/presence/device_motion.h deleted file mode 100644 index 439b5349..00000000 --- a/presence/device_motion.h +++ /dev/null @@ -1,47 +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 THIRD_PARTY_NEARBY_PRESENCE_DEVICE_MOTION_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_DEVICE_MOTION_H_ - -namespace nearby { -namespace presence { -class DeviceMotion { - public: - enum class MotionType { - kPointAndHold = 0, - kStationaryAndHold = 1, - }; - DeviceMotion(MotionType motion_type = MotionType::kPointAndHold, - float confidence = 0) noexcept; - MotionType GetMotionType() const; - float GetConfidence() const; - - private: - const MotionType motion_type_; - const float confidence_; -}; - -inline bool operator==(const DeviceMotion& m1, const DeviceMotion& m2) { - return m1.GetMotionType() == m2.GetMotionType() && - m1.GetConfidence() == m2.GetConfidence(); -} -inline bool operator!=(const DeviceMotion& m1, const DeviceMotion& m2) { - return !(m1 == m2); -} - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_DEVICE_MOTION_H_ diff --git a/presence/device_motion_test.cc b/presence/device_motion_test.cc deleted file mode 100644 index 1155903a..00000000 --- a/presence/device_motion_test.cc +++ /dev/null @@ -1,61 +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 "presence/device_motion.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" - -namespace nearby { -namespace presence { -namespace { -static const DeviceMotion::MotionType kDefaultMotionType = - DeviceMotion::MotionType::kPointAndHold; -static const float kDefaultConfidence = 0; -static const float kConfidenceForTest = 0.1; -TEST(DeviceMotionTest, DefaultConstructorWorks) { - DeviceMotion motion; - EXPECT_EQ(motion.GetMotionType(), kDefaultMotionType); - EXPECT_EQ(motion.GetConfidence(), kDefaultConfidence); -} - -TEST(DeviceMotionTest, DefaultEquals) { - DeviceMotion motion1; - DeviceMotion motion2; - EXPECT_EQ(motion1, motion2); -} - -TEST(DeviceMotionTest, ExplicitInitEquals) { - DeviceMotion motion1 = {kDefaultMotionType, kConfidenceForTest}; - DeviceMotion motion2 = {kDefaultMotionType, kConfidenceForTest}; - EXPECT_EQ(motion1, motion2); - EXPECT_EQ(motion1.GetConfidence(), kConfidenceForTest); -} - -TEST(DeviceMotionTest, ExplicitInitNotEquals) { - DeviceMotion motion1 = {kDefaultMotionType, kConfidenceForTest}; - DeviceMotion motion2 = {kDefaultMotionType}; - EXPECT_NE(motion1, motion2); -} - -TEST(DeviceMotionTest, CopyInitEquals) { - DeviceMotion motion1; - DeviceMotion motion2 = {motion1}; - EXPECT_EQ(motion1, motion2); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/discovery_filter.cc b/presence/discovery_filter.cc deleted file mode 100644 index 453309a5..00000000 --- a/presence/discovery_filter.cc +++ /dev/null @@ -1,36 +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 "presence/discovery_filter.h" - -namespace nearby { -namespace presence { - -using ::nearby::internal::IdentityType; - -DiscoveryFilter::DiscoveryFilter( - const std::vector& actions, - const std::vector& identities, - const std::vector& zones) noexcept - : actions_(actions), identities_(identities), zones_(zones) {} -std::vector DiscoveryFilter::GetActions() const { - return actions_; -} -std::vector DiscoveryFilter::GetIdentities() const { - return identities_; -} -std::vector DiscoveryFilter::GetZones() const { return zones_; } - -} // namespace presence -} // namespace nearby diff --git a/presence/discovery_filter.h b/presence/discovery_filter.h deleted file mode 100644 index 06b72413..00000000 --- a/presence/discovery_filter.h +++ /dev/null @@ -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 THIRD_PARTY_NEARBY_PRESENCE_DISCOVERY_FILTER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_DISCOVERY_FILTER_H_ - -#include - -#include "internal/proto/credential.pb.h" -#include "presence/presence_action.h" -#include "presence/presence_zone.h" -namespace nearby { -namespace presence { -class DiscoveryFilter { - public: - DiscoveryFilter(const std::vector& = {}, - const std::vector<::nearby::internal::IdentityType>& = {}, - const std::vector& = {}) noexcept; - std::vector GetActions() const; - std::vector<::nearby::internal::IdentityType> GetIdentities() const; - std::vector GetZones() const; - - private: - const std::vector actions_; - const std::vector<::nearby::internal::IdentityType> identities_; - const std::vector zones_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_DISCOVERY_FILTER_H_ diff --git a/presence/discovery_filter_test.cc b/presence/discovery_filter_test.cc deleted file mode 100644 index c85f8f83..00000000 --- a/presence/discovery_filter_test.cc +++ /dev/null @@ -1,51 +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 "presence/discovery_filter.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" - -namespace nearby { -namespace presence { -namespace { - -using ::nearby::internal::IdentityType; - -const PresenceAction kTestAction = {1}; -const IdentityType kTestIdentity = {IdentityType::IDENTITY_TYPE_CONTACTS_GROUP}; - -TEST(DiscoveryFilterTest, DefaultConstructorWorks) { - DiscoveryFilter filter; - EXPECT_EQ(filter.GetActions().size(), 0); - EXPECT_EQ(filter.GetIdentities().size(), 0); - EXPECT_EQ(filter.GetZones().size(), 0); -} - -TEST(DiscoveryFilterTest, PartiallyInitializationWorks) { - DiscoveryFilter filter1{{kTestAction}, {kTestIdentity}}; - DiscoveryFilter filter2{{kTestAction}}; - EXPECT_EQ(filter1.GetActions(), filter2.GetActions()); - EXPECT_NE(filter1.GetIdentities(), filter2.GetIdentities()); - EXPECT_EQ(filter1.GetZones(), filter2.GetZones()); - - EXPECT_EQ(filter1.GetActions()[0], kTestAction); - EXPECT_EQ(filter1.GetIdentities()[0], kTestIdentity); - EXPECT_EQ(filter1.GetZones().capacity(), 0); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/discovery_options.h b/presence/discovery_options.h deleted file mode 100644 index 44dcfc0b..00000000 --- a/presence/discovery_options.h +++ /dev/null @@ -1,34 +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 THIRD_PARTY_NEARBY_PRESENCE_DISCOVERY_OPTIONS_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_DISCOVERY_OPTIONS_H_ - -namespace nearby { -namespace presence { -struct DiscoveryOptions { - const bool local_wifi_only_; -}; - -inline bool operator==(const DiscoveryOptions& o1, const DiscoveryOptions& o2) { - return o1.local_wifi_only_ == o2.local_wifi_only_; -} - -inline bool operator!=(const DiscoveryOptions& o1, const DiscoveryOptions& o2) { - return !(o1 == o2); -} - -} // namespace presence -} // namespace nearby -#endif // THIRD_PARTY_NEARBY_PRESENCE_DISCOVERY_OPTIONS_H_ diff --git a/presence/discovery_options_test.cc b/presence/discovery_options_test.cc deleted file mode 100644 index 631ed12f..00000000 --- a/presence/discovery_options_test.cc +++ /dev/null @@ -1,51 +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 "presence/discovery_options.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" - -namespace nearby { -namespace presence { -namespace { - -constexpr bool kTestLocalWifiOnly = false; -TEST(DiscoveryOptionsTest, NoDefaultConstructor) { - EXPECT_FALSE(std::is_trivially_constructible::value); -} - -TEST(DiscoveryOptionsTest, ExplicitInitEquals) { - DiscoveryOptions option1 = {kTestLocalWifiOnly}; - DiscoveryOptions option2 = {kTestLocalWifiOnly}; - EXPECT_EQ(option1, option2); - EXPECT_EQ(option1.local_wifi_only_, kTestLocalWifiOnly); -} - -TEST(DiscoveryOptionsTest, ExplicitInitNotEquals) { - DiscoveryOptions option1 = {kTestLocalWifiOnly}; - DiscoveryOptions option2 = {!kTestLocalWifiOnly}; - EXPECT_NE(option1, option2); -} - -TEST(DiscoveryOptionsTest, CopyInitEquals) { - DiscoveryOptions option1 = {kTestLocalWifiOnly}; - DiscoveryOptions option2 = {option1}; - EXPECT_EQ(option1, option2); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/fake_presence_client.cc b/presence/fake_presence_client.cc deleted file mode 100644 index 44e73440..00000000 --- a/presence/fake_presence_client.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 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. -// 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 "presence/fake_presence_client.h" - - -#include -#include -#include - -#include "presence/data_types.h" -#include "presence/presence_device.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -absl::StatusOr FakePresenceClient::StartScan( - ScanRequest scan_request, ScanCallback callback) { - current_scan_session_id_++; - active_scan_sessions_.push_back(current_scan_session_id_); - absl::StatusOr scan_session_id(current_scan_session_id_); - callback_ = std::move(callback); - return scan_session_id; -} - -void FakePresenceClient::StopScan(ScanSessionId id) { - auto position = - std::find(active_scan_sessions_.begin(), active_scan_sessions_.end(), id); - if (position != active_scan_sessions_.end()) { - active_scan_sessions_.erase(position); - } -} - -std::vector FakePresenceClient::GetActiveScanSessions() { - return active_scan_sessions_; -} - -void FakePresenceClient::CallStartScanCallback(absl::Status status) { - callback_.start_scan_cb(status); -} - -void FakePresenceClient::CallOnDiscovered(PresenceDevice device) { - callback_.on_discovered_cb(device); -} - -void FakePresenceClient::CallOnUpdated(PresenceDevice device) { - callback_.on_updated_cb(device); -} - -void FakePresenceClient::CallOnLost(PresenceDevice device) { - callback_.on_lost_cb(device); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/fake_presence_client.h b/presence/fake_presence_client.h deleted file mode 100644 index b2a6d816..00000000 --- a/presence/fake_presence_client.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_FAKE_PRESENCE_CLIENT_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ - -#include -#include - -#include "absl/status/statusor.h" -#include "presence/broadcast_request.h" -#include "presence/presence_client.h" -#include "presence/presence_device.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -class FakePresenceClient : public PresenceClient { - public: - FakePresenceClient() = default; - FakePresenceClient(const FakePresenceClient&) = delete; - FakePresenceClient(FakePresenceClient&&) = default; - FakePresenceClient& operator=(const FakePresenceClient&) = delete; - ~FakePresenceClient() = default; - - absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) override; - - void StopScan(ScanSessionId session_id) override; - - // Not Implemented. - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) override { - return 0; - } - - // Not Implemented. - void StopBroadcast(BroadcastSessionId session_id) override {} - - // Not Implemented. - std::optional GetLocalDevice() override { - return std::nullopt; - } - - - std::vector GetActiveScanSessions(); - void CallStartScanCallback(absl::Status status); - void CallOnDiscovered(PresenceDevice device); - void CallOnUpdated(PresenceDevice device); - void CallOnLost(PresenceDevice device); - - private: - uint64_t current_scan_session_id_; - ScanCallback callback_; - std::vector active_scan_sessions_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_CLIENT_H_ diff --git a/presence/fake_presence_service.cc b/presence/fake_presence_service.cc deleted file mode 100644 index ff06221a..00000000 --- a/presence/fake_presence_service.cc +++ /dev/null @@ -1,107 +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 "presence/fake_presence_service.h" - -#include -#include -#include - -#include "internal/interop/device_provider.h" -#include "internal/platform/borrowable.h" -#include "presence/fake_presence_client.h" - -namespace nearby { -namespace presence { - -FakePresenceService::FakePresenceService() = default; - -std::unique_ptr FakePresenceService::CreatePresenceClient() { - auto fake = std::make_unique(); - most_recent_fake_presence_client_ = fake.get(); - return std::move(fake); -} - -// Not implemented. -absl::StatusOr FakePresenceService::StartScan( - ScanRequest scan_request, ScanCallback callback) { - return absl::Status(absl::StatusCode::kCancelled, - "StartScan not implemented yet"); -} - -// Not implemented. -void FakePresenceService::StopScan(ScanSessionId session_id) {} - -// Not implemented. -absl::StatusOr FakePresenceService::StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) { - return absl::Status(absl::StatusCode::kCancelled, - "StartBroadcast not implemented yet"); -} - -// Not implemented. -void FakePresenceService::StopBroadcast(BroadcastSessionId session_id) {} - -void FakePresenceService::UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& metadata, - bool regen_credentials, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) { - metadata_ = metadata; - - if (!regen_credentials) { - // No need to call back on credentials_generated_cb. - return; - } - - if (gen_credentials_status_.ok()) { - std::move(credentials_generated_cb.credentials_generated_cb)( - shared_credentials_); - } else { - std::move(credentials_generated_cb.credentials_generated_cb)( - gen_credentials_status_); - } -} - -NearbyDeviceProvider* FakePresenceService::GetLocalDeviceProvider() { - return provider_; -} - -void FakePresenceService::GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) { - if (get_public_credentials_status_.ok()) { - std::move(callback.credentials_fetched_cb)(shared_credentials_); - return; - } - - std::move(callback.credentials_fetched_cb)(get_public_credentials_status_); -} - -void FakePresenceService::UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) { - if (update_remote_public_credentials_status_.ok()) { - remote_shared_credentials_ = remote_public_creds; - } - - std::move(credentials_updated_cb.credentials_updated_cb)( - update_remote_public_credentials_status_); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/fake_presence_service.h b/presence/fake_presence_service.h deleted file mode 100644 index 81dca042..00000000 --- a/presence/fake_presence_service.h +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_FAKE_PRESENCE_SERVICE_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_SERVICE_H_ - -#include "internal/interop/device_provider.h" -#include "internal/interop/fake_device_provider.h" -#include "internal/platform/borrowable.h" -#include "internal/proto/metadata.pb.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/presence_client.h" -#include "presence/presence_service.h" - -namespace nearby { -namespace presence { - -class FakePresenceClient; - -class FakePresenceService : public PresenceService { - public: - FakePresenceService(); - ~FakePresenceService() override { lender_.Release(); } - - // PresenceService: - std::unique_ptr CreatePresenceClient() override; - - absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) override; - - void StopScan(ScanSessionId session_id) override; - - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) override; - - void StopBroadcast(BroadcastSessionId session_id) override; - - void UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& metadata, - bool regen_credentials, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) override; - - NearbyDeviceProvider* GetLocalDeviceProvider() override; - - ::nearby::internal::DeviceIdentityMetaData GetDeviceIdentityMetaData() - override { - return metadata_; - } - - void GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) override; - void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) override; - - // Use for testing. Call this to set the response to - // `UpdateLocalDeviceMetadata`. - void SetUpdateLocalDeviceMetadataResponse( - absl::Status status, - std::vector shared_credentials) { - shared_credentials_ = shared_credentials; - gen_credentials_status_ = status; - } - - FakePresenceClient* GetMostRecentFakePresenceClient() { - return most_recent_fake_presence_client_; - } - - // Used for testing to verify the remote credentials set. - std::vector GetRemoteSharedCredentials() { - return remote_shared_credentials_; - } - - void SetUpdateRemoteSharedCredentialsResult(absl::Status status) { - update_remote_public_credentials_status_ = status; - } - - void SetLocalPublicCredentialsResult( - absl::Status status, - std::vector shared_credentials) { - get_public_credentials_status_ = status; - shared_credentials_ = shared_credentials; - } - - void SetDeviceProvider(NearbyDeviceProvider* provider) { - provider_ = provider; - } - - private: - FakePresenceClient* most_recent_fake_presence_client_ = nullptr; - std::vector shared_credentials_; - std::vector remote_shared_credentials_; - absl::Status gen_credentials_status_; - absl::Status update_remote_public_credentials_status_; - absl::Status get_public_credentials_status_; - ::nearby::internal::DeviceIdentityMetaData metadata_; - NearbyDeviceProvider* provider_; - ::nearby::Lender lender_{this}; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_FAKE_PRESENCE_SERVICE_H_ diff --git a/presence/fpp/BUILD b/presence/fpp/BUILD deleted file mode 100644 index 6e5d738d..00000000 --- a/presence/fpp/BUILD +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 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. -# You may obtain a copy of the License at -# -# http://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. - -load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") - -licenses(["notice"]) - -cc_library( - name = "fpp_manager", - srcs = [ - "fpp_manager.cc", - ], - hdrs = ["fpp_manager.h"], - visibility = [ - "//presence:__subpackages__", - ], - deps = [ - "//internal/platform:logging", - "//presence:types", - "//presence/fpp/fpp_c_ffi", - "//presence/implementation:sensor_fusion", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/status", - ], -) - -cc_library( - name = "sensor_fusion_impl", - srcs = [ - "sensor_fusion_impl.cc", - ], - hdrs = ["sensor_fusion_impl.h"], - visibility = [ - "//presence:__subpackages__", - ], - deps = [ - ":fpp_manager", - "//presence/implementation:sensor_fusion", - "@com_google_absl//absl/status", - ], -) - -cc_test( - name = "fpp_manager_test", - size = "small", - srcs = ["fpp_manager_test.cc"], - deps = [ - ":fpp_manager", - "//presence/implementation:sensor_fusion", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/status", - "@com_google_googletest//:gtest_main", - ] + select({ - "@platforms//os:windows": [ - "//internal/platform/implementation/windows", - ], - "//conditions:default": [ - "//internal/platform/implementation/g3", - ], - }), -) - -cc_test( - name = "sensor_fusion_test", - size = "small", - srcs = ["sensor_fusion_test.cc"], - deps = [ - ":sensor_fusion_impl", - "//presence/implementation:sensor_fusion", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/status", - "@com_google_googletest//:gtest_main", - ] + select({ - "@platforms//os:windows": [ - "//internal/platform/implementation/windows", - ], - "//conditions:default": [ - "//internal/platform/implementation/g3", - ], - }), -) diff --git a/presence/fpp/fpp/Cargo.lock b/presence/fpp/fpp/Cargo.lock deleted file mode 100644 index be2b9180..00000000 --- a/presence/fpp/fpp/Cargo.lock +++ /dev/null @@ -1,25 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "fpp" -version = "0.1.0" -dependencies = [ - "itertools", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] diff --git a/presence/fpp/fpp/Cargo.toml b/presence/fpp/fpp/Cargo.toml deleted file mode 100644 index b3de1c90..00000000 --- a/presence/fpp/fpp/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "fpp" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -itertools = "0.10.5" diff --git a/presence/fpp/fpp/src/fspl_converter.rs b/presence/fpp/fpp/src/fspl_converter.rs deleted file mode 100644 index 6b03f6b8..00000000 --- a/presence/fpp/fpp/src/fspl_converter.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -const ADVERTISE_TX_POWER_HIGH_DB: i32 = 1; - -const FSPL_AT_1_METER_DB: i32 = 40; - -const MEASURED_POWER_AT_1_METER_DB_AT_HIGH_TX_POWER: i32 = -60; - -pub fn compute_distance_meters_at_high_tx_power(rssi: i32) -> f64 { - let nominal_tx_power = ADVERTISE_TX_POWER_HIGH_DB; - let antenna_gain = - (nominal_tx_power - FSPL_AT_1_METER_DB) - MEASURED_POWER_AT_1_METER_DB_AT_HIGH_TX_POWER; - let tx_power_at_0_meters = nominal_tx_power - antenna_gain; - compute_distance_meters(tx_power_at_0_meters, rssi) -} - -pub fn compute_distance_meters(tx_power_at_0_meters: i32, rssi: i32) -> f64 { - let fspl = tx_power_at_0_meters - rssi; - ble_fspl_to_meters(fspl) -} - -fn ble_fspl_to_meters(fspl: i32) -> f64 { - let base: f64 = 10.0; - base.powi((fspl - FSPL_AT_1_METER_DB) / 20) -} diff --git a/presence/fpp/fpp/src/fspl_converter_test.rs b/presence/fpp/fpp/src/fspl_converter_test.rs deleted file mode 100644 index efa273c8..00000000 --- a/presence/fpp/fpp/src/fspl_converter_test.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -use crate::fspl_converter::compute_distance_meters_at_high_tx_power; - -#[test] -fn test_short_distance() { - assert_eq!(compute_distance_meters_at_high_tx_power(-40), 0.1); -} - -#[test] -fn test_medium_distance() { - assert_eq!(compute_distance_meters_at_high_tx_power(-60), 1.0); -} - -#[test] -fn test_large_distance() { - assert_eq!(compute_distance_meters_at_high_tx_power(-80), 10.0); -} diff --git a/presence/fpp/fpp/src/fused_presence_utils.rs b/presence/fpp/fpp/src/fused_presence_utils.rs deleted file mode 100644 index 48b2dd0e..00000000 --- a/presence/fpp/fpp/src/fused_presence_utils.rs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -pub(crate) const DEFAULT_TAP_DISTANCE_THRESHOLD_METERS: f64 = AMBIGUITY_METERS + 0.02; -pub(crate) const DEFAULT_REACH_DISTANCE_THRESHOLD_METERS: f64 = AMBIGUITY_METERS + 0.5; -pub(crate) const DEFAULT_SHORT_RANGE_DISTANCE_THRESHOLD_METERS: f64 = AMBIGUITY_METERS + 1.2; -pub(crate) const DEFAULT_LONG_RANGE_DISTANCE_THRESHOLD_METERS: f64 = AMBIGUITY_METERS + 3.0; -pub(crate) const DEFAULT_CONSECUTIVE_SCANS_REQUIRED: u8 = 2; -const AMBIGUITY_METERS: f64 = 0.06; - -/// Proximity state from device to another in terms of actionability -#[derive(Eq, Hash, Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum ProximityState { - /// Unknown proximity state - Unknown, - /// The device is within a tap zone (<0.02m) - Tap, - /// The device is within a reach zone (<0.5m) - Reach, - /// The device is within a short range zone (<1.2m) - ShortRange, - /// The device is within a long range zone (<3.0m) - LongRange, - /// The device is at a far range - Far, -} - -/// Represents the confidence levels for a given measurement -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum MeasurementConfidence { - /// Measurement confidence is low, the default for BLE medium - Low, - /// Measurement confidence is medium - Medium, - /// Measurement confidence is High - High, - /// Measurement confidence is unknown - Unknown, -} - -/// Data sources that are used to track presence -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub enum PresenceDataSource { - /// Data source for proximity estimate is BLE - Ble, - /// Data source for proximity estimate is UWB - Uwb, - /// Data source for proximity estimate is NAN - Nan, - /// Data source for proximity estimate is unknown - Unknown, -} - -/// A PII-stripped subset of Bluetooth scan result -#[repr(C)] -pub struct BleScanResult { - /// Device ID of the nearby device - pub device_id: u64, - /// Transmitting power of signal - pub tx_power: MaybeTxPower, - /// RSSI value - pub rssi: i32, - /// Time scan result was obtained - pub elapsed_real_time_millis: u64, -} - -/// Enum representing an optional tx power value -#[repr(C)] -pub enum MaybeTxPower { - /// Valid TX power with associated data value - Valid(i32), - /// Absent Tx Power - Invalid, -} - -/// Describes the most accurate and recent measurement for a given device -#[derive(Copy, Clone, PartialEq, Debug)] -#[repr(C)] -pub struct ProximityEstimate { - /// Device ID of the nearby device - pub device_id: u64, - /// Distance to the nearby device in meters - pub distance_meters: f64, - /// Measurement confidence of the estimate - pub distance_confidence: MeasurementConfidence, - /// The time the proximity estimate was obtained (milliseconds since the - /// program start time) - pub elapsed_real_time_millis: u64, - /// Proximity state zone of the nearby device - pub proximity_state: ProximityState, - /// Medium through which the proximity estimate was computed - pub source: PresenceDataSource, -} diff --git a/presence/fpp/fpp/src/lib.rs b/presence/fpp/fpp/src/lib.rs deleted file mode 100644 index ef30da9e..00000000 --- a/presence/fpp/fpp/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -#![deny( - missing_docs, - clippy::indexing_slicing, - clippy::unwrap_used, - clippy::panic, - clippy::expect_used -)] - -//! Processes raw scan results from BLE, UWB and NAN and outputs proximity estimates/zones - -mod fspl_converter; - -/// Fused presence Utils -pub mod fused_presence_utils; - -/// Presence detector module -pub mod presence_detector; - -#[cfg(test)] -mod fspl_converter_test; - -#[cfg(test)] -mod presence_detector_test; diff --git a/presence/fpp/fpp/src/presence_detector.rs b/presence/fpp/fpp/src/presence_detector.rs deleted file mode 100644 index 7f613ab5..00000000 --- a/presence/fpp/fpp/src/presence_detector.rs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -use std::collections::{HashMap, VecDeque}; -use std::time::{Instant, SystemTime}; - -use itertools::Itertools; - -use crate::fspl_converter::compute_distance_meters_at_high_tx_power; -use crate::fused_presence_utils::{ - BleScanResult, MaybeTxPower, MeasurementConfidence, PresenceDataSource, ProximityEstimate, - ProximityState, DEFAULT_CONSECUTIVE_SCANS_REQUIRED, - DEFAULT_LONG_RANGE_DISTANCE_THRESHOLD_METERS, DEFAULT_REACH_DISTANCE_THRESHOLD_METERS, - DEFAULT_SHORT_RANGE_DISTANCE_THRESHOLD_METERS, DEFAULT_TAP_DISTANCE_THRESHOLD_METERS, -}; - -const MAX_RSSI_FILTER_VALUE: i32 = 10; -const DEFAULT_ESTIMATED_DISTANCE_DATA_TTL_MILLIS: u128 = 4000; - -/// Static function for getting proximity state from threshold -fn get_proximity_state_from_threshold(distance_meters: f64) -> ProximityState { - if distance_meters <= DEFAULT_TAP_DISTANCE_THRESHOLD_METERS { - return ProximityState::Tap; - } - if distance_meters <= DEFAULT_REACH_DISTANCE_THRESHOLD_METERS { - return ProximityState::Reach; - } - if distance_meters <= DEFAULT_SHORT_RANGE_DISTANCE_THRESHOLD_METERS { - return ProximityState::ShortRange; - } - if distance_meters <= DEFAULT_LONG_RANGE_DISTANCE_THRESHOLD_METERS { - return ProximityState::LongRange; - } - ProximityState::Far -} - -/// Tracks and computes proximity/presence state events. -pub struct PresenceDetector { - start_time: Instant, - last_range_update_time: RangingUpdateTime, - best_proximity_estimate_per_device: HashMap, - transition_history: VecDeque, -} - -struct RangingUpdateTime(u128); - -impl RangingUpdateTime { - pub fn is_expired(&self) -> bool { - let elapsed_real_time_millis = Instant::now().elapsed().as_millis(); - elapsed_real_time_millis - self.0 > DEFAULT_ESTIMATED_DISTANCE_DATA_TTL_MILLIS - } - - pub fn update(&mut self, start_time: Instant) { - self.0 = Instant::now().duration_since(start_time).as_millis(); - } -} - -impl PresenceDetector { - /// Creates a new instance of presence detector - pub fn new() -> Self { - PresenceDetector { - start_time: Instant::now(), - last_range_update_time: RangingUpdateTime(0), - best_proximity_estimate_per_device: HashMap::new(), - transition_history: VecDeque::with_capacity( - (DEFAULT_CONSECUTIVE_SCANS_REQUIRED + 1).into(), - ), - } - } - - /// Updates the presence detector with a new scan result and returns the - /// current proximity estimate - pub fn on_ble_scan_result( - &mut self, - ble_scan_result: BleScanResult, - ) -> Option { - let device_id = ble_scan_result.device_id; - if ble_scan_result.rssi > MAX_RSSI_FILTER_VALUE { - return self.best_proximity_estimate_per_device.get(&device_id).copied(); - } - if self.last_range_update_time.is_expired() { - self.transition_history.clear(); - } - let mut tx_power: i32 = 0; - if let MaybeTxPower::Valid(some_tx_power) = ble_scan_result.tx_power { - tx_power = some_tx_power; - } - let rssi = ble_scan_result.rssi + tx_power; - let distance_meters = compute_distance_meters_at_high_tx_power(rssi); - let new_proximity_estimate = ProximityEstimate { - device_id, - distance_confidence: MeasurementConfidence::Low, - distance_meters, - proximity_state: get_proximity_state_from_threshold(distance_meters), - elapsed_real_time_millis: Instant::now().duration_since(self.start_time).as_millis() - as u64, - source: PresenceDataSource::Ble, - }; - self.transition_history.push_front(new_proximity_estimate.proximity_state); - self.transition_history.truncate(DEFAULT_CONSECUTIVE_SCANS_REQUIRED.into()); - if self.transition_history.iter().unique().count() == 1 - && self.transition_history.len() == DEFAULT_CONSECUTIVE_SCANS_REQUIRED.into() - { - self.best_proximity_estimate_per_device.insert(device_id, new_proximity_estimate); - self.last_range_update_time.update(self.start_time); - } - self.best_proximity_estimate_per_device.get(&device_id).copied() - } - - /// Returns the current proximity estimate for a given device - pub fn get_proximity_estimate(&self, device_id: u64) -> Option { - self.best_proximity_estimate_per_device.get(&device_id).copied() - } -} - -impl Default for PresenceDetector { - fn default() -> Self { - Self::new() - } -} diff --git a/presence/fpp/fpp/src/presence_detector_test.rs b/presence/fpp/fpp/src/presence_detector_test.rs deleted file mode 100644 index 1d35f187..00000000 --- a/presence/fpp/fpp/src/presence_detector_test.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -use crate::fused_presence_utils::*; -use crate::presence_detector::*; - -const BLE_SCAN_RESULT_REACH_ZONE: BleScanResult = BleScanResult { - device_id: 1234, - tx_power: { MaybeTxPower::Invalid }, - rssi: -40, - elapsed_real_time_millis: 123456, -}; - -const BLE_SCAN_RESULT_BAD_RSSI: BleScanResult = BleScanResult { - rssi: 127, - ..BLE_SCAN_RESULT_REACH_ZONE -}; - -const BLE_SCAN_RESULT_SHORT_RANGE_ZONE: BleScanResult = BleScanResult { - rssi: -60, - ..BLE_SCAN_RESULT_REACH_ZONE -}; - -const REACH_PROXIMITY_ESTIMATE: ProximityEstimate = ProximityEstimate { - device_id: 1234, - distance_meters: 0.1, - distance_confidence: MeasurementConfidence::Low, - elapsed_real_time_millis: 0, - proximity_state: ProximityState::Reach, - source: PresenceDataSource::Ble, -}; - -const SHORT_RANGE_PROXIMITY_ESTIMATE: ProximityEstimate = ProximityEstimate { - distance_meters: 1.0, - proximity_state: ProximityState::ShortRange, - ..REACH_PROXIMITY_ESTIMATE -}; - -#[test] -fn test_on_ble_scan_result_success() { - // Tests that the proximity state stored for each device is the accurate one after two - // consecutive scan results - let mut presence_detector = PresenceDetector::new(); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_REACH_ZONE), - None - ); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_REACH_ZONE), - Some(ProximityEstimate { - device_id: 1234, - distance_meters: 0.1, - distance_confidence: MeasurementConfidence::Low, - elapsed_real_time_millis: 0, - proximity_state: ProximityState::Reach, - source: PresenceDataSource::Ble - }) - ); -} - -#[test] -fn test_on_ble_scan_result_bad_rssi() { - // Tests that scan results with bad RSSIs are ignored - let mut presence_detector = PresenceDetector::new(); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_REACH_ZONE), - None - ); - - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_BAD_RSSI), - None - ); -} -#[test] -fn test_on_ble_scan_result_transition_to_new_zone() { - let mut presence_detector = PresenceDetector::new(); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_REACH_ZONE), - None - ); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_REACH_ZONE), - Some(REACH_PROXIMITY_ESTIMATE) - ); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_SHORT_RANGE_ZONE), - Some(REACH_PROXIMITY_ESTIMATE) - ); - assert_eq!( - presence_detector.on_ble_scan_result(BLE_SCAN_RESULT_SHORT_RANGE_ZONE), - Some(SHORT_RANGE_PROXIMITY_ESTIMATE) - ); -} diff --git a/presence/fpp/fpp_c_ffi/Cargo.lock b/presence/fpp/fpp_c_ffi/Cargo.lock deleted file mode 100644 index 99bf6078..00000000 --- a/presence/fpp/fpp_c_ffi/Cargo.lock +++ /dev/null @@ -1,105 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "fpp" -version = "0.1.0" -dependencies = [ - "itertools", -] - -[[package]] -name = "fpp_c_ffi" -version = "0.1.0" -dependencies = [ - "fpp", - "lazy_static", - "rand", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.144" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/presence/fpp/fpp_c_ffi/Cargo.toml b/presence/fpp/fpp_c_ffi/Cargo.toml deleted file mode 100644 index 301a85c3..00000000 --- a/presence/fpp/fpp_c_ffi/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "fpp_c_ffi" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -fpp = {path = "../fpp"} -lazy_static = "1.4.0" -rand = "0.8.5" diff --git a/presence/fpp/fpp_c_ffi/include/presence_detector.h b/presence/fpp/fpp_c_ffi/include/presence_detector.h deleted file mode 100644 index 7bc03aa5..00000000 --- a/presence/fpp/fpp_c_ffi/include/presence_detector.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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 PRESENCE_DETECTOR_H_ -#define PRESENCE_DETECTOR_H_ - -#include -#include -#include -#include -#include - -// Represents the confidence levels for a given measurement -enum class MeasurementConfidence { - /// Measurement confidence is low, the default for BLE medium - Low, - /// Measurement confidence is medium - Medium, - /// Measurement confidence is High - High, - /// Measurement confidence is unknown - Unknown, -}; - -/// Data sources that are used to track presence -enum class PresenceDataSource { - /// Data source for proximity estimate is BLE - Ble, - /// Data source for proximity estimate is UWB - Uwb, - /// Data source for proximity estimate is NAN - Nan, - /// Data source for proximity estimate is unknown - Unknown, -}; - -/// Proximity state from device to another in terms of actionability -enum class ProximityState { - /// Unknown proximity state - Unknown, - /// The device is within a tap zone (<0.02m) - Tap, - /// The device is within a reach zone (<0.5m) - Reach, - /// The device is within a short range zone (<1.2m) - ShortRange, - /// The device is within a long range zone (<3.0m) - LongRange, - /// The device is at a far range - Far, -}; - -/// Wraps the handle ID to an underlying PresenceDetector object -struct PresenceDetectorHandle { - uint64_t handle; -}; - -/// Enum representing an optional tx power value -struct MaybeTxPower { - enum class Tag { - /// Valid TX power with associated data value - Valid, - /// Absent Tx Power - Invalid, - }; - - struct Valid_Body { - int32_t _0; - }; - - Tag tag; - union { - Valid_Body valid; - }; -}; - -/// A PII-stripped subset of Bluetooth scan result -struct BleScanResult { - /// Device ID of the nearby device - uint64_t device_id; - /// Transmitting power of signal - MaybeTxPower tx_power; - /// RSSI value - int32_t rssi; - /// Time scan result was obtained - uint64_t elapsed_real_time_millis; -}; - -/// Describes the most accurate and recent measurement for a given device -struct ProximityEstimate { - /// Device ID of the nearby device - uint64_t device_id; - /// Distance to the nearby device in meters - double distance_meters; - /// Measurement confidence of the estimate - MeasurementConfidence distance_confidence; - /// The time the proximity estimate was obtained - uint64_t elapsed_real_time_millis; - /// Proximity state zone of the nearby device - ProximityState proximity_state; - /// Medium through which the proximity estimate was computed - PresenceDataSource source; -}; - -extern "C" { - -/// Creates a new presence detector object and returns the handle for the new -/// object -PresenceDetectorHandle presence_detector_create(); - -/// Updates PresenceDetector with a new scan result and returns an error code -/// if unsuccessful -/// -/// # Safety -/// -/// Ensure that the output parameter refers to an initialized instance -int32_t update_ble_scan_result(PresenceDetectorHandle presence_detector_handle, - BleScanResult ble_scan_result, - ProximityEstimate *proximity_estimate); - -/// Gets the current proximity estimate for a given device ID -/// -/// # Safety -/// -/// Ensure that the output parameter refers to an initialized instance -int32_t get_proximity_estimate(PresenceDetectorHandle presence_detector_handle, - uint64_t device_id, - ProximityEstimate *proximity_estimate); - -/// De-allocates memory for a presence detector object -int presence_detector_free(PresenceDetectorHandle presence_detector_handle); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // PRESENCE_DETECTOR_H_ diff --git a/presence/fpp/fpp_c_ffi/src/handle_map.rs b/presence/fpp/fpp_c_ffi/src/handle_map.rs deleted file mode 100644 index 0f9566a9..00000000 --- a/presence/fpp/fpp_c_ffi/src/handle_map.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -use core::marker::PhantomData; -use fpp::presence_detector::PresenceDetector; -use lazy_static::lazy_static; -use rand::Rng; -use std::collections::HashMap; -use std::sync::{Mutex, MutexGuard}; - -pub(crate) struct HandleMap { - _marker: PhantomData, - map: HashMap, -} - -impl HandleMap { - pub(crate) fn init() -> Self { - Self { - _marker: Default::default(), - map: HashMap::new(), - } - } - - /// inserts an entry into the map and returns the randomly generated handle to the entry - pub(crate) fn insert(&mut self, data: T) -> u64 { - let mut rng = rand::thread_rng(); - let mut handle: u64 = rng.gen(); - - while self.map.contains_key(&handle) { - handle = rng.gen(); - } - - assert!(self.map.insert(handle, data).is_none()); - handle - } - - /// Removes an entry at a given handle returning an Option of the owned value - pub(crate) fn remove(&mut self, handle: &u64) -> Option { - self.map.remove(handle) - } - - /// Gets a reference to the entry stored at the specified handle - pub(crate) fn get(&mut self, handle: &u64) -> Option<&mut T> { - self.map.get_mut(handle) - } -} - -// Returns a threadsafe instance of the global static hashmap tracking the PresenceDetector handles -pub(crate) fn get_presence_detector_handle_map( -) -> MutexGuard<'static, HandleMap>> { - PRESENCE_DETECTOR_HANDLE_MAP - .lock() - .unwrap_or_else(|err_guard| err_guard.into_inner()) -} - -// Global hashmap to track valid pointers, this is a safety precaution to make sure we are not -// reading from unsafe memory address's passed in by the caller -lazy_static! { - static ref PRESENCE_DETECTOR_HANDLE_MAP: Mutex>> = - Mutex::new(HandleMap::init()); -} diff --git a/presence/fpp/fpp_c_ffi/src/lib.rs b/presence/fpp/fpp_c_ffi/src/lib.rs deleted file mode 100644 index b0c536f7..00000000 --- a/presence/fpp/fpp_c_ffi/src/lib.rs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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. - -#![deny( - missing_docs, - clippy::indexing_slicing, - clippy::unwrap_used, - clippy::panic, - clippy::expect_used -)] - -//! Rust FFI wrapper for PresenceDetector. Can be called from C/C++ clients - -use fpp::fused_presence_utils::*; -use fpp::presence_detector::*; - -use crate::handle_map::get_presence_detector_handle_map; - -mod handle_map; - -/// Wraps the handle ID to an underlying PresenceDetector object -#[repr(C)] -pub struct PresenceDetectorHandle { - handle: u64, -} - -/// Enum class representing possible outputs of proximity data processing call -#[repr(C)] -pub enum ComputationStatus { - /// Returned if the proximity estimate calculation was successful - Success, - /// Returned if there is no computed proximity estimate - NoComputedProximityEstimate, - /// Returned if the handle is invalid - InvalidPresenceDetectorHandleError, - /// Returned if the output parameter is null - NullOutputParameterError, -} - -impl ComputationStatus { - fn to_status_code(&self) -> i32 { - match self { - /// Status codes 100+ are considered errors - Self::Success => 1, - Self::NoComputedProximityEstimate => 2, - Self::InvalidPresenceDetectorHandleError => 101, - Self::NullOutputParameterError => 102, - } - } -} - -/// Creates a new presence detector object and returns the handle for the new -/// object -#[no_mangle] -pub extern "C" fn presence_detector_create() -> PresenceDetectorHandle { - let handle = get_presence_detector_handle_map().insert(Box::new(PresenceDetector::new())); - PresenceDetectorHandle { handle } -} - -/// Updates PresenceDetector with a new scan result and returns an error code if -/// unsuccessful -/// -/// # Safety -/// -/// Ensure that the output parameter refers to an initialized instance -#[no_mangle] -pub unsafe extern "C" fn update_ble_scan_result( - presence_detector_handle: PresenceDetectorHandle, - ble_scan_result: BleScanResult, - proximity_estimate: *mut ProximityEstimate, -) -> i32 { - if let Some(presence_detector) = - get_presence_detector_handle_map().get(&presence_detector_handle.handle) - { - if let Some(current_proximity_estimate) = - presence_detector.on_ble_scan_result(ble_scan_result) - { - if let Some(proximity_estimate) = proximity_estimate.as_mut() { - *proximity_estimate = current_proximity_estimate; - ComputationStatus::Success.to_status_code() - } else { - ComputationStatus::NullOutputParameterError.to_status_code() - } - } else { - ComputationStatus::NoComputedProximityEstimate.to_status_code() - } - } else { - ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() - } -} - -/// Gets the current proximity estimate for a given device ID -/// -/// # Safety -/// -/// Ensure that the output parameter refers to an initialized instance -#[no_mangle] -pub unsafe extern "C" fn get_proximity_estimate( - presence_detector_handle: PresenceDetectorHandle, - device_id: u64, - proximity_estimate: *mut ProximityEstimate, -) -> i32 { - if let Some(presence_detector) = - get_presence_detector_handle_map().get(&presence_detector_handle.handle) - { - presence_detector.get_proximity_estimate(device_id).map(|current_proximity_estimate| { - if let Some(proximity_estimate) = proximity_estimate.as_mut() { - *proximity_estimate = current_proximity_estimate; - return ComputationStatus::Success.to_status_code(); - } - ComputationStatus::NullOutputParameterError.to_status_code() - }); - } - - ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() -} - -/// De-allocates memory for a presence detector object -#[no_mangle] -pub extern "C" fn presence_detector_free( - presence_detector_handle: PresenceDetectorHandle, -) -> std::os::raw::c_int { - if let Some(presence_detector) = - get_presence_detector_handle_map().remove(&presence_detector_handle.handle) - { - let _ = *presence_detector; - return ComputationStatus::Success.to_status_code(); - } - ComputationStatus::InvalidPresenceDetectorHandleError.to_status_code() -} diff --git a/presence/fpp/fpp_manager.cc b/presence/fpp/fpp_manager.cc deleted file mode 100644 index e7d9efc8..00000000 --- a/presence/fpp/fpp_manager.cc +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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 "presence/fpp/fpp_manager.h" - -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "internal/platform/logging.h" -#include "presence/fpp/fpp_c_ffi/include/presence_detector.h" -#include "presence/implementation/sensor_fusion.h" -#include "presence/presence_zone.h" - -namespace nearby { -namespace presence { - -namespace { -// See -// https://source.corp.google.com/piper///depot/google3/third_party/nearby/presence/fpp/fpp_c_ffi/src/lib.rs;l=49 -// for constants definition -constexpr int kSuccess = 1; -constexpr int kNoComputedProximityEstimate = 2; -constexpr int kInvalidPresenceDetectorHandleError = 101; -constexpr int kNullOutputParameterError = 102; - -// Converts optional tx power to the rust api compatible equivalent -MaybeTxPower ConvertTxPower(std::optional txPower) { - if (txPower.has_value()) { - return {MaybeTxPower::Tag::Valid, {txPower.value()}}; - } - return {MaybeTxPower::Tag::Invalid, {}}; -} - -// Converts FPP ProximityState struct to NP RangeType struct -PresenceZone::DistanceBoundary::RangeType ConvertProximityStateToRangeType( - ProximityState proximity_state) { - switch (proximity_state) { - case ProximityState::Tap: - return PresenceZone::DistanceBoundary::RangeType::kWithinTap; - case ProximityState::Reach: - return PresenceZone::DistanceBoundary::RangeType::kWithinReach; - case ProximityState::ShortRange: - case ProximityState::LongRange: - case ProximityState::Far: - return PresenceZone::DistanceBoundary::RangeType::kFar; - case ProximityState::Unknown: - default: - LOG(WARNING) << "Proximity state is unknown"; - return PresenceZone::DistanceBoundary::RangeType::kRangeUnknown; - } -} -} // namespace - -absl::Status FppManager::UpdateBleScanResult(uint64_t device_id, - std::optional txPower, - int rssi, - uint64_t elapsed_realtime_millis) { - if (zone_transition_callbacks_.empty()) { - return absl::InternalError("No callback registered"); - } - BleScanResult ble_scan_result = {device_id, ConvertTxPower(txPower), rssi, - elapsed_realtime_millis}; - ProximityEstimate default_proximity_estimate = - ProximityEstimate{device_id, - /*distanceMeters=*/0.0, - MeasurementConfidence::Unknown, - /*elapsedRealtime=*/0, - ProximityState::Unknown, - PresenceDataSource::Ble}; - ProximityEstimate old_proximity_estimate = - current_proximity_estimates_.contains(device_id) - ? current_proximity_estimates_[device_id] - : default_proximity_estimate; - ProximityEstimate new_proximity_estimate = default_proximity_estimate; - int status_code = update_ble_scan_result( - presence_detector_handle_, ble_scan_result, &new_proximity_estimate); - if (status_code == kNoComputedProximityEstimate) { - LOG(INFO) << "Insufficient number of scan results available to " - "compute proximity state"; - return absl::OkStatus(); - } - if (status_code == kSuccess) { - current_proximity_estimates_[device_id] = new_proximity_estimate; - CheckPresenceZoneChanged(device_id, old_proximity_estimate, - new_proximity_estimate); - return absl::OkStatus(); - } - LOG(WARNING) - << "Could not successfully update FPP with new scan result: Error code=" - << status_code; - return absl::InternalError(GetStatusStringFromCode(status_code)); -} - -void FppManager::RegisterZoneTransitionListener( - uint64_t callback_id, ZoneTransitionCallback callback) { - zone_transition_callbacks_[callback_id] = std::move(callback); -} - -void FppManager::UnregisterZoneTransitionListener(uint64_t callback_id) { - zone_transition_callbacks_.erase(callback_id); -} - -void FppManager::ResetProximityStateData() { - current_proximity_estimates_.clear(); -} - -std::optional FppManager::GetRangingData(uint64_t device_id) { - return ConvertProximityEstimateToRangingData( - current_proximity_estimates_[device_id]); -} - -// Converts FPP ProximityEstimate struct to NP RangingData struct -RangingData FppManager::ConvertProximityEstimateToRangingData( - ProximityEstimate estimate) { - RangingMeasurement ranging_measurement = { - /*confidenceLevel=*/0.0, static_cast(estimate.distance_meters)}; - RangingPosition ranging_position = { - ranging_measurement, /*azimuth=*/std::nullopt, - /*elevation=*/std::nullopt, estimate.elapsed_real_time_millis}; - ZoneTransition zone_transition = { - ConvertProximityStateToRangeType(estimate.proximity_state), - /*confidenceLevel=*/0.0}; - return {DataSource::kBle, ranging_position, zone_transition, - std::vector()}; -} - -void FppManager::CheckPresenceZoneChanged(uint64_t device_id, - ProximityEstimate old_estimate, - ProximityEstimate new_estimate) { - if (old_estimate.proximity_state != new_estimate.proximity_state) { - LOG(WARNING) << "Updating zone transition callbacks with new zone. Zone=" - << static_cast(new_estimate.proximity_state); - for (auto& pair : zone_transition_callbacks_) { - pair.second.on_proximity_zone_changed( - device_id, - ConvertProximityStateToRangeType(new_estimate.proximity_state)); - } - } -} - -std::string FppManager::GetStatusStringFromCode(int status_code) { - switch (status_code) { - case kInvalidPresenceDetectorHandleError: - return "INVALID_PRESENCE_DETECTOR_HANDLE"; - case kNullOutputParameterError: - return "NULL_OUTPUT_PARAMETER"; - default: - LOG(WARNING) << "Error code is unknown"; - return "UNKNOWN_ERROR"; - } -} - -} // namespace presence -} // namespace nearby diff --git a/presence/fpp/fpp_manager.h b/presence/fpp/fpp_manager.h deleted file mode 100644 index cecdb21e..00000000 --- a/presence/fpp/fpp_manager.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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_PRESENCE_FPP_FPP_MANAGER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_FPP_FPP_MANAGER_H_ - -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/status/status.h" -#include "presence/fpp/fpp_c_ffi/include/presence_detector.h" -#include "presence/implementation/sensor_fusion.h" -#include "presence/presence_zone.h" - -namespace nearby { -namespace presence { - -// Manages fused presence updates and serves as a sync -> async converter class -// between fpp and NP sensor fusion -class FppManager { - public: - using RangeType = PresenceZone::DistanceBoundary::RangeType; - - FppManager() { presence_detector_handle_ = presence_detector_create(); } - ~FppManager() { presence_detector_free(presence_detector_handle_); } - - /** Updates FPP with new BLE scan results. Returns status code */ - absl::Status UpdateBleScanResult(uint64_t device_id, - std::optional txPower, int rssi, - uint64_t elapsed_realtime_millis); - /** - * Adds callback for updates of proximity zone transitions. - */ - void RegisterZoneTransitionListener(uint64_t callback_id, - ZoneTransitionCallback callback); - - /** - * Unregister callback for updates of proximity zone transitions. - */ - void UnregisterZoneTransitionListener(uint64_t callback_id); - - /** - * Clears all proximity state data - */ - void ResetProximityStateData(); - - /* - * Converts ProximityEstimate to a NP compatible struct - */ - RangingData ConvertProximityEstimateToRangingData(ProximityEstimate estimate); - - /** - * Gets the most recent ranging data for a given device - */ - std::optional GetRangingData(uint64_t device_id); - - /* - * Converts a status code to a string representation - */ - std::string GetStatusStringFromCode(int status_code); - - private: - void CheckPresenceZoneChanged(uint64_t device_id, - ProximityEstimate old_estimate, - ProximityEstimate new_estimate); - absl::flat_hash_map current_proximity_estimates_; - absl::flat_hash_map - zone_transition_callbacks_; - PresenceDetectorHandle presence_detector_handle_; -}; -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_FPP_FPP_MANAGER_H_ diff --git a/presence/fpp/fpp_manager_test.cc b/presence/fpp/fpp_manager_test.cc deleted file mode 100644 index 6911e06f..00000000 --- a/presence/fpp/fpp_manager_test.cc +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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 "presence/fpp/fpp_manager.h" - -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "presence/implementation/sensor_fusion.h" - -namespace nearby { -namespace presence { -namespace { -constexpr uint64_t kDeviceId = 1234; -constexpr int kReachRssi = -40; -constexpr int kShortRangeRssi = -60; -constexpr int kCallbackId = 12345; - -TEST(FppManager, UpdateBleScanResultSuccess) { - FppManager manager; - bool callback_called = false; - manager.RegisterZoneTransitionListener( - kCallbackId, - {.on_proximity_zone_changed = - [&callback_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }}); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/0)); - // State is only computed after second consecutive scan is fulfilled - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/2000)); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinReach); - EXPECT_TRUE(callback_called); -} - -TEST(FppManager, ZoneTransitionDetected) { - FppManager manager; - bool callback_called = false; - manager.RegisterZoneTransitionListener( - kCallbackId, - {.on_proximity_zone_changed = - [&callback_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }}); - // ProximityEstimate is only computed after consecutive scans is fulfilled - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/2000)); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinReach); - EXPECT_TRUE(callback_called); - callback_called = false; - - // Update with new zone - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinReach); - EXPECT_FALSE(callback_called); - // Update with consecutive scan of new zone - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kFar); - EXPECT_TRUE(callback_called); -} - -TEST(FppManager, ConvertProximityEstimateToRangingData) { - FppManager manager; - ProximityEstimate proximity_estimate = - ProximityEstimate{kDeviceId, - 0.1, - MeasurementConfidence::Low, - 0, - ProximityState::Reach, - PresenceDataSource::Ble}; - RangingData rangingData = - manager.ConvertProximityEstimateToRangingData(proximity_estimate); - EXPECT_EQ(rangingData.data_source, DataSource::kBle); - EXPECT_EQ(rangingData.position.distance.value, 0.1f); - EXPECT_EQ(rangingData.zone_transition->confidence_level, 0.0f); - EXPECT_EQ(rangingData.zone_transition->distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinReach); - ProximityEstimate unknown_proximity_estimate = - ProximityEstimate{kDeviceId, - 0.0, - MeasurementConfidence::Low, - 0, - ProximityState::Unknown, - PresenceDataSource::Ble}; - RangingData unknown_rangingData = - manager.ConvertProximityEstimateToRangingData(unknown_proximity_estimate); - EXPECT_EQ(unknown_rangingData.zone_transition->distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kRangeUnknown); - ProximityEstimate tap_proximity_estimate = - ProximityEstimate{kDeviceId, - 0.03, - MeasurementConfidence::Low, - 0, - ProximityState::Tap, - PresenceDataSource::Ble}; - RangingData tap_rangingData = - manager.ConvertProximityEstimateToRangingData(tap_proximity_estimate); - EXPECT_EQ(tap_rangingData.zone_transition->distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinTap); -} - -TEST(FppManager, UpdateBleScanResultWithTxPowerSuccess) { - FppManager manager; - bool callback_called = false; - manager.RegisterZoneTransitionListener( - kCallbackId, - {.on_proximity_zone_changed = - [&callback_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }}); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/20, kReachRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/20, kReachRssi, - /*elapsed_real_time_millis=*/2000)); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinTap); - EXPECT_TRUE(callback_called); -} - -TEST(FppManager, UnregisterZoneTransitionListener) { - FppManager manager; - bool callback_called = false; - manager.RegisterZoneTransitionListener( - kCallbackId, - {.on_proximity_zone_changed = - [&callback_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }}); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/2000)); - EXPECT_TRUE(callback_called); - callback_called = false; - - // Unregister listener and update with new zone - manager.UnregisterZoneTransitionListener(kCallbackId); - EXPECT_EQ(manager - .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0) - .code(), - absl::StatusCode::kInternal); - EXPECT_EQ(manager - .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kShortRangeRssi, - /*elapsed_real_time_millis=*/0) - .code(), - absl::StatusCode::kInternal); - EXPECT_FALSE(callback_called); -} - -TEST(FppManager, ResetProximityStateData) { - FppManager manager; - bool callback_called = false; - manager.RegisterZoneTransitionListener( - kCallbackId, - {.on_proximity_zone_changed = - [&callback_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - callback_called = true; - }}); - ASSERT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/0)); - // State is only computed after second consecutive scan is fulfilled - ASSERT_OK(manager.UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, - kReachRssi, - /*elapsed_real_time_millis=*/2000)); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinReach); - EXPECT_TRUE(callback_called); - - // Reset proximity state data - manager.ResetProximityStateData(); - EXPECT_EQ(manager.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kRangeUnknown); -} - -TEST(FppManager, GetStatusStringFromCode) { - FppManager manager; - EXPECT_EQ(manager.GetStatusStringFromCode(101), - "INVALID_PRESENCE_DETECTOR_HANDLE"); - EXPECT_EQ(manager.GetStatusStringFromCode(102), "NULL_OUTPUT_PARAMETER"); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/fpp/sensor_fusion_impl.cc b/presence/fpp/sensor_fusion_impl.cc deleted file mode 100644 index 2bda18b5..00000000 --- a/presence/fpp/sensor_fusion_impl.cc +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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 "presence/fpp/sensor_fusion_impl.h" - -#include -#include -#include - -#include "absl/status/status.h" -#include "presence/fpp/fpp_manager.h" - -namespace nearby { -namespace presence { -std::vector SensorFusionImpl::GetDataSources( - uint64_t elapsed_realtime_millis, - const std::vector& available_sources) { - // TODO(b/264547688) - Implement - return std::vector(); -} -absl::Status SensorFusionImpl::UpdateBleScanResult( - uint64_t device_id, std::optional txPower, int rssi, - uint64_t elapsed_realtime_millis) { - return fpp_manager_.UpdateBleScanResult(device_id, txPower, rssi, - elapsed_realtime_millis); -} -void SensorFusionImpl::UpdateUwbRangingResult(uint64_t device_id, - RangingPosition position) { - // TODO(b/264547688) - Implement -} - -void SensorFusionImpl::RequestZoneTransitionUpdates( - ZoneTransitionCallback callback) { - int callback_id = ++id_generator_; - callback.on_callback_id_generated(callback_id); - fpp_manager_.RegisterZoneTransitionListener(callback_id, std::move(callback)); -} - -void SensorFusionImpl::RequestDeviceMotionUpdates( - SensorFusion::DeviceMotionCallback callback) { - // TODO(b/264547688) - Implement -} -void SensorFusionImpl::RemoveDeviceMotionUpdates( - SensorFusion::DeviceMotionCallback callback) { - // TODO(b/264547688) - Implement -} - -void SensorFusionImpl::RemoveZoneTransitionUpdates(uint64_t callback_id) { - fpp_manager_.UnregisterZoneTransitionListener(callback_id); -} - -std::optional SensorFusionImpl::GetRangingData( - uint64_t device_id) { - return fpp_manager_.GetRangingData(device_id); -} -} // namespace presence -} // namespace nearby diff --git a/presence/fpp/sensor_fusion_impl.h b/presence/fpp/sensor_fusion_impl.h deleted file mode 100644 index ac37b6a8..00000000 --- a/presence/fpp/sensor_fusion_impl.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ - -#include -#include - -#include "presence/fpp/fpp_manager.h" -#include "presence/implementation/sensor_fusion.h" - -namespace nearby { -namespace presence { - -class SensorFusionImpl : public SensorFusion { - public: - ~SensorFusionImpl() = default; - std::vector GetDataSources( - uint64_t elapsed_realtime_millis, - const std::vector& available_sources) override; - absl::Status UpdateBleScanResult(uint64_t device_id, - std::optional txPower, int rssi, - uint64_t elapsed_realtime_millis) override; - void UpdateUwbRangingResult(uint64_t device_id, - RangingPosition position) override; - void RequestZoneTransitionUpdates(ZoneTransitionCallback callback) override; - void RemoveZoneTransitionUpdates(uint64_t callback_id) override; - void RequestDeviceMotionUpdates(DeviceMotionCallback callback) override; - void RemoveDeviceMotionUpdates(DeviceMotionCallback callback) override; - std::optional GetRangingData(uint64_t device_id) override; - - private: - FppManager fpp_manager_; - int id_generator_ = 0; -}; -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_FPP_SENSOR_FUSION_IMPL_H_ diff --git a/presence/fpp/sensor_fusion_test.cc b/presence/fpp/sensor_fusion_test.cc deleted file mode 100644 index aee34d7b..00000000 --- a/presence/fpp/sensor_fusion_test.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 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. -// You may obtain a copy of the License at -// -// http://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 -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "presence/fpp/sensor_fusion_impl.h" - -namespace nearby { -namespace presence { -namespace { -constexpr uint64_t kDeviceId = 1234; -constexpr int kReachRssi = -40; - -TEST(SensorFusion, RequestZoneTransitionUpdatesSuccess) { - SensorFusionImpl sensor_fusion_impl; - bool callback_called = false; - bool callback2_called = false; - sensor_fusion_impl.RequestZoneTransitionUpdates( - {.on_callback_id_generated = [&callback_called](uint64_t callback_id) { - callback_called = true; - EXPECT_EQ(callback_id, 1); - }}); - sensor_fusion_impl.RequestZoneTransitionUpdates( - {.on_callback_id_generated = [&callback2_called](uint64_t callback_id2) { - callback2_called = true; - EXPECT_EQ(callback_id2, 2); - }}); - EXPECT_TRUE(callback2_called); -} - -TEST(SensorFusion, RemoveZoneTransitionUpdates) { - SensorFusionImpl sensor_fusion_impl; - bool callback_called = false; - sensor_fusion_impl.RequestZoneTransitionUpdates( - {.on_callback_id_generated = [&callback_called](uint64_t callback_id) { - callback_called = true; - EXPECT_EQ(callback_id, 1); - }}); - sensor_fusion_impl.RemoveZoneTransitionUpdates(1); - EXPECT_EQ( - sensor_fusion_impl - .UpdateBleScanResult(kDeviceId, /*txPower=*/std::nullopt, kReachRssi, - /*elapsed_real_time_millis=*/0) - .code(), - absl::StatusCode::kInternal); -} - -TEST(SensorFusion, UpdateBleScanResult) { - SensorFusionImpl sensor_fusion_impl; - bool proximity_zone_changed_called = false; - sensor_fusion_impl.RequestZoneTransitionUpdates( - {.on_proximity_zone_changed = - [&proximity_zone_changed_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - proximity_zone_changed_called = true; - }}); - EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( - kDeviceId, /*txPower=*/std::nullopt, kReachRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( - kDeviceId, /*txPower=*/std::nullopt, kReachRssi, - /*elapsed_real_time_millis=*/0)); - - EXPECT_TRUE(proximity_zone_changed_called); -} - -TEST(SensorFusion, GetRangingData) { - SensorFusionImpl sensor_fusion_impl; - bool proximity_zone_changed_called = false; - sensor_fusion_impl.RequestZoneTransitionUpdates( - {.on_proximity_zone_changed = - [&proximity_zone_changed_called]( - uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType range_type) { - proximity_zone_changed_called = true; - }}); - EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( - kDeviceId, /*txPower=*/std::nullopt, kReachRssi, - /*elapsed_real_time_millis=*/0)); - EXPECT_OK(sensor_fusion_impl.UpdateBleScanResult( - kDeviceId, /*txPower=*/std::nullopt, kReachRssi, - /*elapsed_real_time_millis=*/0)); - - EXPECT_TRUE(proximity_zone_changed_called); - - EXPECT_EQ(sensor_fusion_impl.GetRangingData(kDeviceId) - ->zone_transition.value() - .distance_range_type, - PresenceZone::DistanceBoundary::RangeType::kWithinReach); -} -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/action_factory.cc b/presence/implementation/action_factory.cc deleted file mode 100644 index fe4a6e45..00000000 --- a/presence/implementation/action_factory.cc +++ /dev/null @@ -1,106 +0,0 @@ -// 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 "presence/implementation/action_factory.h" - -#include -#include -#include - -#include "internal/platform/logging.h" -#include "presence/data_element.h" -#include "presence/implementation/base_broadcast_request.h" - -namespace nearby { -namespace presence { - -constexpr int kContentTimestampMask = 0x0F; -constexpr int kContentTimestampShift = 28; -constexpr int kEmptyMask = 0; -constexpr int kActionSizeInBits = 32; - -namespace { - -int GetActionMask(ActionBit action) { - int bit = static_cast(action); - if (bit < 0 || bit >= kActionSizeInBits) { - LOG(WARNING) << "Unsupported action " << static_cast(action); - return kEmptyMask; - } - return 1 << (kActionSizeInBits - 1 - bit); -} - -// The reverse of `GetActionMask()` -ActionBit GetActionFromBit(int bit) { - return ActionBit(kActionSizeInBits - 1 - bit); -} - -int GetMask(const DataElement& element) { - int type = element.GetType(); - switch (type) { - case DataElement::kContextTimestampFieldType: { - auto value = element.GetValue(); - if (!value.empty()) { - return (value[0] & kContentTimestampMask) << kContentTimestampShift; - } else { - LOG(WARNING) << "Context timestamp Data Element without value"; - return kEmptyMask; - } - } - case DataElement::kActionFieldType: { - if (element.GetValue().empty()) { - LOG(WARNING) << "Action Data Element without value"; - return kEmptyMask; - } - return GetActionMask(ActionBit(element.GetValue()[0])); - } - } - LOG(WARNING) << "Data Element " << type - << " not supported in base advertisement"; - return kEmptyMask; -} - -} // namespace - -Action ActionFactory::CreateAction( - const std::vector& data_elements) { - Action action = {.action = 0}; - std::for_each(data_elements.begin(), data_elements.end(), - [&](const auto& element) { - int mask = GetMask(element); - action.action |= mask; - }); - return action; -} - -void ActionFactory::DecodeAction(const Action& action, - std::vector& output) { - uint8_t context_timestamp = - (action.action >> kContentTimestampShift) & kContentTimestampMask; - if (context_timestamp) { - output.emplace_back(DataElement::kContextTimestampFieldType, - context_timestamp); - } - constexpr int kFirstUsedBit = - kActionSizeInBits - static_cast(ActionBit::kLastAction); - for (int i = kFirstUsedBit; i < kContentTimestampShift; i++) { - int bit_mask = 1 << i; - if (action.action & bit_mask) { - output.emplace_back(DataElement(GetActionFromBit(i))); - } - } -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/action_factory.h b/presence/implementation/action_factory.h deleted file mode 100644 index b2a43880..00000000 --- a/presence/implementation/action_factory.h +++ /dev/null @@ -1,45 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ACTION_FACTORY_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ACTION_FACTORY_H_ - -#include - -#include "presence/data_element.h" -#include "presence/implementation/base_broadcast_request.h" - -namespace nearby { -namespace presence { - -// Defines the mapping between Data Elements and Actions in the Base NP -// advertisement. -class ActionFactory { - public: - // Returns an Action for Base NP advertisement from a collection of Data - // Elements. Data Elements unsupported in the Base NP advertisement are - // ignored. - static Action CreateAction(const std::vector& data_elements); - - // Decodes a Base NP Action into a list of Data Elements. The Data Elements - // are appended to the `output` list. - // - // DecodeAction is effectively a reverse operation of CreateAction. - static void DecodeAction(const Action& action, - std::vector& output); -}; -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ACTION_FACTORY_H_ diff --git a/presence/implementation/action_factory_test.cc b/presence/implementation/action_factory_test.cc deleted file mode 100644 index 63db1990..00000000 --- a/presence/implementation/action_factory_test.cc +++ /dev/null @@ -1,107 +0,0 @@ -// 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 "presence/implementation/action_factory.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/escaping.h" -#include "presence/data_element.h" -#include "presence/implementation/base_broadcast_request.h" - -namespace nearby { -namespace presence { -namespace { - -using ::testing::ElementsAre; - -constexpr uint32_t kActiveUnlockBitMask = 1 << 23; -constexpr uint32_t kFastPairBitMask = 1 << 17; - -TEST(ActionFactory, CreateActiveUnlockAction) { - std::vector data_elements; - data_elements.emplace_back(ActionBit::kActiveUnlockAction); - - Action action = ActionFactory::CreateAction(data_elements); - - EXPECT_EQ(action.action, kActiveUnlockBitMask); -} - -TEST(ActionFactory, CreateActiveIgnoresUnsupportedActions) { - std::vector data_elements; - data_elements.emplace_back(ActionBit::kActiveUnlockAction); - // The action is 32 bit, so the valid range is [0-31] - data_elements.emplace_back(ActionBit(-1)); - data_elements.emplace_back(ActionBit(32)); - Action action = ActionFactory::CreateAction(data_elements); - - EXPECT_EQ(action.action, kActiveUnlockBitMask); -} - -TEST(ActionFactory, CreateContextTimestamp) { - const std::string kTimestamp = absl::HexStringToBytes("0B"); - - std::vector data_elements; - data_elements.emplace_back(DataElement::kContextTimestampFieldType, - kTimestamp); - - Action action = ActionFactory::CreateAction(data_elements); - - EXPECT_EQ(action.action, 0x0BU << 28); -} - -TEST(ActionFactory, CreateContextTimestampAndFastPair) { - const std::string kTimestamp = absl::HexStringToBytes("0B"); - - std::vector data_elements; - data_elements.emplace_back(DataElement::kContextTimestampFieldType, - kTimestamp); - data_elements.emplace_back(ActionBit::kFastPairSassAction); - - Action action = ActionFactory::CreateAction(data_elements); - - EXPECT_EQ(action.action, (0x0BU << 28) | kFastPairBitMask); -} - -TEST(ActionFactory, DecodeActiveUnlockAction) { - constexpr Action kAction = {.action = kActiveUnlockBitMask}; - std::vector data_elements; - - ActionFactory::DecodeAction(kAction, data_elements); - - EXPECT_THAT( - data_elements, - ElementsAre(DataElement(DataElement(ActionBit::kActiveUnlockAction)))); -} - -TEST(ActionFactory, DecodeContextTimestampAndFastPair) { - constexpr Action kAction = {.action = (0x0BU << 28) | kFastPairBitMask}; - std::vector data_elements; - - ActionFactory::DecodeAction(kAction, data_elements); - - EXPECT_THAT( - data_elements, - ElementsAre(DataElement(DataElement::kContextTimestampFieldType, - absl::HexStringToBytes("0B")), - DataElement(DataElement(ActionBit::kFastPairSassAction)))); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_decoder.h b/presence/implementation/advertisement_decoder.h deleted file mode 100644 index 3c5d444b..00000000 --- a/presence/implementation/advertisement_decoder.h +++ /dev/null @@ -1,59 +0,0 @@ -// 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_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_DECODER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_DECODER_H_ - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" - -namespace nearby { -namespace presence { - -// The structured decoded form of a detected Nearby Presence advertisement -struct Advertisement { - uint8_t version = 0; - std::vector data_elements; - absl::StatusOr public_credential = - absl::NotFoundError(""); - internal::IdentityType identity_type = internal::IDENTITY_TYPE_UNSPECIFIED; - std::string metadata_key; -}; - -// Interface for decoding Nearby Presence advertisements from a payload of raw -// bytes into a structured, decrypted, and decoded format -class AdvertisementDecoder { - public: - // Is needed otherwise deleting an instance via a pointer to a base class - // results in undefined behavior - virtual ~AdvertisementDecoder() = default; - - // Returns the structured and decoded contents of an advertisement given a - // payload of bytes as a string. Returns an error if the advertisement is - // misformatted or if it couldn't be decrypted. - virtual absl::StatusOr DecodeAdvertisement( - absl::string_view advertisement) = 0; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_DECODER_H_ diff --git a/presence/implementation/advertisement_decoder_impl.cc b/presence/implementation/advertisement_decoder_impl.cc deleted file mode 100644 index fec04c85..00000000 --- a/presence/implementation/advertisement_decoder_impl.cc +++ /dev/null @@ -1,287 +0,0 @@ -// 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 "presence/implementation/advertisement_decoder_impl.h" - -#include -#include -#include -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#include "internal/platform/logging.h" -#include "presence/data_element.h" -#include "presence/implementation/action_factory.h" -#include "presence/implementation/advertisement_decoder.h" -#include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/ldt.h" - -namespace nearby { -namespace presence { - -namespace { - -constexpr uint8_t kDataTypeMask = - (1 << DataElement::kDataElementLengthShift) - 1; - -constexpr int kAdvertisementVersion = 0; - -constexpr int kEncryptedIdentityAdditionalLength = - kSaltSize + kBaseMetadataSize; -constexpr int kEddystoneAdditionalLength = 20; - -uint8_t GetDataElementType(uint8_t header) { return header & kDataTypeMask; } - -size_t GetDataElementLength(uint8_t header) { - return header >> DataElement::kDataElementLengthShift; -} - -// Verifies if the DE header describes a valid DE in v0 advertisement. -bool IsDataElementAllowed(uint8_t header) { - uint8_t data_type = GetDataElementType(header); - size_t length = GetDataElementLength(header); - switch (data_type) { - case DataElement::kSaltFieldType: - return length == 2; - case DataElement::kPublicIdentityFieldType: - return length == 0; - case DataElement::kPrivateGroupIdentityFieldType: - case DataElement::kContactsGroupIdentityFieldType: - return length >= 2 && length <= 6; - case DataElement::kTxPowerFieldType: - return length == 1; - case DataElement::kActionFieldType: - return length >= 1 && length <= 3; - case DataElement::kModelIdFieldType: - return length == 3; - case DataElement::kEddystoneIdFieldType: - return length == 0; - case DataElement::kAccountKeyDataFieldType: - return length <= 12; - case DataElement::kConnectionStatusFieldType: - return length <= 3; - case DataElement::kBatteryFieldType: - return length <= 3; - default: - return false; - } -} - -bool IsEncryptedIdentity(int data_type) { - return data_type == DataElement::kPrivateGroupIdentityFieldType || - data_type == DataElement::kContactsGroupIdentityFieldType; -} - -bool IsIdentity(int data_type) { - return data_type == DataElement::kPublicIdentityFieldType || - IsEncryptedIdentity(data_type); -} - -internal::IdentityType GetIdentityType(int data_type) { - switch (data_type) { - case DataElement::kPrivateGroupIdentityFieldType: - return internal::IDENTITY_TYPE_PRIVATE_GROUP; - case DataElement::kContactsGroupIdentityFieldType: - return internal::IDENTITY_TYPE_CONTACTS_GROUP; - case DataElement::kPublicIdentityFieldType: - return internal::IDENTITY_TYPE_PUBLIC; - } - return internal::IDENTITY_TYPE_UNSPECIFIED; -} - -// Returns the real length of a DE in v0 advertisement, which may be larger than -// the value in the header. -size_t GetDataElementTrueLength(uint8_t header) { - uint8_t data_type = GetDataElementType(header); - size_t length = GetDataElementLength(header); - if (IsEncryptedIdentity(data_type)) { - // The length of an encrypted DE is 16 bytes of overhead (salt + metadata - // key) + the actual payload, which is too long to fit in the 4-bit DE - // length field. - length += kEncryptedIdentityAdditionalLength; - } else if (data_type == DataElement::kEddystoneIdFieldType) { - // Length in the header is set to EID length minus 20, because EID is longer - // than 15 (the maximum length that can be stored in 4 bits. - length += kEddystoneAdditionalLength; - } - return length; -} - -absl::StatusOr ParseDataElement(const absl::string_view input, - size_t& index) { - if (index >= input.size()) { - return absl::OutOfRangeError(absl::StrFormat( - "Data element (%s) is %d bytes long. Expected more than %d", - absl::BytesToHexString(input), input.size(), index)); - } - uint8_t header = input[index]; - if (!IsDataElementAllowed(header)) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported Data Element 0x%x", header)); - } - uint8_t data_type = GetDataElementType(header); - size_t length = GetDataElementTrueLength(header); - ++index; - size_t start = index; - index += length; - if (index > input.size()) { - return absl::OutOfRangeError(absl::StrFormat( - "Data element (%s) is %d bytes long. Expected at least %d", - absl::BytesToHexString(input), input.size(), index)); - } - VLOG(1) << "Type: " << static_cast(data_type) - << " length: " << static_cast(length) - << " DE: " << absl::BytesToHexString(input.substr(start, length)); - return DataElement(data_type, input.substr(start, length)); -} -} // namespace - -void DecodeBaseAction(absl::string_view serialized_action, - Advertisement& decoded_advertisement) { - if (serialized_action.empty() || serialized_action.size() > 3) { - LOG(WARNING) << "Base NP action \'" - << absl::BytesToHexString(serialized_action) - << "\' has wrong length " << serialized_action.size() - << " , expected size in range [1 - 3]"; - return; - } - // Action, 0-2 bytes in Big Endian order. - Action action = {.action = 0}; - for (int i = 0; i < serialized_action.size(); ++i) { - int offset = (sizeof(uint32_t) - 1 - i) * 8; - action.action |= serialized_action[i] << offset; - } - - ActionFactory::DecodeAction(action, decoded_advertisement.data_elements); -} - -absl::StatusOr DecryptLdt( - const std::vector& credentials, - absl::string_view salt, absl::string_view encrypted_contents, - Advertisement& decoded_advertisement) { - if (credentials.empty()) { - return absl::UnavailableError("No credentials"); - } - for (const auto& credential : credentials) { - absl::StatusOr encryptor = LdtEncryptor::Create( - credential.key_seed(), credential.metadata_encryption_key_tag_v0()); - if (encryptor.ok()) { - absl::StatusOr result = - encryptor->DecryptAndVerify(encrypted_contents, salt); - if (result.ok() && result->size() > kBaseMetadataSize) { - decoded_advertisement.public_credential = credential; - decoded_advertisement.metadata_key = - result->substr(0, kBaseMetadataSize); - return result->substr(kBaseMetadataSize); - } - } - } - return absl::UnavailableError( - "Couldn't decrypt the message with any credentials"); -} - -absl::Status DecryptDataElements( - const std::vector& credentials, - const DataElement& elem, Advertisement& decoded_advertisement) { - if (elem.GetValue().size() <= kEncryptedIdentityAdditionalLength) { - return absl::OutOfRangeError(absl::StrFormat( - "Encrypted identity data element is too short - %d bytes", - elem.GetValue().size())); - } - absl::string_view salt = elem.GetValue().substr(0, kSaltSize); - decoded_advertisement.data_elements.emplace_back(DataElement::kSaltFieldType, - salt); - absl::string_view encrypted = elem.GetValue().substr(kSaltSize); - absl::StatusOr decrypted = - DecryptLdt(credentials, salt, encrypted, decoded_advertisement); - if (!decrypted.ok()) { - LOG(WARNING) << "Failed to decrypt advertisement, status: " - << decrypted.status(); - return decrypted.status(); - } - size_t index = 0; - while (index < decrypted->size()) { - absl::StatusOr internal_elem = - ParseDataElement(*decrypted, index); - if (!internal_elem.ok()) { - LOG(WARNING) << "Failed to read data element, status: " - << internal_elem.status(); - return internal_elem.status(); - } - if (internal_elem->GetType() == DataElement::kActionFieldType) { - DecodeBaseAction(internal_elem->GetValue(), decoded_advertisement); - } else { - decoded_advertisement.data_elements.push_back(*std::move(internal_elem)); - } - } - return absl::OkStatus(); -} - -absl::StatusOr AdvertisementDecoderImpl::DecodeAdvertisement( - absl::string_view advertisement) { - Advertisement decoded_advertisement = Advertisement{}; - std::vector result; - LOG(INFO) << "Advertisement: " << absl::BytesToHexString(advertisement); - if (advertisement.empty()) { - return absl::OutOfRangeError("Empty advertisement"); - } - uint8_t version = advertisement[0]; - VLOG(1) << "Version: " << version; - if (version != kAdvertisementVersion) { - return absl::UnimplementedError(absl::StrFormat( - "Advertisement version (%d) is not supported", version)); - } - decoded_advertisement.version = version; - size_t index = 1; - absl::StatusOr decrypted; - while (index < advertisement.size()) { - absl::StatusOr elem = ParseDataElement(advertisement, index); - if (!elem.ok()) { - LOG(WARNING) << "Failed to read data element, status: " << elem.status(); - return elem.status(); - } - if (IsIdentity(elem->GetType())) { - decoded_advertisement.identity_type = GetIdentityType(elem->GetType()); - } - if (IsEncryptedIdentity(elem->GetType())) { - if (credentials_map_ == nullptr) { - return absl::FailedPreconditionError("Missing credentials"); - } - auto identity_type_specific_creds = - (*credentials_map_)[decoded_advertisement.identity_type]; - absl::Status status = DecryptDataElements(identity_type_specific_creds, - *elem, decoded_advertisement); - if (!status.ok()) { - return status; - } - } else { - if (elem->GetType() == DataElement::kActionFieldType) { - DecodeBaseAction(elem->GetValue(), decoded_advertisement); - } else { - decoded_advertisement.data_elements.push_back(*std::move(elem)); - } - } - } - - return std::move(decoded_advertisement); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_decoder_impl.h b/presence/implementation/advertisement_decoder_impl.h deleted file mode 100644 index c3e7e592..00000000 --- a/presence/implementation/advertisement_decoder_impl.h +++ /dev/null @@ -1,51 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_DECODER_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_DECODER_IMPL_H_ - -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "presence/implementation/advertisement_decoder.h" - -namespace nearby { -namespace presence { - -// Implements the C++ backed parsing and decrypting of advertisement bytes -class AdvertisementDecoderImpl : public AdvertisementDecoder { - public: - AdvertisementDecoderImpl() = default; - explicit AdvertisementDecoderImpl( - absl::flat_hash_map>* - credentials_map) - : credentials_map_(credentials_map) {} - - absl::StatusOr DecodeAdvertisement( - absl::string_view advertisement) override; - - private: - absl::flat_hash_map>* - credentials_map_ = nullptr; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_DECODER_IMPL_H_ diff --git a/presence/implementation/advertisement_decoder_new_format_test.cc b/presence/implementation/advertisement_decoder_new_format_test.cc deleted file mode 100644 index ef78c828..00000000 --- a/presence/implementation/advertisement_decoder_new_format_test.cc +++ /dev/null @@ -1,156 +0,0 @@ -// 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 -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/container/flat_hash_map.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/implementation/advertisement_decoder.h" -#include "presence/implementation/advertisement_decoder_rust_impl.h" - -namespace nearby { -namespace presence { -namespace { - -using ::nearby::ByteArray; // NOLINT -using ::nearby::internal::IdentityType; // NOLINT -using ::nearby::internal::SharedCredential; // NOLINT -using ::testing::ElementsAre; -using ::testing::status::StatusIs; - -TEST(AdvertisementDecoderImpl, DecodePublicAdvertisement) { - std::string V0AdvPlaintextBytes = - "00" // Adv Header V0 unencrypted - "1503"; // length 1 Tx Power DE value 3 - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(); - - absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes(V0AdvPlaintextBytes)); - ASSERT_OK(result); - EXPECT_EQ(result->identity_type, IdentityType::IDENTITY_TYPE_PUBLIC); - EXPECT_EQ(result->version, 0); - EXPECT_THAT(result->data_elements, - ElementsAre(DataElement(DataElement::kTxPowerFieldType, - absl::HexStringToBytes("03")))); -} - -TEST(AdvertisementDecoderImpl, DecodePublicAdvertisementMultiDe) { - std::string V0AdvPlaintextMultiDeBytes = - "00" // Adv Header V0 unencrypted - "1505" // length 1 Tx Power DE value 5 - "260040"; // length 2 actions de with NearbyShare bit set - - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(); - absl::StatusOr result = decoder.DecodeAdvertisement( - absl::HexStringToBytes(V0AdvPlaintextMultiDeBytes)); - ASSERT_OK(result); - EXPECT_EQ(result->identity_type, IdentityType::IDENTITY_TYPE_PUBLIC); - EXPECT_EQ(result->version, 0); - EXPECT_THAT(result->data_elements, - ElementsAre(DataElement(DataElement::kTxPowerFieldType, - absl::HexStringToBytes("05")), - DataElement(ActionBit::kNearbyShareAction))); -} - -// V0 encrypted advertisement data - ripped out of np_adv/tests/examples_v0.rs -TEST(AdvertisementDecoderImpl, DecodeEncryptedAdvertisement) { - std::string V0AdvEncryptedBytes = "042222D82212EF16DBF872F2A3A7C0FA5248EC"; - ByteArray seed({ - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - }); - ByteArray known_mac({0x09, 0xFE, 0x9E, 0x81, 0xB7, 0x3E, 0x5E, 0xCC, - 0x76, 0x59, 0x57, 0x71, 0xE0, 0x1F, 0xFB, 0x34, - 0x38, 0xE7, 0x5F, 0x24, 0xA7, 0x69, 0x56, 0xA0, - 0xB8, 0xEA, 0x67, 0xD1, 0x1C, 0x3E, 0x36, 0xFD}); - SharedCredential public_credential; - public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_tag_v0( - known_mac.AsStringView()); - public_credential.set_id(12345678); - absl::flat_hash_map> - credentials; - credentials[IdentityType::IDENTITY_TYPE_PRIVATE_GROUP].push_back( - public_credential); - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(&credentials); - - absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes(V0AdvEncryptedBytes)); - ASSERT_OK(result); - EXPECT_EQ(result->public_credential.value().id(), public_credential.id()); - EXPECT_EQ(result->public_credential.value().key_seed(), - public_credential.key_seed()); - EXPECT_EQ(result->identity_type, IdentityType::IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_EQ(result->version, 0); - EXPECT_THAT(result->data_elements, - ElementsAre(DataElement(DataElement::kSaltFieldType, - absl::HexStringToBytes("2222")), - DataElement(DataElement::kTxPowerFieldType, - absl::HexStringToBytes("03")))); -} - -TEST(AdvertisementDecoderImpl, DecodeEncryptedAdvertisementNoCreds) { - std::string V0AdvEncryptedBytes = "042222D82212EF16DBF872F2A3A7C0FA5248EC"; - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(); - - absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes(V0AdvEncryptedBytes)); - EXPECT_THAT(result, StatusIs(absl::StatusCode::kUnavailable)); -} - -TEST(AdvertisementDecoderImpl, V1AdvCurrentlyUnsupported) { - std::string V1Adv = - "20" // Version header V1 - "00" // format - "02" // section len - "1503"; // Tx power value 3 - - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(); - absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes(V1Adv)); - EXPECT_THAT(result, StatusIs(absl::StatusCode::kUnimplemented)); -} - -TEST(AdvertisementDecoderImpl, V0InvalidEmptyAdv) { - std::string V1Adv = "00"; - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(); - absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes(V1Adv)); - EXPECT_THAT(result, StatusIs(absl::StatusCode::kInvalidArgument)); -} - -TEST(AdvertisementDecoderImpl, V0InvalidAdvContents) { - std::string invalid_v0_adv = - "00" // Adv Header V0 unencrypted - "3503"; // length 3 Tx Power DE with only 1 byte - AdvertisementDecoderImpl decoder = AdvertisementDecoderImpl(); - absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes(invalid_v0_adv)); - EXPECT_THAT(result, StatusIs(absl::StatusCode::kInvalidArgument)); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_decoder_rust_impl.cc b/presence/implementation/advertisement_decoder_rust_impl.cc deleted file mode 100644 index 9ff10320..00000000 --- a/presence/implementation/advertisement_decoder_rust_impl.cc +++ /dev/null @@ -1,241 +0,0 @@ -// 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 "presence/implementation/advertisement_decoder_rust_impl.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#include "np_cpp_ffi_types.h" -#include "nearby_protocol.h" -#include "internal/platform/logging.h" -#include "presence/data_element.h" -#include "presence/implementation/advertisement_decoder.h" - -namespace nearby { -namespace presence { -namespace { - -absl::StatusOr<::nearby_protocol::ActionType> MapAction( - const ActionBit action) { - return ::nearby_protocol::ActionType::TryBuildFromU8( - static_cast(action)); -} - -void AddActionsToAdvertisement(const nearby_protocol::V0Actions& parsed_actions, - Advertisement& advertisement) { - for (const auto action : kAllActionBits) { - auto action_type = MapAction(action); - if (!action_type.ok()) { - LOG(WARNING) << "Advertisement contains an unsupported action bit: " - << (int)action; - continue; - } - if (parsed_actions.HasAction(*action_type)) { - advertisement.data_elements.push_back(DataElement(action)); - } - } -} - -void ProcessDataElement(const nearby_protocol::V0DataElement& data_element, - Advertisement& advertisement) { - switch (data_element.GetKind()) { - case nearby_protocol::V0DataElementKind::TxPower: { - advertisement.data_elements.push_back(DataElement( - DataElement::kTxPowerFieldType, data_element.AsTxPower().GetAsI8())); - return; - } - case nearby_protocol::V0DataElementKind::Actions: { - AddActionsToAdvertisement(data_element.AsActions(), advertisement); - return; - } - default: { - LOG(WARNING) << "Unsupported data element type: " - << (int)data_element.GetKind(); - } - } -} - -internal::IdentityType GetIdentityType( - nearby_protocol::DeserializedV0IdentityKind identity) { - switch (identity) { - case np_ffi::internal::DeserializedV0IdentityKind::Plaintext: - return internal::IdentityType::IDENTITY_TYPE_PUBLIC; - case np_ffi::internal::DeserializedV0IdentityKind::Decrypted: - return internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; - } -} - -absl::StatusOr<::nearby::internal::SharedCredential> FindById( - std::vector<::nearby::internal::SharedCredential> private_credentials, - uint64_t id) { - auto cred = - std::find_if(private_credentials.begin(), private_credentials.end(), - [&id](const auto& x) { return x.id() == id; }); - if (cred == private_credentials.end()) { - return absl::NotFoundError("No credential found with id: " + - std::to_string(id)); - } - return *cred; -} - -absl::Status ProcessLegibleV0Adv( - nearby_protocol::LegibleDeserializedV0Advertisement legible_adv, - std::vector<::nearby::internal::SharedCredential> private_credentials, - Advertisement& advertisement) { - advertisement.identity_type = GetIdentityType(legible_adv.GetIdentityKind()); - - auto num_des = legible_adv.GetNumberOfDataElements(); - auto payload = legible_adv.IntoPayload(); - - // TODO(b/333126765): salt isn't a DE, we should restructure the - // Advertisement struct to reflect this - if (advertisement.identity_type == - internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP) { - auto cred_details = payload.TryGetIdentityDetails(); - if (!cred_details.ok()) { - return cred_details.status(); - } - - advertisement.public_credential = - FindById(private_credentials, cred_details->cred_id); - - // TODO(b/333126765): update salt to use unsigned char * to remove cast - std::string salt(reinterpret_cast(cred_details->salt), 2); - advertisement.data_elements.push_back(DataElement(0x00, salt)); - - std::string metadata_key( - reinterpret_cast(cred_details->identity_token), 14); - advertisement.metadata_key = std::move(metadata_key); - } - - for (int i = 0; i < num_des; i++) { - auto de_result = payload.TryGetDataElement(i); - if (!de_result.ok()) { - return de_result.status(); - } - ProcessDataElement(*de_result, advertisement); - } - return absl::OkStatus(); -} - -absl::Status ProcessV0Advertisement( - nearby_protocol::DeserializedV0Advertisement result, - std::vector<::nearby::internal::SharedCredential> private_credentials, - Advertisement& adv) { - switch (result.GetKind()) { - case nearby_protocol::DeserializedV0AdvertisementKind::Legible: - return ProcessLegibleV0Adv(result.IntoLegible(), private_credentials, - adv); - break; - case nearby_protocol::DeserializedV0AdvertisementKind:: - NoMatchingCredentials: { - return absl::UnavailableError( - "Couldn't decrypt the message with any credentials"); - } - } -} - -} // namespace - -absl::StatusOr AdvertisementDecoderImpl::DecodeAdvertisement( - absl::string_view advertisement) { - auto byte_buffer = nearby_protocol::ByteBuffer< - nearby_protocol::MAX_ADV_PAYLOAD_SIZE>::TryFromString(advertisement); - if (!byte_buffer.ok()) { - return absl::InvalidArgumentError("Invalid length advertisement"); - } - - Advertisement decoded_advertisement; - const nearby_protocol::RawAdvertisementPayload payload(byte_buffer.value()); - auto deserialize_result = - nearby_protocol::Deserializer::DeserializeAdvertisement(payload, - cred_book_); - - switch (deserialize_result.GetKind()) { - case np_ffi::internal::DeserializeAdvertisementResultKind::Error: { - return absl::InvalidArgumentError("Invalid advertisement format"); - } - case np_ffi::internal::DeserializeAdvertisementResultKind::V1: { - return absl::UnimplementedError( - absl::StrFormat("V1 Advertisement format is not supported")); - } - case np_ffi::internal::DeserializeAdvertisementResultKind::V0: { - decoded_advertisement.version = 0; - auto result = - ProcessV0Advertisement(deserialize_result.IntoV0(), - private_credentials_, decoded_advertisement); - if (!result.ok()) { - return result; - } - break; - } - } - - return decoded_advertisement; -} - -nearby_protocol::CredentialBook -AdvertisementDecoderImpl::InitializeCredentialBook( - absl::flat_hash_map>* - credentials_map) { - if (credentials_map == nullptr) { - nearby_protocol::CredentialSlab slab; - nearby_protocol::CredentialBook cred_book(slab); - return cred_book; - } - - nearby_protocol::CredentialSlab slab; - for (const auto& credential : (*credentials_map) - [internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP]) { - // Make sure the vector is not empty, as this is a prerequisite of the Rust - // code we call into. - std::vector metadata_bytes(1); - if (!credential.encrypted_metadata_bytes_v0().empty()) { - metadata_bytes = - std::vector(credential.encrypted_metadata_bytes_v0().begin(), - credential.encrypted_metadata_bytes_v0().end()); - } - nearby_protocol::MatchedCredentialData matched_cred(credential.id(), - metadata_bytes); - - auto key_seed = credential.key_seed(); - std::array key_seed_array; - std::copy(key_seed.begin(), key_seed.end(), key_seed_array.data()); - - auto tag = credential.metadata_encryption_key_tag_v0(); - std::array tag_array; - std::copy(tag.begin(), tag.end(), tag_array.data()); - - auto matchable_credential = nearby_protocol::V0MatchableCredential( - key_seed_array, tag_array, matched_cred); - slab.AddV0Credential(matchable_credential); - } - nearby_protocol::CredentialBook cred_book(slab); - return cred_book; -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_decoder_rust_impl.h b/presence/implementation/advertisement_decoder_rust_impl.h deleted file mode 100644 index b2444e7d..00000000 --- a/presence/implementation/advertisement_decoder_rust_impl.h +++ /dev/null @@ -1,61 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_DECODER_RUST_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_DECODER_RUST_IMPL_H_ - -#include - -#include "absl/container/flat_hash_map.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "nearby_protocol.h" -#include "presence/implementation/advertisement_decoder.h" - -namespace nearby { -namespace presence { - -// Implements the Rust backed parsing and decrypting of advertisement bytes -class AdvertisementDecoderImpl : public AdvertisementDecoder { - public: - AdvertisementDecoderImpl() - : cred_book_(InitializeCredentialBook(nullptr)), - private_credentials_( - std::vector<::nearby::internal::SharedCredential>()) {} - - explicit AdvertisementDecoderImpl( - absl::flat_hash_map>* - credentials_map) - : cred_book_(InitializeCredentialBook(credentials_map)), - private_credentials_( - (*credentials_map) - [internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP]) {} - - absl::StatusOr DecodeAdvertisement( - absl::string_view advertisement) override; - - private: - nearby_protocol::CredentialBook InitializeCredentialBook( - absl::flat_hash_map>* - credentials_map); - nearby_protocol::CredentialBook cred_book_; - std::vector<::nearby::internal::SharedCredential> private_credentials_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_DECODER_IMPL_H_ diff --git a/presence/implementation/advertisement_decoder_test.cc b/presence/implementation/advertisement_decoder_test.cc deleted file mode 100644 index 5b2a70d4..00000000 --- a/presence/implementation/advertisement_decoder_test.cc +++ /dev/null @@ -1,226 +0,0 @@ -// 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 "presence/implementation/advertisement_decoder.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/container/flat_hash_map.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/implementation/advertisement_decoder_impl.h" -#include "presence/scan_request.h" -#include "presence/scan_request_builder.h" - -namespace nearby { -namespace presence { - -namespace { -using ::nearby::ByteArray; // NOLINT -using ::nearby::internal::IdentityType; // NOLINT -using ::nearby::internal::SharedCredential; // NOLINT -using ::testing::ElementsAre; -using ::testing::UnorderedElementsAre; -using ::testing::status::StatusIs; - -constexpr absl::string_view kAccountName = "test account"; - -ScanRequest GetScanRequest() { - return {.account_name = std::string(kAccountName), - .identity_types = { - IdentityType::IDENTITY_TYPE_PRIVATE_GROUP, - IdentityType::IDENTITY_TYPE_CONTACTS_GROUP, - IdentityType::IDENTITY_TYPE_PUBLIC, - }}; -} - -ScanRequest GetScanRequest(std::vector credentials) { - LegacyPresenceScanFilter scan_filter = {.remote_public_credentials = - credentials}; - return ScanRequestBuilder() - .SetAccountName(kAccountName) - .AddIdentityType(IdentityType::IDENTITY_TYPE_PRIVATE_GROUP) - .AddIdentityType(IdentityType::IDENTITY_TYPE_CONTACTS_GROUP) - .AddIdentityType(IdentityType::IDENTITY_TYPE_PUBLIC) - .Build(); -} - -SharedCredential GetPublicCredential() { - // Values copied from LDT tests - ByteArray seed({204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, - 184, 148, 30, 209, 154, 29, 54, 14, 117, 224, 152, - 200, 193, 94, 107, 28, 194, 182, 32, 205, 57}); - ByteArray known_mac({0xB4, 0xC5, 0x9F, 0xA5, 0x99, 0x24, 0x1B, 0x81, - 0x75, 0x8D, 0x97, 0x6B, 0x5A, 0x62, 0x1C, 0x05, - 0x23, 0x2F, 0xE1, 0xBF, 0x89, 0xAE, 0x59, 0x87, - 0xCA, 0x25, 0x4C, 0x35, 0x54, 0xDC, 0xE5, 0x0E}); - SharedCredential public_credential; - public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_tag_v0( - known_mac.AsStringView()); - return public_credential; -} - -TEST(AdvertisementDecoderImpl, - DecodeBaseNpV0PublicIdentityWithTxAndActionFields) { - AdvertisementDecoderImpl decoder; - // v0 public identity, power and action, action value 8 for active unlock. - // These values all come from - // //third_party/nearby/presence/implementation/advertisement_factory_test.cc - auto result = - decoder.DecodeAdvertisement(absl::HexStringToBytes("000315FF260080")); - - ASSERT_OK(result); - EXPECT_THAT(result->data_elements, - UnorderedElementsAre( - DataElement(DataElement::kPublicIdentityFieldType, ""), - DataElement(DataElement::kTxPowerFieldType, - absl::HexStringToBytes("ff")), - DataElement(DataElement(ActionBit::kActiveUnlockAction)))); -} - -TEST(AdvertisementDecoderImpl, DecodeBaseNpPublicAdvertisement) { - const std::string salt = "AB"; - AdvertisementDecoderImpl decoder; - - const absl::StatusOr result = decoder.DecodeAdvertisement( - absl::HexStringToBytes("002041420337C1C2C31BEE")); - - ASSERT_OK(result); - EXPECT_EQ(result->identity_type, IdentityType::IDENTITY_TYPE_PUBLIC); - EXPECT_EQ(result->version, 0); - EXPECT_THAT( - result->data_elements, - ElementsAre(DataElement(DataElement::kSaltFieldType, salt), - DataElement(DataElement::kPublicIdentityFieldType, ""), - DataElement(DataElement::kModelIdFieldType, - absl::HexStringToBytes("C1C2C3")), - DataElement(DataElement::kBatteryFieldType, - absl::HexStringToBytes("EE")))); -} - -TEST(AdvertisementDecoderImpl, DecodeBaseNpWithTxAndActionFields) { - std::string salt = "AB"; - AdvertisementDecoderImpl decoder; - - auto result = decoder.DecodeAdvertisement( - absl::HexStringToBytes("0020414203155036B04180")); - - ASSERT_OK(result); - EXPECT_THAT(result->data_elements, - UnorderedElementsAre( - DataElement(DataElement::kSaltFieldType, salt), - DataElement(DataElement::kPublicIdentityFieldType, ""), - DataElement(DataElement::kTxPowerFieldType, - absl::HexStringToBytes("50")), - DataElement(DataElement::kContextTimestampFieldType, - absl::HexStringToBytes("0B")), - DataElement(DataElement(ActionBit::kTapToTransferAction)), - DataElement(DataElement(ActionBit::kNearbyShareAction)))); -} - -TEST(AdvertisementDecoderImpl, DecodeBaseNpPrivateAdvertisement) { - std::string salt = "AB"; - ByteArray metadata_key( - {205, 104, 63, 225, 161, 209, 248, 70, 84, 61, 10, 19, 212, 174}); - absl::flat_hash_map> - credentials; - credentials[IdentityType::IDENTITY_TYPE_PRIVATE_GROUP].push_back( - GetPublicCredential()); - AdvertisementDecoderImpl decoder(&credentials); - - absl::StatusOr result = decoder.DecodeAdvertisement( - absl::HexStringToBytes("00514142b8412efb0bc657ba514baf4d1b50ddc842cd1c")); - ASSERT_OK(result); - EXPECT_EQ(result->metadata_key, metadata_key.AsStringView()); - EXPECT_EQ(result->identity_type, IdentityType::IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_THAT(result->data_elements, - ElementsAre(DataElement(DataElement::kSaltFieldType, salt), - DataElement(DataElement::kTxPowerFieldType, - absl::HexStringToBytes("05")), - DataElement(DataElement::kActionFieldType, - absl::HexStringToBytes("08")))); -} - -TEST(AdvertisementDecoderImpl, InvalidEncryptedContent) { - std::string salt = "AB"; - ByteArray metadata_key( - {205, 104, 63, 225, 161, 209, 248, 70, 84, 61, 10, 19, 212, 174}); - absl::flat_hash_map> - credentials; - credentials[IdentityType::IDENTITY_TYPE_PRIVATE_GROUP].push_back( - GetPublicCredential()); - AdvertisementDecoderImpl decoder(&credentials); - - EXPECT_THAT(decoder.DecodeAdvertisement(absl::HexStringToBytes( - "00414142f085d661ac8cb110e792e7faeb736294")), - StatusIs(absl::StatusCode::kOutOfRange)); -} - -TEST(AdvertisementDecoderImpl, UnsupportedDataElement) { - std::string valid_header_and_salt = absl::HexStringToBytes("00204142"); - AdvertisementDecoderImpl decoder; - - EXPECT_THAT(decoder.DecodeAdvertisement(valid_header_and_salt + - absl::HexStringToBytes("0D")), - StatusIs(absl::StatusCode::kInvalidArgument)); -} - -TEST(AdvertisementDecoderImpl, InvalidAdvertisementFieldTooShort) { - AdvertisementDecoderImpl decoder; - - // 0x59 header means 5 bytes long Account Key Data but only 4 bytes follow. - EXPECT_THAT( - decoder.DecodeAdvertisement(absl::HexStringToBytes("0059A0A1A2A3")), - StatusIs(absl::StatusCode::kOutOfRange)); -} - -TEST(AdvertisementDecoderImpl, ZeroLengthPayload) { - AdvertisementDecoderImpl decoder; - - // A action with type 0xA and no payload - const absl::StatusOr result = - decoder.DecodeAdvertisement(absl::HexStringToBytes("000A")); - - ASSERT_OK(result); - EXPECT_THAT(result->data_elements, ElementsAre(DataElement(0xA, ""))); -} - -TEST(AdvertisementDecoderImpl, EmptyAdvertisement) { - AdvertisementDecoderImpl decoder; - - EXPECT_THAT(decoder.DecodeAdvertisement(""), - StatusIs(absl::StatusCode::kOutOfRange)); -} - -TEST(AdvertisementDecoderImpl, UnsupportedAdvertisementVersion) { - AdvertisementDecoderImpl decoder; - - EXPECT_THAT(decoder.DecodeAdvertisement( - absl::HexStringToBytes("012041420318CD29EEFF")), - StatusIs(absl::StatusCode::kUnimplemented)); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_factory.cc b/presence/implementation/advertisement_factory.cc deleted file mode 100644 index 87c74183..00000000 --- a/presence/implementation/advertisement_factory.cc +++ /dev/null @@ -1,236 +0,0 @@ -// 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 "presence/implementation/advertisement_factory.h" - -#include -#include -#include -#include -#include - -#include "absl/base/attributes.h" -#include "absl/status/status.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "absl/types/variant.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/logging.h" -#include "internal/platform/uuid.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/ldt.h" -#include "presence/implementation/mediums/advertisement_data.h" - -namespace nearby { -namespace presence { - -namespace { -using ::nearby::internal::IdentityType; -constexpr uint8_t kBaseVersion = 0; -constexpr size_t kMaxBaseNpAdvSize = 26; - -absl::StatusOr CreateDataElementHeader(size_t length, - unsigned data_type) { - if (length > DataElement::kMaxDataElementLength) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported Data Element length: %d", length)); - } - if (data_type > DataElement::kMaxDataElementType) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported Data Element type: %d", data_type)); - } - return (length << DataElement::kDataElementLengthShift) | data_type; -} - -absl::Status AppendDataElement(unsigned data_type, - absl::string_view data_element, - std::string& output) { - auto header = CreateDataElementHeader(data_element.size(), data_type); - if (!header.ok()) { - LOG(WARNING) << "Can't add Data element type: " << data_type - << ", length: " << data_element.size(); - return header.status(); - } - output.push_back(*header); - output.insert(output.end(), data_element.begin(), data_element.end()); - return absl::OkStatus(); -} - -uint8_t GetIdentityFieldType(IdentityType type) { - switch (type) { - case IdentityType::IDENTITY_TYPE_PRIVATE_GROUP: - return DataElement::kPrivateGroupIdentityFieldType; - case IdentityType::IDENTITY_TYPE_CONTACTS_GROUP: - return DataElement::kContactsGroupIdentityFieldType; - case IdentityType::IDENTITY_TYPE_PUBLIC: - ABSL_FALLTHROUGH_INTENDED; - default: - return DataElement::kPublicIdentityFieldType; - } -} - -std::string SerializeAction(const Action& action) { - std::string output; - uint32_t input = action.action; - for (int i = 3; i >= 0; --i) { - if (input == 0) { - return output; - } - int shift = 8 * i; - output.push_back(static_cast((input >> shift) & 0xFF)); - input &= (1 << shift) - 1; - } - return output; -} - -bool RequiresCredentials(IdentityType identity_type) { - return identity_type == IdentityType::IDENTITY_TYPE_PRIVATE_GROUP || - identity_type == IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; -} -} // namespace - -absl::StatusOr AdvertisementFactory::CreateAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const { - AdvertisementData advert = {}; - if (absl::holds_alternative( - request.variant)) { - return CreateBaseNpAdvertisement(request, std::move(credential)); - } - return advert; -} - -absl::StatusOr -AdvertisementFactory::CreateBaseNpAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const { - const auto& presence = - absl::get(request.variant); - std::string payload; - payload.reserve(kMaxBaseNpAdvSize); - payload.push_back(kBaseVersion); - absl::Status result; - std::string tx_power = {static_cast(request.tx_power)}; - std::string action = SerializeAction(presence.action); - uint8_t identity_type = - GetIdentityFieldType(presence.credential_selector.identity_type); - bool needs_encryption = - identity_type != DataElement::kPublicIdentityFieldType; - if (needs_encryption) { - if (request.salt.size() != kSaltSize) { - return absl::InvalidArgumentError( - absl::StrFormat("Unsupported salt size %d", request.salt.size())); - } - if (!credential) { - return absl::FailedPreconditionError("Missing credentials"); - } - std::string unencrypted; - result = AppendDataElement(DataElement::kTxPowerFieldType, tx_power, - unencrypted); - if (!result.ok()) { - return result; - } - result = - AppendDataElement(DataElement::kActionFieldType, action, unencrypted); - if (!result.ok()) { - return result; - } - VLOG(1) << "Unencrypted advertisement payload " - << absl::BytesToHexString(unencrypted); - absl::StatusOr encrypted = - EncryptDataElements(*credential, request.salt, unencrypted); - if (!encrypted.ok()) { - return encrypted.status(); - } - if (encrypted->size() <= kBaseMetadataSize) { - return absl::OutOfRangeError( - absl::StrFormat("Encrypted identity DE is too short - %d bytes. " - "Expected more than %d", - encrypted->size(), kBaseMetadataSize)); - } - - // The Identity DE header does not include the length of salt nor metadata. - absl::StatusOr identity_header = CreateDataElementHeader( - encrypted->size() - kBaseMetadataSize, identity_type); - if (!identity_header.ok()) { - return identity_header.status(); - } - payload.push_back(*identity_header); - // In the encrypted format, salt is not a DE (thus no header) - payload.append(request.salt); - payload.append(*encrypted); - } else { - result = AppendDataElement(identity_type, "", payload); - if (!result.ok()) { - return result; - } - if (!request.salt.empty()) { - result = - AppendDataElement(DataElement::kSaltFieldType, request.salt, payload); - if (!result.ok()) { - return result; - } - } - result = - AppendDataElement(DataElement::kTxPowerFieldType, tx_power, payload); - if (!result.ok()) { - return result; - } - result = AppendDataElement(DataElement::kActionFieldType, action, payload); - if (!result.ok()) { - return result; - } - } - return AdvertisementData{.is_extended_advertisement = false, - .content = payload}; -} -absl::StatusOr AdvertisementFactory::EncryptDataElements( - const LocalCredential& credential, absl::string_view salt, - absl::string_view data_elements) const { - if (credential.metadata_encryption_key_v0().size() != kBaseMetadataSize) { - return absl::FailedPreconditionError(absl::StrFormat( - "Metadata key size %d, expected %d", - credential.metadata_encryption_key_v0().size(), kBaseMetadataSize)); - } - - // HMAC is not used during encryption, so we can pass an empty value. - absl::StatusOr encryptor = - LdtEncryptor::Create(credential.key_seed(), /*known_hmac=*/""); - if (!encryptor.ok()) { - return encryptor.status(); - } - std::string plaintext = - absl::StrCat(credential.metadata_encryption_key_v0(), data_elements); - return encryptor->Encrypt(plaintext, salt); -} - -absl::StatusOr AdvertisementFactory::GetCredentialSelector( - const BaseBroadcastRequest& request) { - if (absl::holds_alternative( - request.variant)) { - const auto& presence = - absl::get(request.variant); - if (RequiresCredentials(presence.credential_selector.identity_type)) { - return presence.credential_selector; - } - } - return absl::NotFoundError("credentials not required"); -} -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_factory.h b/presence/implementation/advertisement_factory.h deleted file mode 100644 index 54211944..00000000 --- a/presence/implementation/advertisement_factory.h +++ /dev/null @@ -1,63 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_FACTORY_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_FACTORY_H_ - -#include - -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/mediums/advertisement_data.h" - -namespace nearby { -namespace presence { - -// Builds BLE advertisements from broadcast requests. -class AdvertisementFactory { - public: - using LocalCredential = internal::LocalCredential; - - // Returns a `CredentialSelector` if credentials are required to create an - // advertisement from the `request`. - static absl::StatusOr GetCredentialSelector( - const BaseBroadcastRequest& request); - - // Returns a BLE advertisement for given `request. - absl::StatusOr CreateAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const; // NOLINT - - absl::StatusOr CreateAdvertisement( - const BaseBroadcastRequest& request) const { - return CreateAdvertisement(request, - absl::optional()); // NOLINT - } - - private: - absl::StatusOr CreateBaseNpAdvertisement( - const BaseBroadcastRequest& request, - absl::optional credential) const; // NOLINT - absl::StatusOr EncryptDataElements( - const LocalCredential& credential, absl::string_view salt, - absl::string_view data_elements) const; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_ADVERTISEMENT_FACTORY_H_ diff --git a/presence/implementation/advertisement_factory_test.cc b/presence/implementation/advertisement_factory_test.cc deleted file mode 100644 index 8c2897f8..00000000 --- a/presence/implementation/advertisement_factory_test.cc +++ /dev/null @@ -1,148 +0,0 @@ -// 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 "presence/implementation/advertisement_factory.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "absl/strings/escaping.h" -#include "internal/platform/byte_array.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/implementation/action_factory.h" -#include "presence/implementation/mediums/advertisement_data.h" - -namespace nearby { -namespace presence { - -namespace { - -using ::nearby::ByteArray; // NOLINT -using ::nearby::internal::IdentityType; -using ::nearby::internal::LocalCredential; // NOLINT -using ::testing::NiceMock; -using ::testing::Return; -using ::testing::status::StatusIs; - -LocalCredential CreateLocalCredential(IdentityType identity_type) { - // Values copied from LDT tests - ByteArray seed({204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, - 184, 148, 30, 209, 154, 29, 54, 14, 117, 224, 152, - 200, 193, 94, 107, 28, 194, 182, 32, 205, 57}); - ByteArray metadata_key( - {205, 104, 63, 225, 161, 209, 248, 70, 84, 61, 10, 19, 212, 174}); - - LocalCredential private_credential; - private_credential.set_identity_type(identity_type); - private_credential.set_key_seed(seed.AsStringView()); - private_credential.set_metadata_encryption_key_v0( - metadata_key.AsStringView()); - return private_credential; -} - -TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) { - std::string account_name = "Test account"; - std::string salt = "AB"; - constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; - std::vector data_elements; - data_elements.emplace_back(ActionBit::kActiveUnlockAction); - Action action = ActionFactory::CreateAction(data_elements); - BaseBroadcastRequest request = - BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) - .SetAccountName(account_name) - .SetSalt(salt) - .SetTxPower(5) - .SetAction(action)); - - absl::StatusOr result = - AdvertisementFactory().CreateAdvertisement( - request, CreateLocalCredential(kIdentity)); - - ASSERT_OK(result); - EXPECT_FALSE(result->is_extended_advertisement); - EXPECT_EQ(absl::BytesToHexString(result->content), - "00514142b8412efb0bc657ba514baf4d1b50ddc842cd1c"); -} - -TEST(AdvertisementFactory, CreateAdvertisementFromTrustedIdentity) { - std::string account_name = "Test account"; - std::string salt = "AB"; - constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; - std::vector data_elements; - data_elements.emplace_back(ActionBit::kActiveUnlockAction); - data_elements.emplace_back(ActionBit::kPresenceManagerAction); - Action action = ActionFactory::CreateAction(data_elements); - BaseBroadcastRequest request = - BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) - .SetAccountName(account_name) - .SetSalt(salt) - .SetTxPower(5) - .SetAction(action)); - - absl::StatusOr result = - AdvertisementFactory().CreateAdvertisement( - request, CreateLocalCredential(kIdentity)); - - ASSERT_OK(result); - EXPECT_FALSE(result->is_extended_advertisement); - EXPECT_EQ(absl::BytesToHexString(result->content), - "0052414257a35c020f1c547d7e169303196d75da7118ba"); -} - -TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) { - std::string salt = "AB"; - constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PUBLIC; - std::vector data_elements; - data_elements.emplace_back(ActionBit::kActiveUnlockAction); - Action action = ActionFactory::CreateAction(data_elements); - BaseBroadcastRequest request = - BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) - .SetSalt(salt) - .SetTxPower(5) - .SetAction(action)); - - absl::StatusOr result = - AdvertisementFactory().CreateAdvertisement(request); - - ASSERT_OK(result); - EXPECT_FALSE(result->is_extended_advertisement); - EXPECT_EQ(absl::BytesToHexString(result->content), "00032041421505260080"); -} - -TEST(AdvertisementFactory, CreateAdvertisementFailsWhenSaltIsTooShort) { - std::string salt = "AB"; - constexpr IdentityType kIdentity = internal::IDENTITY_TYPE_PRIVATE_GROUP; - std::vector data_elements; - data_elements.emplace_back(ActionBit::kActiveUnlockAction); - Action action = ActionFactory::CreateAction(data_elements); - BaseBroadcastRequest request = - BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) - .SetSalt(salt) - .SetTxPower(5) - .SetAction(action)); - // Override the salt with invalid value - request.salt = "C"; - - EXPECT_THAT(AdvertisementFactory().CreateAdvertisement(request), - StatusIs(absl::StatusCode::kInvalidArgument)); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_filter.cc b/presence/implementation/advertisement_filter.cc deleted file mode 100644 index e3b5bb37..00000000 --- a/presence/implementation/advertisement_filter.cc +++ /dev/null @@ -1,119 +0,0 @@ -// 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 "presence/implementation/advertisement_filter.h" - -#include -#include - -#include "absl/types/variant.h" -#include "internal/platform/logging.h" -#include "presence/data_element.h" -#include "presence/implementation/advertisement_decoder.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -bool Contains(const std::vector& data_elements, - const DataElement& data_element) { - return std::find(data_elements.begin(), data_elements.end(), data_element) != - data_elements.end(); -} - -bool ContainsAll(const std::vector& data_elements, - const std::vector& extended_properties) { - for (const auto& filter_element : extended_properties) { - if (!Contains(data_elements, filter_element)) { - return false; - } - } - return true; -} - -bool ContainsAny(const std::vector& data_elements, - const std::vector& actions) { - if (actions.empty()) { - return true; - } - for (int action : actions) { - if (Contains(data_elements, DataElement(ActionBit(action)))) { - return true; - } - } - return false; -} - -bool AdvertisementFilter::MatchesScanFilter( - const Advertisement& advertisement) { - // Verify the identity is one requested in the scan_request. - // Per the Public API of scan_request, if identity_types provided in the - // scan_request is empty then decode advertisements of every identity type - auto requested_identity_types = scan_request_.identity_types; - if (!requested_identity_types.empty() && - !(std::find( - requested_identity_types.begin(), requested_identity_types.end(), - advertisement.identity_type) != requested_identity_types.end())) { - LOG(INFO) << "Skipping advertisement with identity type: " - << advertisement.identity_type - << " because that identity type was not requested in the scan " - "request"; - return false; - } - - // The advertisement matches the scan request when it matches at least - // one of the filters in the request. - if (scan_request_.scan_filters.empty()) { - return true; - } - - // NOLINT is used to suppress google3-legacy-absl-backport lints because the - // the suggestion is not compatible with Chrome - for (const auto& filter : scan_request_.scan_filters) { - if (absl::holds_alternative(filter)) { // NOLINT - if (MatchesScanFilter(advertisement.data_elements, - absl::get(filter))) { // NOLINT - return true; - } - } else if (absl::holds_alternative( // NOLINT - filter)) { - if (MatchesScanFilter( - advertisement.data_elements, - absl::get(filter))) { // NOLINT - return true; - } - } - } - return false; -} - -bool AdvertisementFilter::MatchesScanFilter( - const std::vector& data_elements, - const PresenceScanFilter& filter) { - // The advertisement must contain all Data Elements in scan request. - return ContainsAll(data_elements, filter.extended_properties); -} - -bool AdvertisementFilter::MatchesScanFilter( - const std::vector& data_elements, - const LegacyPresenceScanFilter& filter) { - // The advertisement must: - // * contain any Action from scan request, - // * contain all Data Elements in scan request. - return ContainsAny(data_elements, filter.actions) && - ContainsAll(data_elements, filter.extended_properties); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/advertisement_filter.h b/presence/implementation/advertisement_filter.h deleted file mode 100644 index 2e2db1e4..00000000 --- a/presence/implementation/advertisement_filter.h +++ /dev/null @@ -1,46 +0,0 @@ -// 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_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FILTER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FILTER_H_ - -#include - -#include "presence/data_element.h" -#include "presence/implementation/advertisement_decoder.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { -class AdvertisementFilter { - public: - explicit AdvertisementFilter(ScanRequest scan_request) - : scan_request_(scan_request) {} - - // Returns true if the decoded advertisement in `data_elements` matches the - // filters in `scan_request`. - bool MatchesScanFilter(const Advertisement& adv); - - private: - bool MatchesScanFilter(const std::vector& data_elements, - const PresenceScanFilter& filter); - bool MatchesScanFilter(const std::vector& data_elements, - const LegacyPresenceScanFilter& filter); - ScanRequest scan_request_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_ADVERTISEMENT_FILTER_H_ diff --git a/presence/implementation/advertisement_filter_test.cc b/presence/implementation/advertisement_filter_test.cc deleted file mode 100644 index ff3a1dfd..00000000 --- a/presence/implementation/advertisement_filter_test.cc +++ /dev/null @@ -1,174 +0,0 @@ -// 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 "presence/implementation/advertisement_filter.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/implementation/advertisement_decoder.h" -#include "presence/scan_request.h" -#include "presence/scan_request_builder.h" - -namespace nearby { -namespace presence { -namespace { - -TEST(AdvertisementFilter, MatchesScanFilterNoFilterPasses) { - std::vector adv = { - DataElement(DataElement::kPrivateGroupIdentityFieldType, "payload")}; - ScanRequest empty_scan_request = {}; - AdvertisementFilter adv_filter(empty_scan_request); - - // A scan request without scan filters matches any advertisement - EXPECT_TRUE(adv_filter.MatchesScanFilter( - {.data_elements = {DataElement( - DataElement::kPrivateGroupIdentityFieldType, "payload")}})); - EXPECT_TRUE(adv_filter.MatchesScanFilter({})); -} - -TEST(AdvertisementFilter, MatchesPresenceScanFilter) { - std::vector adv = { - DataElement(DataElement::kPrivateGroupIdentityFieldType, "payload")}; - DataElement model_id = - DataElement(DataElement::kModelIdFieldType, "model id"); - DataElement salt = DataElement(DataElement::kSaltFieldType, "salt"); - DataElement salt2 = DataElement(DataElement::kSaltFieldType, "salt 2"); - PresenceScanFilter filter = {.extended_properties = {model_id, salt}}; - - AdvertisementFilter adv_filter( - ScanRequestBuilder().AddScanFilter(filter).Build()); - - EXPECT_FALSE(adv_filter.MatchesScanFilter({})); - EXPECT_FALSE(adv_filter.MatchesScanFilter({.data_elements = {salt}})); - EXPECT_TRUE( - adv_filter.MatchesScanFilter({.data_elements = {salt, model_id}})); - EXPECT_TRUE( - adv_filter.MatchesScanFilter({.data_elements = {salt, salt2, model_id}})); - EXPECT_FALSE( - adv_filter.MatchesScanFilter({.data_elements = {salt2, model_id}})); -} - -TEST(AdvertisementFilter, MatchesLegacyPresenceScanFilter) { - std::vector adv = { - DataElement(DataElement::kPrivateGroupIdentityFieldType, "payload")}; - DataElement model_id = - DataElement(DataElement::kModelIdFieldType, "model id"); - DataElement salt = DataElement(DataElement::kSaltFieldType, "salt"); - DataElement salt2 = DataElement(DataElement::kSaltFieldType, "salt 2"); - LegacyPresenceScanFilter filter = {.extended_properties = {model_id, salt}}; - - AdvertisementFilter adv_filter( - ScanRequestBuilder().AddScanFilter(filter).Build()); - - EXPECT_FALSE(adv_filter.MatchesScanFilter(Advertisement{})); - EXPECT_FALSE(adv_filter.MatchesScanFilter({.data_elements = {salt}})); - EXPECT_TRUE( - adv_filter.MatchesScanFilter({.data_elements = {salt, model_id}})); - EXPECT_TRUE( - adv_filter.MatchesScanFilter({.data_elements = {salt, salt2, model_id}})); - EXPECT_FALSE(adv_filter.MatchesScanFilter( - Advertisement{.data_elements = {salt2, model_id}})); -} - -TEST(AdvertisementFilter, - EncryptedIdentityFilterIgnoresPublicIdentityAdvertisement) { - AdvertisementFilter adv_filter( - {.identity_types = { - internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP, - internal::IdentityType::IDENTITY_TYPE_CONTACTS_GROUP}}); - - EXPECT_FALSE(adv_filter.MatchesScanFilter( - {.identity_type = internal::IdentityType::IDENTITY_TYPE_PUBLIC})); - EXPECT_TRUE(adv_filter.MatchesScanFilter( - {.identity_type = internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP})); -} - -TEST(AdvertisementFilter, PublicIdentityFilterMatchesPublicIdentityAdv) { - AdvertisementFilter adv_filter( - {.identity_types = {internal::IdentityType::IDENTITY_TYPE_PUBLIC}}); - - EXPECT_TRUE(adv_filter.MatchesScanFilter( - {.identity_type = internal::IdentityType::IDENTITY_TYPE_PUBLIC})); - EXPECT_FALSE(adv_filter.MatchesScanFilter( - {.identity_type = internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP})); -} - -TEST(AdvertisementFilter, EmptyIdentityFilterMatchesAllAdvIdentityTypes) { - AdvertisementFilter adv_filter({}); - - EXPECT_TRUE(adv_filter.MatchesScanFilter( - {.identity_type = internal::IdentityType::IDENTITY_TYPE_PUBLIC})); - EXPECT_TRUE(adv_filter.MatchesScanFilter( - {.identity_type = internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP})); -} - -TEST(AdvertisementFilter, MatchesLegacyPresenceScanFilterWithActions) { - std::vector adv = { - DataElement(DataElement::kPrivateGroupIdentityFieldType, "payload")}; - DataElement model_id = - DataElement(DataElement::kModelIdFieldType, "model id"); - DataElement salt = DataElement(DataElement::kSaltFieldType, "salt"); - DataElement ttt_action = DataElement(ActionBit::kTapToTransferAction); - LegacyPresenceScanFilter filter = { - .actions = {static_cast(ActionBit::kActiveUnlockAction), - static_cast(ActionBit::kTapToTransferAction)}, - .extended_properties = {model_id, salt}}; - - AdvertisementFilter adv_filter( - ScanRequestBuilder().AddScanFilter(filter).Build()); - - EXPECT_FALSE( - adv_filter.MatchesScanFilter({.data_elements = {salt, model_id}})); - EXPECT_TRUE(adv_filter.MatchesScanFilter( - {.data_elements = {salt, ttt_action, model_id}})); -} - -TEST(AdvertisementFilter, MatchesMultipleFilters) { - std::vector adv = { - DataElement(DataElement::kPrivateGroupIdentityFieldType, "payload")}; - DataElement model_id = - DataElement(DataElement::kModelIdFieldType, "model id"); - DataElement salt = DataElement(DataElement::kSaltFieldType, "salt"); - DataElement ttt_action = DataElement(ActionBit::kTapToTransferAction); - PresenceScanFilter presence_filter = {.extended_properties = {model_id}}; - LegacyPresenceScanFilter legacy_filter = { - .actions = {static_cast(ActionBit::kActiveUnlockAction), - static_cast(ActionBit::kTapToTransferAction)}, - .extended_properties = {salt}}; - - AdvertisementFilter adv_filter(ScanRequestBuilder() - .AddScanFilter(presence_filter) - .AddScanFilter(legacy_filter) - .Build()); - - EXPECT_TRUE(adv_filter.MatchesScanFilter({.data_elements = {model_id}})); - EXPECT_TRUE( - adv_filter.MatchesScanFilter({.data_elements = {salt, ttt_action}})); - EXPECT_FALSE(adv_filter.MatchesScanFilter({.data_elements = {ttt_action}})); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/base_broadcast_request.cc b/presence/implementation/base_broadcast_request.cc deleted file mode 100644 index 30dda102..00000000 --- a/presence/implementation/base_broadcast_request.cc +++ /dev/null @@ -1,112 +0,0 @@ -// 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 "presence/implementation/base_broadcast_request.h" - -#include -#include - -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/crypto.h" -#include "internal/platform/logging.h" -#include "presence/broadcast_request.h" -#include "presence/implementation/action_factory.h" - -namespace nearby { -namespace presence { - -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetSalt( - absl::string_view salt) { - if (salt.size() != kSaltSize) { - LOG(WARNING) << "Unsupported salt length: " << salt.size(); - } else { - salt_ = std::string(salt); - } - return *this; -} -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetTxPower( - int8_t tx_power) { - tx_power_ = tx_power; - return *this; -} - -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetAction( - const Action& action) { - action_ = action; - return *this; -} - -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetPowerMode( - PowerMode power_mode) { - power_mode_ = power_mode; - return *this; -} - -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetAccountName( - absl::string_view account_name) { - account_name_ = std::string(account_name); - return *this; -} - -BasePresenceRequestBuilder& BasePresenceRequestBuilder::SetManagerAppId( - absl::string_view manager_app_id) { - manager_app_id_ = std::string(manager_app_id); - return *this; -} - -BasePresenceRequestBuilder::operator BaseBroadcastRequest() const { - BaseBroadcastRequest::BasePresence presence{ - .credential_selector = {.manager_app_id = manager_app_id_, - .account_name = account_name_, - .identity_type = identity_}, - .action = action_}; - - std::string bytes(kSaltSize, 0); - RandBytes(const_cast(bytes.data()), bytes.size()); - - BaseBroadcastRequest broadcast_request{ - .variant = presence, - .salt = salt_.size() == kSaltSize ? salt_ : bytes, - .tx_power = tx_power_, - .power_mode = power_mode_}; - return broadcast_request; -} - -absl::StatusOr BaseBroadcastRequest::Create( - const BroadcastRequest& request) { - if (absl::holds_alternative(request.variant)) { - const auto& presence_request = - absl::get(request.variant); - if (presence_request.sections.empty()) { - return absl::InvalidArgumentError("Missing broadcast sections"); - } - if (presence_request.sections.size() > 1) { - LOG(WARNING) << "Only first section is used in BLE 4.2 advertisement"; - } - const PresenceBroadcast::BroadcastSection& section = - presence_request.sections.front(); - return BaseBroadcastRequest( - BasePresenceRequestBuilder(section.identity) - .SetTxPower(request.tx_power) - .SetAction(ActionFactory::CreateAction(section.extended_properties)) - .SetPowerMode(request.power_mode) - .SetManagerAppId(section.manager_app_id) - .SetAccountName(section.account_name)); - } - return absl::UnimplementedError("Request not supported"); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/base_broadcast_request.h b/presence/implementation/base_broadcast_request.h deleted file mode 100644 index 36821ccc..00000000 --- a/presence/implementation/base_broadcast_request.h +++ /dev/null @@ -1,102 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_BASE_BROADCAST_REQUEST_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_BASE_BROADCAST_REQUEST_H_ - -#include - -#include -#include - -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "absl/types/variant.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "presence/broadcast_request.h" -#include "presence/power_mode.h" - -namespace nearby { -namespace presence { - -constexpr int8_t kUnspecifiedTxPower = -128; -constexpr size_t kSaltSize = 2; -// The identity metadata size in the base advertisement -constexpr size_t kBaseMetadataSize = 14; - -/** Defines the action (intended actions) of base NP advertisement */ -struct Action { - uint32_t action; -}; - -/** Defines a Nearby Presence broadcast request */ -struct BaseBroadcastRequest { - // Creates `BaseBroadcastRequest` from the public API request in - // `BroadcastRequest`. - static absl::StatusOr Create( - const BroadcastRequest& request); - - struct BasePresence { - CredentialSelector credential_selector; - Action action; - }; - struct BaseFastPair { - struct Discoverable { - std::string model_id; - }; - struct Nondiscoverable { - std::string account_key_data; - std::string battery_info; - }; - absl::variant advertisement; - }; - struct BaseEddystone { - std::string ephemeral_id; - }; - absl::variant variant; - std::string salt; - int8_t tx_power; - unsigned int interval_ms; - PowerMode power_mode; -}; - -/** Builds a brodacast request variant with NP identity for BLE 4.2 */ -class BasePresenceRequestBuilder { - public: - explicit BasePresenceRequestBuilder( - const nearby::internal::IdentityType& identity) - : identity_(identity) {} - BasePresenceRequestBuilder& SetSalt(absl::string_view salt); - BasePresenceRequestBuilder& SetTxPower(int8_t tx_power); - BasePresenceRequestBuilder& SetAction(const Action& action); - BasePresenceRequestBuilder& SetPowerMode(PowerMode power_mode); - BasePresenceRequestBuilder& SetAccountName(absl::string_view account_name); - BasePresenceRequestBuilder& SetManagerAppId(absl::string_view manager_app_id); - - explicit operator BaseBroadcastRequest() const; - - private: - nearby::internal::IdentityType identity_; - std::string salt_; - int8_t tx_power_ = kUnspecifiedTxPower; - Action action_; - PowerMode power_mode_ = PowerMode::kNoPower; - std::string account_name_; - std::string manager_app_id_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_BASE_BROADCAST_REQUEST_H_ diff --git a/presence/implementation/base_broadcast_request_test.cc b/presence/implementation/base_broadcast_request_test.cc deleted file mode 100644 index b27040b3..00000000 --- a/presence/implementation/base_broadcast_request_test.cc +++ /dev/null @@ -1,94 +0,0 @@ -// 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 "presence/implementation/base_broadcast_request.h" - -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/types/variant.h" -#include "internal/proto/credential.pb.h" -#include "presence/broadcast_request.h" -#include "presence/data_element.h" - -namespace nearby { -namespace presence { -namespace { - -using ::nearby::internal::IdentityType; -using ::testing::status::StatusIs; - -TEST(BroadcastRequestTest, CreateBasePresenceRequest) { - nearby::internal::IdentityType identity; - constexpr int8_t kTxPower = -13; - - BaseBroadcastRequest request = BaseBroadcastRequest( - BasePresenceRequestBuilder(identity).SetTxPower(kTxPower).SetPowerMode( - PowerMode::kBalanced)); - - EXPECT_TRUE(absl::holds_alternative( - request.variant)); - EXPECT_EQ(request.salt.size(), 2); - EXPECT_EQ(request.tx_power, kTxPower); - EXPECT_EQ(request.power_mode, PowerMode::kBalanced); -} - -TEST(BroadcastRequestTest, CreateFromPresenceRequest) { - constexpr int8_t kTxPower = 30; - constexpr uint32_t kExpectedAction = - (1 << 23); // encoded kActiveUnlockAction - std::string account_name = "Test account"; - std::string manager_app_id = "Manager app id"; - PresenceBroadcast::BroadcastSection section = { - .identity = internal::IDENTITY_TYPE_PUBLIC, - .extended_properties = {DataElement( - DataElement(ActionBit::kActiveUnlockAction))}, - .account_name = account_name, - .manager_app_id = manager_app_id}; - PresenceBroadcast presence_request = {.sections = {section}}; - BroadcastRequest input = {.tx_power = kTxPower, .variant = presence_request}; - - absl::StatusOr request = - BaseBroadcastRequest::Create(input); - - ASSERT_OK(request); - EXPECT_THAT(request->tx_power, kTxPower); - EXPECT_THAT(absl::get(request->variant) - .credential_selector.identity_type, - IdentityType::IDENTITY_TYPE_PUBLIC); - EXPECT_THAT(absl::get(request->variant) - .action.action, - kExpectedAction); - EXPECT_THAT(absl::get(request->variant) - .credential_selector.account_name, - account_name); - EXPECT_THAT(absl::get(request->variant) - .credential_selector.manager_app_id, - manager_app_id); -} - -TEST(BroadcastRequestTest, CreateFromEmptyPresenceRequestFails) { - BroadcastRequest empty = { - .variant = PresenceBroadcast(), - }; - - EXPECT_THAT(BaseBroadcastRequest::Create(empty), - StatusIs(absl::StatusCode::kInvalidArgument)); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/broadcast_manager.cc b/presence/implementation/broadcast_manager.cc deleted file mode 100644 index 088083b3..00000000 --- a/presence/implementation/broadcast_manager.cc +++ /dev/null @@ -1,269 +0,0 @@ -// 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 "presence/implementation/broadcast_manager.h" - -#include -#include -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/status/status.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/implementation/crypto.h" -#include "internal/platform/logging.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/implementation/advertisement_factory.h" -#include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/mediums/advertisement_data.h" - -namespace nearby { -namespace presence { -namespace { - -using AdvertisingCallback = ::nearby::api::ble::BleMedium::AdvertisingCallback; -using AdvertisingSession = ::nearby::api::ble::BleMedium::AdvertisingSession; -using LocalCredential = internal::LocalCredential; - -uint16_t SaltToInt(absl::string_view salt) { - if (salt.length() < 2) return 0; - uint16_t b0 = salt[0]; - uint16_t b1 = salt[1]; - return b0 << 8 | b1; -} -std::string SaltFromInt(uint16_t x) { - std::string salt; - salt.resize(2); - salt[0] = x >> 8 & 0xFF; - salt[1] = x & 0xFF; - return salt; -} - -// Selects a salt that has not been used yet. The salt is added to -// `credential.consumed_salts`. -// We may fail to find an unused salt. In this unlikely event, an already -// consumed salt is returned. -std::string SelectSalt(LocalCredential& credential, - absl::string_view preferred_salt) { - // NP certificate guidelines say that we should try to get an unused salt 128 - // times. - constexpr int kMaxSaltSelectRetries = 128; - - uint16_t s = SaltToInt(preferred_salt); - for (int i = 0; i < kMaxSaltSelectRetries; i++) { - if (!credential.consumed_salts().contains(s)) { - break; - } - s = nearby::RandData(); - } - credential.mutable_consumed_salts()->insert({s, true}); - return SaltFromInt(s); -} - -} // namespace - -absl::StatusOr BroadcastManager::StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) { - absl::StatusOr request = - BaseBroadcastRequest::Create(broadcast_request); - if (!request.ok()) { - LOG(WARNING) << "Invalid broadcast request, reason: " << request.status(); - callback.start_broadcast_cb(request.status()); - return request.status(); - } - BroadcastSessionId id = GenerateBroadcastSessionId(); - RunOnServiceControllerThread( - "start-broadcast", - [this, id, power_mode = broadcast_request.power_mode, request = *request, - broadcast_callback = std::move( - callback)]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable { - sessions_.insert({id, BroadcastSessionState( - std::move(broadcast_callback), power_mode)}); - FetchCredentials(id, std::move(request)); - }); - return id; -} - -void BroadcastManager::FetchCredentials( - BroadcastSessionId id, BaseBroadcastRequest broadcast_request) { - absl::StatusOr credential_selector = - AdvertisementFactory::GetCredentialSelector(broadcast_request); - if (!credential_selector.ok()) { - // Public advertisement, we don't need credential to advertise. - Advertise(id, broadcast_request, /*credentials=*/{}); - return; - } - credential_manager_->GetLocalCredentials( - *credential_selector, - GetLocalCredentialsResultCallback{ - .credentials_fetched_cb = - [this, id, broadcast_request = std::move(broadcast_request), - selector = *credential_selector]( - absl::StatusOr< - std::vector<::nearby::internal::LocalCredential>> - credentials) { - if (!credentials.ok()) { - LOG(WARNING) << "Failed to fetch credentials, status: " - << credentials.status(); - NotifyStartCallbackStatus(id, credentials.status()); - return; - } - RunOnServiceControllerThread( - "advertise-non-public", - [this, id, broadcast_request = std::move(broadcast_request), - credentials = std::move(*credentials), - selector = std::move(selector)]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(executor_) mutable { - absl::optional credential = - Advertise(id, broadcast_request, credentials); - if (credential) { - credential_manager_->UpdateLocalCredential( - selector, std::move(*credential), - {[](absl::Status status) { - if (!status.ok()) { - LOG(WARNING) << "Failed to update private " - "credential, status: " - << status; - } - }}); - } - }); - }}); -} - -absl::optional BroadcastManager::SelectCredential( // NOLINT - BaseBroadcastRequest& broadcast_request, - std::vector credentials) { - if (credentials.empty()) { - return absl::optional(); // NOLINT - } - auto credential = - std::min_element(credentials.begin(), credentials.end(), - [](const LocalCredential& a, const LocalCredential& b) { - return a.start_time_millis() < b.start_time_millis(); - }); - if (credential == credentials.end()) { - LOG(WARNING) << "No active credentials"; - return absl::optional(); // NOLINT - } - std::string salt = SelectSalt(*credential, broadcast_request.salt); - if (salt != broadcast_request.salt) { - VLOG(1) << "Changed salt"; - broadcast_request.salt = salt; - } - return *credential; -} - -absl::optional BroadcastManager::Advertise( // NOLINT - BroadcastSessionId id, BaseBroadcastRequest broadcast_request, - std::vector credentials) { - auto it = sessions_.find(id); - if (it == sessions_.end()) { - LOG(INFO) << "Broadcast session terminated, id: " << id; - return absl::optional(); // NOLINT - } - absl::optional credential = // NOLINT - SelectCredential(broadcast_request, std::move(credentials)); - absl::StatusOr advertisement = - AdvertisementFactory().CreateAdvertisement(broadcast_request, credential); - if (!advertisement.ok()) { - LOG(WARNING) << "Can't create advertisement, reason: " - << advertisement.status(); - NotifyStartCallbackStatus(id, advertisement.status()); - return absl::optional(); // NOLINT - } - std::unique_ptr session = - mediums_->GetBle().StartAdvertising( - *advertisement, it->second.GetPowerMode(), - AdvertisingCallback{ - .start_advertising_result = [this, id](absl::Status status) { - NotifyStartCallbackStatus(id, status); - }}); - if (!session) { - NotifyStartCallbackStatus(id, - absl::InternalError("Can't start advertising")); - return absl::optional(); // NOLINT - } - it->second.SetAdvertisingSession(std::move(session)); - return credential; -} - -void BroadcastManager::NotifyStartCallbackStatus(BroadcastSessionId id, - absl::Status status) { - RunOnServiceControllerThread("started-broadcast-cb", - [this, id, status]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(executor_) { - auto it = sessions_.find(id); - if (it == sessions_.end()) { - return; - } - it->second.CallStartedCallback(status); - if (!status.ok()) { - // Delete failed session. - sessions_.erase(it); - } - }); -} - -void BroadcastManager::StopBroadcast(BroadcastSessionId id) { - RunOnServiceControllerThread( - "stop-broadcast", [this, id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(executor_) { - auto it = sessions_.find(id); - if (it == sessions_.end()) { - VLOG(1) << absl::StrFormat("BroadcastSession(0x%x) not found", id); - return; - } - it->second.StopAdvertising(); - sessions_.erase(it); - }); -} - -BroadcastSessionId BroadcastManager::GenerateBroadcastSessionId() { - return nearby::RandData(); -} - -void BroadcastManager::BroadcastSessionState::SetAdvertisingSession( - std::unique_ptr session) { - advertising_session_ = std::move(session); -} - -void BroadcastManager::BroadcastSessionState::CallStartedCallback( - absl::Status status) { - BroadcastCallback callback = std::move(broadcast_callback_); - if (callback.start_broadcast_cb) { - callback.start_broadcast_cb(status); - } -} - -void BroadcastManager::BroadcastSessionState::StopAdvertising() { - std::unique_ptr advertising_session = - std::move(advertising_session_); - if (advertising_session) { - absl::Status status = advertising_session->stop_advertising(); - if (!status.ok()) { - LOG(WARNING) << "StopAdvertising error: " << status; - } - } -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/broadcast_manager.h b/presence/implementation/broadcast_manager.h deleted file mode 100644 index aedf2fec..00000000 --- a/presence/implementation/broadcast_manager.h +++ /dev/null @@ -1,109 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_BROADCAST_MANAGER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_BROADCAST_MANAGER_H_ - -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/runnable.h" -#include "internal/platform/single_thread_executor.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/credential_manager.h" -#include "presence/implementation/mediums/mediums.h" -#include "presence/power_mode.h" - -namespace nearby { -namespace presence { - -// The instance of BroadcastManager is owned by {@code ServiceControllerImpl}. -// Helping service controller to manage broadcast requests and callbacks. - -class BroadcastManager { - public: - using SingleThreadExecutor = ::nearby::SingleThreadExecutor; - using AdvertisingSession = ::nearby::api::ble::BleMedium::AdvertisingSession; - using Runnable = ::nearby::Runnable; - using LocalCredential = internal::LocalCredential; - BroadcastManager(Mediums& mediums, CredentialManager& credential_manager, - SingleThreadExecutor& executor) { - mediums_ = &mediums, credential_manager_ = &credential_manager, - executor_ = &executor; - } - ~BroadcastManager() = default; - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback); - void StopBroadcast(BroadcastSessionId); - - private: - Mediums* mediums_; - CredentialManager* credential_manager_; - SingleThreadExecutor* executor_; - class BroadcastSessionState { - public: - explicit BroadcastSessionState(BroadcastCallback broadcast_callback, - PowerMode power_mode) - : broadcast_callback_(std::move(broadcast_callback)), - power_mode_(power_mode) {} - - void SetAdvertisingSession(std::unique_ptr session); - void CallStartedCallback(absl::Status status); - void StopAdvertising(); - - PowerMode GetPowerMode() { return power_mode_; } - - private: - BroadcastCallback broadcast_callback_; - PowerMode power_mode_; - std::unique_ptr advertising_session_; - }; - BroadcastSessionId GenerateBroadcastSessionId(); - void NotifyStartCallbackStatus(BroadcastSessionId id, absl::Status status); - void RunOnServiceControllerThread(absl::string_view name, Runnable runnable) { - executor_->Execute(std::string(name), std::move(runnable)); - } - void FetchCredentials(BroadcastSessionId id, - BaseBroadcastRequest broadcast_request) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - absl::optional SelectCredential( // NOLINT - BaseBroadcastRequest& broadcast_request, - std::vector credentials); - - // Returns the private credential, if any, selected to generate the - // advertisement. A salt used in the advertisement is added to the returned - // private credential. The caller must save it in the storage. - absl::optional Advertise( // NOLINT - BroadcastSessionId id, BaseBroadcastRequest broadcast_request, - std::vector credentials) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - absl::flat_hash_map sessions_ - ABSL_GUARDED_BY(*executor_); -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_BROADCAST_MANAGER_H_ diff --git a/presence/implementation/broadcast_manager_test.cc b/presence/implementation/broadcast_manager_test.cc deleted file mode 100644 index 32effaf9..00000000 --- a/presence/implementation/broadcast_manager_test.cc +++ /dev/null @@ -1,177 +0,0 @@ -// 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 "presence/implementation/broadcast_manager.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/future.h" -#include "internal/platform/medium_environment.h" -#include "internal/proto/credential.pb.h" -#include "presence/implementation/credential_manager_impl.h" -#include "presence/implementation/mediums/mediums.h" - -namespace nearby { -namespace presence { -namespace { - -using FeatureFlags = ::nearby::FeatureFlags::Flags; -using internal::IdentityType; -using ::nearby::CountDownLatch; -using ::nearby::MediumEnvironment; -using ::testing::status::StatusIs; - -constexpr FeatureFlags kTestCases[] = { - FeatureFlags{}, -}; - -constexpr absl::string_view kAccountName = "Test account"; -constexpr int8_t kTxPower = 30; - -BroadcastRequest CreateBroadcastRequest(IdentityType identity) { - PresenceBroadcast::BroadcastSection section = { - .identity = identity, - .extended_properties = {DataElement( - DataElement(ActionBit::kActiveUnlockAction))}, - .account_name = std::string(kAccountName)}; - PresenceBroadcast presence_request = {.sections = {section}}; - BroadcastRequest request = {.tx_power = kTxPower, - .variant = presence_request}; - return request; -} - -class MediumEnvironmentStarter { - public: - MediumEnvironmentStarter() { MediumEnvironment::Instance().Start(); } - ~MediumEnvironmentStarter() { MediumEnvironment::Instance().Stop(); } -}; - -class BroadcastManagerTest : public testing::TestWithParam { - protected: - void TearDown() override { - MediumEnvironment::Instance().Sync(); - // Finish pending tasks before destroying BroadcastManager - executor_.Shutdown(); - } - bool IsAdvertising() { - WaitForServiceControllerTasks(); - MediumEnvironment::Instance().Sync(); - return MediumEnvironment::Instance() - .GetBleMediumStatus(*mediums_.GetBle().GetImpl()) - ->is_advertising; - } - BroadcastCallback CreateBroadcastCallback() { - return BroadcastCallback{.start_broadcast_cb = [this](absl::Status status) { - start_broadcast_status_.Set(status); - }}; - } - - void WaitForServiceControllerTasks() { - CountDownLatch latch(1); - executor_.Execute([&]() { latch.CountDown(); }); - latch.Await(); - } - - // The medium environment must be initialized (started) before the service - // controller. - MediumEnvironmentStarter env_; - nearby::Future start_broadcast_status_; - BroadcastCallback broadcast_callback_{ - .start_broadcast_cb = [this](absl::Status status) { - start_broadcast_status_.Set(status); - }}; - Mediums mediums_; - SingleThreadExecutor executor_; - CredentialManagerImpl credential_manager_{&executor_}; - BroadcastManager broadcast_manager_{mediums_, credential_manager_, executor_}; -}; - -INSTANTIATE_TEST_SUITE_P(ParametrisedBroadcastManagerTest, BroadcastManagerTest, - testing::ValuesIn(kTestCases)); - -TEST_P(BroadcastManagerTest, StartBroadcastPublicIdentity) { - absl::StatusOr session = - broadcast_manager_.StartBroadcast( - CreateBroadcastRequest(internal::IDENTITY_TYPE_PUBLIC), - CreateBroadcastCallback()); - - EXPECT_OK(session); - EXPECT_TRUE(start_broadcast_status_.Get().ok()); - EXPECT_OK(start_broadcast_status_.Get().GetResult()); - EXPECT_TRUE(IsAdvertising()); -} - -TEST_P(BroadcastManagerTest, StartAndStopBroadcast) { - absl::StatusOr session = - broadcast_manager_.StartBroadcast( - CreateBroadcastRequest(internal::IDENTITY_TYPE_PUBLIC), - CreateBroadcastCallback()); - ASSERT_OK(session); - EXPECT_TRUE(IsAdvertising()); - - broadcast_manager_.StopBroadcast(*session); - EXPECT_FALSE(IsAdvertising()); -} - -TEST_P(BroadcastManagerTest, StopBroadcastTwiceNoSideEffects) { - absl::StatusOr session = - broadcast_manager_.StartBroadcast( - CreateBroadcastRequest(internal::IDENTITY_TYPE_PUBLIC), - CreateBroadcastCallback()); - ASSERT_OK(session); - EXPECT_TRUE(IsAdvertising()); - - broadcast_manager_.StopBroadcast(*session); - broadcast_manager_.StopBroadcast(*session); -} - -TEST_P(BroadcastManagerTest, StopBroadcastInvalidSessionNoSideEffects) { - broadcast_manager_.StopBroadcast(123456); -} - -TEST_P(BroadcastManagerTest, StartBroadcastInvalidRequestFails) { - absl::StatusOr session = - broadcast_manager_.StartBroadcast(BroadcastRequest{}, - CreateBroadcastCallback()); - - EXPECT_THAT(session, StatusIs(absl::StatusCode::kInvalidArgument)); - EXPECT_TRUE(start_broadcast_status_.Get().ok()); - EXPECT_THAT(start_broadcast_status_.Get().GetResult(), - StatusIs(absl::StatusCode::kInvalidArgument)); - EXPECT_FALSE(IsAdvertising()); -} - -TEST_P(BroadcastManagerTest, StartBroadcastPrivateIdentityFails) { - // TODO(b/256249404): Support private identity. - absl::StatusOr session = - broadcast_manager_.StartBroadcast( - CreateBroadcastRequest(internal::IDENTITY_TYPE_PRIVATE_GROUP), - CreateBroadcastCallback()); - - ASSERT_OK(session); - EXPECT_TRUE(start_broadcast_status_.Get().ok()); - EXPECT_THAT(start_broadcast_status_.Get().GetResult(), - StatusIs(absl::StatusCode::kNotFound)); - EXPECT_FALSE(IsAdvertising()); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/connection_authenticator.h b/presence/implementation/connection_authenticator.h deleted file mode 100644 index 7a9b2cb8..00000000 --- a/presence/implementation/connection_authenticator.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_H_ - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" - -namespace nearby { -namespace presence { - -class ConnectionAuthenticator { - public: - struct OneWayInitiatorData { - std::string shared_credential_hash; - }; - - struct TwoWayInitiatorData { - std::string shared_credential_hash; - std::string private_key_signature; - }; - - struct ResponderData { - std::string private_key_signature; - }; - - using InitiatorData = absl::variant; - - virtual ~ConnectionAuthenticator() = default; - - // Builds a signed message to be returned to Nearby Connections for - // authentication on the other side of the connection. - // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. - // local_credential - The local credential used to sign the derived - // information. If this is std::nullopt, then we will be - // performing one-way authentication. - // shared_credential - The shared credential used to decrypt the advertisement - // from the remote device. - virtual absl::StatusOr BuildSignedMessageAsInitiator( - absl::string_view ukey2_secret, - std::optional local_credential, - const internal::SharedCredential& shared_credential) const = 0; - - // Builds a signed message to be returned to Nearby Connections for - // authentication on the other side of the connection. - // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. - // local_credential - The local credential used to sign the derived - // information so the initiator can verify against our - // shared credential. - virtual absl::StatusOr BuildSignedMessageAsResponder( - absl::string_view ukey2_secret, - const internal::LocalCredential& local_credential) const = 0; - - // Verifies a signed message received from the responder (broadcaster) of the - // Nearby Presence advertisement. - // authentication_data - the data required to verify the connection, received - // from the responder. - // ukey2_secret - the shared secret derived from the ukey2 handshake in NC. - // shared_credentials - the set of shared credentials that can be used to - // verify the responder data. - virtual absl::Status VerifyMessageAsInitiator( - ResponderData authentication_data, absl::string_view ukey2_secret, - const std::vector& shared_credentials) - const = 0; - - // Verifies a signed message received from the Nearby Connections peer. - // Returns the matched local credential if the verification was successful. - // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. - // received_frame - The received frame from Nearby Connections. - // local_credentials - The set of local credentials that may contain the - // required keyseed hash. - // shared_credentials - The set of shared credentials that can be used to - // verify the signed contents of the frame. - virtual absl::StatusOr VerifyMessageAsResponder( - absl::string_view ukey2_secret, InitiatorData initiator_data, - const std::vector& local_credentials, - const std::vector& shared_credentials) - const = 0; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_H_ diff --git a/presence/implementation/connection_authenticator_impl.cc b/presence/implementation/connection_authenticator_impl.cc deleted file mode 100644 index cbe68aa2..00000000 --- a/presence/implementation/connection_authenticator_impl.cc +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 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. -// 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 "presence/implementation/connection_authenticator_impl.h" - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "absl/types/variant.h" -#include "internal/crypto/ed25519.h" -#include "internal/crypto_cros/hkdf.h" -#include "internal/crypto_cros/secure_util.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" - -namespace nearby { -namespace presence { - -namespace { -constexpr int kPresenceAuthenticatorVersion = 1; -constexpr int kPresenceAuthenticatorHkdfKeySize = 32; -constexpr char kBroadcasterMessageHeader[] = - "Nearby Presence Broadcaster Signature"; -constexpr char kDiscovererMessageHeader[] = - "Nearby Presence Discoverer Signature"; -constexpr char kHkdfSalt[] = "Google Nearby"; -constexpr char kBroadcasterHkdfInfo[] = - "Nearby Presence Broadcaster Credential Hash"; -constexpr char kDiscovererHkdfInfo[] = - "Nearby Presence Discoverer Credential Hash"; -} // namespace - -absl::StatusOr -ConnectionAuthenticatorImpl::BuildSignedMessageAsInitiator( - absl::string_view ukey2_secret, - std::optional local_credential, - const internal::SharedCredential& shared_credential) const { - auto shared_credential_hash = crypto::HkdfSha256( - absl::StrCat(ukey2_secret, shared_credential.key_seed()), kHkdfSalt, - kDiscovererHkdfInfo, kPresenceAuthenticatorHkdfKeySize); - if (local_credential.has_value()) { - // two-way authentication, private identity. - auto signer = crypto::Ed25519Signer::Create( - (*local_credential).connection_signing_key().key()); - if (!signer.ok()) { - return signer.status(); - } - auto pkey_signature = - signer->Sign(absl::StrCat(kDiscovererMessageHeader, ukey2_secret)); - if (!pkey_signature.has_value()) { - return absl::InternalError("Signing using private key failed."); - } - return ConnectionAuthenticator::TwoWayInitiatorData{ - .shared_credential_hash = shared_credential_hash, - .private_key_signature = *pkey_signature, - }; - } - // one-way authentication, trusted identity. - return ConnectionAuthenticator::OneWayInitiatorData{ - .shared_credential_hash = shared_credential_hash, - }; -} - -absl::StatusOr -ConnectionAuthenticatorImpl::BuildSignedMessageAsResponder( - absl::string_view ukey2_secret, - const internal::LocalCredential& local_credential) const { - auto signer = crypto::Ed25519Signer::Create( - local_credential.connection_signing_key().key()); - if (!signer.ok()) { - return signer.status(); - } - auto pkey_signature = - signer->Sign(absl::StrCat(kBroadcasterMessageHeader, ukey2_secret)); - if (!pkey_signature.has_value()) { - return absl::InternalError("Signing using private key failed."); - } - return ConnectionAuthenticator::ResponderData{.private_key_signature = - *pkey_signature}; -} - -absl::Status ConnectionAuthenticatorImpl::VerifyMessageAsInitiator( - ResponderData authentication_data, absl::string_view ukey2_secret, - const std::vector& shared_credentials) const { - if (authentication_data.private_key_signature.empty()) { - return absl::InvalidArgumentError("Empty private key signature."); - } - for (const auto& shared_credential : shared_credentials) { - auto verifier = crypto::Ed25519Verifier::Create( - shared_credential.connection_signature_verification_key()); - if (!verifier.ok()) { - continue; - } - // Verify ED25519 signature, returning true if verification succeeded. - if (verifier - ->Verify(absl::StrCat(kBroadcasterMessageHeader, ukey2_secret), - authentication_data.private_key_signature) - .ok()) { - return absl::OkStatus(); - } - } - return absl::InternalError("Unable to verify responder's private key sig."); -} - -absl::StatusOr -ConnectionAuthenticatorImpl::VerifyMessageAsResponder( - absl::string_view ukey2_secret, InitiatorData initiator_data, - const std::vector& local_credentials, - const std::vector& shared_credentials) const { - std::string shared_credential_hash; - std::optional matched_local_credential; - if (absl::holds_alternative(initiator_data)) { - // one-way. we only need to verify if the hash matches one of our - // local credentials. - auto auth_data = absl::get(initiator_data); - if (auth_data.shared_credential_hash.size() != - kPresenceAuthenticatorHkdfKeySize) { - return absl::InvalidArgumentError("Invalid shared credential hash size."); - } - for (const auto& local_credential : local_credentials) { - // Verify Credential ID hash. - auto cid_hash = crypto::HkdfSha256( - absl::StrCat(ukey2_secret, local_credential.key_seed()), kHkdfSalt, - kDiscovererHkdfInfo, kPresenceAuthenticatorHkdfKeySize); - if (crypto::SecureMemEqual(cid_hash.c_str(), - auth_data.shared_credential_hash.c_str(), - kPresenceAuthenticatorHkdfKeySize)) { - matched_local_credential = local_credential; - } - } - } else { - // two-way. we need to verify if the hash matches one of our local - // credentials _and_ make sure it matches one of our shared credentials. - // We want to check each shared credential to verify using its public key. - - // Match the local credential. - auto auth_data = absl::get(initiator_data); - if (auth_data.shared_credential_hash.size() != - kPresenceAuthenticatorHkdfKeySize) { - return absl::InvalidArgumentError("Invalid shared credential hash size."); - } - if (auth_data.private_key_signature.empty()) { - return absl::InvalidArgumentError("Empty private key signature."); - } - for (const auto& local_credential : local_credentials) { - // Verify Credential ID hash. - auto cid_hash = crypto::HkdfSha256( - absl::StrCat(ukey2_secret, local_credential.key_seed()), kHkdfSalt, - kDiscovererHkdfInfo, kPresenceAuthenticatorHkdfKeySize); - if (crypto::SecureMemEqual(cid_hash.c_str(), - auth_data.shared_credential_hash.c_str(), - kPresenceAuthenticatorHkdfKeySize)) { - matched_local_credential = local_credential; - } - } - // Now, match our shared credential. - std::optional matched_shared_credential; - for (const auto& shared_credential : shared_credentials) { - auto verifier = crypto::Ed25519Verifier::Create( - shared_credential.connection_signature_verification_key()); - if (!verifier.ok() || - verifier - ->Verify(absl::StrCat(kDiscovererMessageHeader, ukey2_secret), - auth_data.private_key_signature) - .ok()) { - matched_shared_credential = shared_credential; - break; - } - } - if (!matched_shared_credential.has_value()) { - return absl::InternalError("Unable to verify shared credential."); - } - } - if (matched_local_credential.has_value()) { - return *matched_local_credential; - } - return absl::InternalError("Unable to verify local credential."); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/connection_authenticator_impl.h b/presence/implementation/connection_authenticator_impl.h deleted file mode 100644 index 25f42ddc..00000000 --- a/presence/implementation/connection_authenticator_impl.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_IMPL_H_ - -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" -#include "presence/implementation/connection_authenticator.h" - -namespace nearby { -namespace presence { - -class ConnectionAuthenticatorImpl : public ConnectionAuthenticator { - public: - // Builds a signed message to be returned to Nearby Connections for - // authentication on the other side of the connection. - // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. - // local_credential - The local credential used to sign the derived - // information. If this is std::nullopt, then we will be - // performing one-way authentication. - // shared_credential - The shared credential used to decrypt the advertisement - // from the remote device. - absl::StatusOr BuildSignedMessageAsInitiator( - absl::string_view ukey2_secret, - std::optional local_credential, - const internal::SharedCredential& shared_credential) const override; - - // Builds a signed message to be returned to Nearby Connections for - // authentication on the other side of the connection. - // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. - // local_credential - The local credential used to sign the derived - // information so the initiator can verify against our - // shared credential. - absl::StatusOr BuildSignedMessageAsResponder( - absl::string_view ukey2_secret, - const internal::LocalCredential& local_credential) const override; - - // Verifies a signed message received from the responder (broadcaster) of the - // Nearby Presence advertisement. - // authentication_data - the data required to verify the connection, received - // from the responder. - // ukey2_secret - the shared secret derived from the ukey2 handshake in NC. - // shared_credentials - the set of shared credentials that can be used to - // verify the responder data. - absl::Status VerifyMessageAsInitiator( - ResponderData authentication_data, absl::string_view ukey2_secret, - const std::vector& shared_credentials) - const override; - - // Verifies a signed message received from the Nearby Connections peer. - // ukey2_secret - The shared secret derived from the UKEY2 handshake in NC. - // received_frame - The received frame from Nearby Connections. - // local_credentials - The set of local credentials that may contain the - // required keyseed hash. - // shared_credentials - The set of shared credentials that can be used to - // verify the signed contents of the frame. - absl::StatusOr VerifyMessageAsResponder( - absl::string_view ukey2_secret, InitiatorData initiator_data, - const std::vector& local_credentials, - const std::vector& shared_credentials) - const override; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CONNECTION_AUTHENTICATOR_IMPL_H_ diff --git a/presence/implementation/connection_authenticator_impl_test.cc b/presence/implementation/connection_authenticator_impl_test.cc deleted file mode 100644 index e28eb477..00000000 --- a/presence/implementation/connection_authenticator_impl_test.cc +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 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. -// 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 "presence/implementation/connection_authenticator_impl.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "internal/crypto/ed25519.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" - -namespace nearby { -namespace presence { -namespace { - -using ::protobuf_matchers::EqualsProto; -using ::testing::status::StatusIs; - -constexpr char kUkey2Secret[] = {0x34, 0x56, 0x78, 0x90}; -constexpr char kKeySeed1[] = {1, 2, 3, 4, 5, 6, 7, 8}; -constexpr char kKeySeed2[] = {8, 7, 6, 5, 4, 3, 2, 1}; - -internal::LocalCredential BuildLocalCredential( - const crypto::Ed25519KeyPair& key_pair, absl::string_view key_seed) { - internal::LocalCredential local_credential; - local_credential.mutable_connection_signing_key()->set_key( - absl::StrCat(key_pair.private_key, key_pair.public_key)); - local_credential.set_key_seed(key_seed); - return local_credential; -} - -internal::SharedCredential BuildSharedCredential( - const crypto::Ed25519KeyPair& key_pair, absl::string_view key_seed) { - internal::SharedCredential shared_credential; - shared_credential.set_connection_signature_verification_key( - key_pair.public_key); - shared_credential.set_key_seed(key_seed); - return shared_credential; -} - -class PresenceAuthenticatorTest : public ::testing::Test { - protected: - void SetUp() override { - auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair(); - ASSERT_OK_AND_ASSIGN(auto key_pair1, key_pair_or_status); - auto key_pair2_or_status = crypto::Ed25519Signer::CreateNewKeyPair(); - ASSERT_OK_AND_ASSIGN(auto key_pair2, key_pair2_or_status); - initiator_local_credential_ = BuildLocalCredential(key_pair1, kKeySeed1); - initiator_shared_credential_ = BuildSharedCredential(key_pair1, kKeySeed1); - initiator_shared_credential_wrong_key_ = - BuildSharedCredential(key_pair2, kKeySeed1); - responder_local_credential_ = BuildLocalCredential(key_pair2, kKeySeed2); - responder_shared_credential_ = BuildSharedCredential(key_pair2, kKeySeed2); - responder_shared_credential_wrong_key_ = - BuildSharedCredential(key_pair1, kKeySeed2); - } - - internal::LocalCredential initiator_local_credential_; - internal::LocalCredential responder_local_credential_; - internal::SharedCredential initiator_shared_credential_; - internal::SharedCredential initiator_shared_credential_wrong_key_; - internal::SharedCredential responder_shared_credential_; - internal::SharedCredential responder_shared_credential_wrong_key_; -}; - -TEST_F(PresenceAuthenticatorTest, TestTwoWayInitiatorSignResponderVerify) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, initiator_local_credential_, - responder_shared_credential_)); - auto local_credential = responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {responder_local_credential_}, - {initiator_shared_credential_}); - ASSERT_TRUE(local_credential.ok()); - EXPECT_THAT(*local_credential, EqualsProto(responder_local_credential_)); -} - -TEST_F(PresenceAuthenticatorTest, TestOneWayInitiatorSignResponderVerify) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN( - ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, std::nullopt, responder_shared_credential_)); - auto local_credential = responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {responder_local_credential_}, - {initiator_shared_credential_}); - ASSERT_TRUE(local_credential.ok()); - EXPECT_THAT(*local_credential, EqualsProto(responder_local_credential_)); -} - -TEST_F(PresenceAuthenticatorTest, TestResponderSignInitiatorVerify) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, - responder_authenticator.BuildSignedMessageAsResponder( - kUkey2Secret, responder_local_credential_)); - EXPECT_OK(initiator_authenticator.VerifyMessageAsInitiator( - auth_data, kUkey2Secret, {responder_shared_credential_})); -} - -TEST_F(PresenceAuthenticatorTest, - TestTwoWayInitiatorSignResponderVerifyNoSharedCredentialMatchFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, initiator_local_credential_, - responder_shared_credential_)); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {}, {initiator_shared_credential_}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestOneWayInitiatorSignResponderVerifyNoMatchCredentialFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN( - ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, std::nullopt, responder_shared_credential_)); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {}, {initiator_shared_credential_}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestOneWayInitiatorSignResponderVerifyNoCredentialFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN( - ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, std::nullopt, responder_shared_credential_)); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {}, {}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestTwoWayInitiatorSignResponderVerifyNoMatchCredentialFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, initiator_local_credential_, - responder_shared_credential_)); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {}, {initiator_shared_credential_}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestTwoWayInitiatorSignResponderVerifyWrongKeyFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, initiator_local_credential_, - responder_shared_credential_)); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {responder_local_credential_}, - {initiator_shared_credential_wrong_key_}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestResponderSignInitiatorVerifyNoMatchCredentialFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, - responder_authenticator.BuildSignedMessageAsResponder( - kUkey2Secret, responder_local_credential_)); - EXPECT_THAT(initiator_authenticator.VerifyMessageAsInitiator( - auth_data, kUkey2Secret, {}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestResponderSignInitiatorVerifyWrongKeyFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, - responder_authenticator.BuildSignedMessageAsResponder( - kUkey2Secret, responder_local_credential_)); - EXPECT_THAT( - initiator_authenticator.VerifyMessageAsInitiator( - auth_data, kUkey2Secret, {responder_shared_credential_wrong_key_}), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(PresenceAuthenticatorTest, - TestTwoWayInitiatorSignResponderVerifyNoCidHashFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, initiator_local_credential_, - responder_shared_credential_)); - std::get(auth_data) - .shared_credential_hash.clear(); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {responder_local_credential_}, - {initiator_shared_credential_wrong_key_}), - StatusIs(absl::StatusCode::kInvalidArgument)); -} - -TEST_F(PresenceAuthenticatorTest, - TestTwoWayInitiatorSignResponderVerifyNoPkeySigFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, initiator_local_credential_, - responder_shared_credential_)); - std::get(auth_data) - .private_key_signature.clear(); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {responder_local_credential_}, - {initiator_shared_credential_wrong_key_}), - StatusIs(absl::StatusCode::kInvalidArgument)); -} - -TEST_F(PresenceAuthenticatorTest, - TestOneWayInitiatorSignResponderVerifyNoCidHashFails) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN( - ConnectionAuthenticator::InitiatorData auth_data, - initiator_authenticator.BuildSignedMessageAsInitiator( - kUkey2Secret, std::nullopt, responder_shared_credential_)); - std::get(auth_data) - .shared_credential_hash.clear(); - EXPECT_THAT(responder_authenticator.VerifyMessageAsResponder( - kUkey2Secret, auth_data, {responder_local_credential_}, - {initiator_shared_credential_}), - StatusIs(absl::StatusCode::kInvalidArgument)); -} - -TEST_F(PresenceAuthenticatorTest, - TestResponderSignInitiatorVerifyNoPkeySigFail) { - ConnectionAuthenticatorImpl responder_authenticator; - ConnectionAuthenticatorImpl initiator_authenticator; - ASSERT_OK_AND_ASSIGN(ConnectionAuthenticator::ResponderData auth_data, - responder_authenticator.BuildSignedMessageAsResponder( - kUkey2Secret, responder_local_credential_)); - auth_data.private_key_signature.clear(); - EXPECT_THAT(initiator_authenticator.VerifyMessageAsInitiator( - auth_data, kUkey2Secret, {responder_shared_credential_}), - StatusIs(absl::StatusCode::kInvalidArgument)); -} -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/credential_manager.h b/presence/implementation/credential_manager.h deleted file mode 100644 index 2d4e088b..00000000 --- a/presence/implementation/credential_manager.h +++ /dev/null @@ -1,115 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_H_ - -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/metadata.pb.h" - -namespace nearby { -namespace presence { - -using SubscriberId = uint64_t; - -/* - * The instance of CredentialManager is owned by {@code ServiceControllerImpl}. - * Helping service controller to manage local credentials and coordinate with - * downloaded remote credentials. - */ -class CredentialManager { - public: - CredentialManager() = default; - virtual ~CredentialManager() = default; - - // Used to (re)generate user’s private and public credentials. - // The generated private credentials will be saved to creds storage. - // The generated public credentials will be returned inside the - // credentials_generated_cb for manager app to upload to web. - // The user’s own public credentials won’t be saved on local credential - // storage. - virtual void GenerateCredentials( - const nearby::internal::DeviceIdentityMetaData& device_identity_metadata, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) = 0; - - // Update remote public credentials. - virtual void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) = 0; - - virtual void UpdateLocalCredential( - const CredentialSelector& credential_selector, - nearby::internal::LocalCredential credential, - SaveCredentialsResultCallback result_callback) = 0; - - // Used to fetch private creds when broadcasting. - virtual void GetLocalCredentials( - const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) = 0; - - // Used to fetch local/remote public creds based on the value - // of public_credential_type. - virtual void GetPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) = 0; - - // Subscribes for public credentials updates. The `callback` is triggered when - // the public credentials are fetched initially, and then every time the - // credentials change. - virtual SubscriberId SubscribeForPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) = 0; - - // Unsubscribes from public credentials updates. No new callbacks will be - // triggered after this function returns. If there is a callback already - // running, that callback may continue after - // `UnsubscribeFromPublicCredentials()` return. - virtual void UnsubscribeFromPublicCredentials(SubscriberId id) = 0; - - // Decrypts the device identity metadata from a public credential. - // Returns an empty string if decryption fails. - virtual std::string DecryptDeviceIdentityMetaData( - absl::string_view metadata_encryption_key, absl::string_view key_seed, - absl::string_view metadata_string) = 0; - - // If `regen_credentials` is set to true, regenerating credentials. - virtual void SetDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) = 0; - - virtual ::nearby::internal::DeviceIdentityMetaData - GetDeviceIdentityMetaData() = 0; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_H_ diff --git a/presence/implementation/credential_manager_impl.cc b/presence/implementation/credential_manager_impl.cc deleted file mode 100644 index d49d2f56..00000000 --- a/presence/implementation/credential_manager_impl.cc +++ /dev/null @@ -1,834 +0,0 @@ -// 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 "presence/implementation/credential_manager_impl.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "absl/types/span.h" -#include "absl/types/variant.h" -#include "internal/crypto_cros/aead.h" -#include "internal/crypto_cros/ec_private_key.h" -#include "internal/crypto_cros/hkdf.h" -#include "internal/platform/base64_utils.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/crypto.h" -#include "internal/platform/future.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/implementation/crypto.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/logging.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" -#include "presence/data_types.h" -#include "presence/implementation/base_broadcast_request.h" -#include "presence/implementation/ldt.h" - -namespace nearby { -namespace presence { -namespace { -using ::nearby::Base64Utils; -using ::nearby::Crypto; -using ::nearby::Exception; -using ::nearby::ExceptionOr; -using ::nearby::Future; -using ::nearby::internal::IdentityType; -using ::nearby::internal::LocalCredential; -using ::nearby::internal::SharedCredential; - -// Key to retrieve local device's Private/Public Key Credentials from key store. -constexpr char kPairedKeyAliasPrefix[] = "nearby_presence_paired_key_alias_"; - -// Use an empty string because Chromium only supports 1 account. -// Windows & Apple will have their own Identity Provider. -constexpr absl::string_view kEmptyAccountName = ""; - -// The expected number of valid local credentials to be stored on local device. -constexpr int kExpectedValidLocalCredtialSize = 6; -// The expiration time in days for a credential. -constexpr int kCredentialLifeCycleDays = 5; -// The minimum size of bytes to generate credential id. -constexpr int kExpectedByteSizeOfCredentialId = 8; - -// Returns a random duration in [0, max_duration] range. -absl::Duration RandomDuration(absl::Duration max_duration) { - uint32_t random = nearby::RandData(); - return max_duration * random / std::numeric_limits::max(); -} - -std::string CustomizeBytesSize(absl::string_view bytes, size_t len) { - return crypto::HkdfSha256( - /*ikm=*/std::string(bytes), // NOLINT - /*salt=*/std::string(CredentialManagerImpl::kAuthenticityKeyByteSize, 0), - /*info=*/"", /*derived_key_size=*/len); -} - -} // namespace - -// Returns a positive long value extracted from a byte array. -int64_t GenerateIdFromByteArray(const ByteArray& input) { - size_t inputLength = input.size(); - - ByteArray processed_bytes(kExpectedByteSizeOfCredentialId); - // Only use first 8 bytes if the input is longer than 8 bytes. - if (inputLength > kExpectedByteSizeOfCredentialId) { - processed_bytes.CopyAt(0, input); - } else { - // Extend the input with zeros if it's shorter than 8 bytes - processed_bytes.CopyAt(kExpectedByteSizeOfCredentialId - inputLength, - input); - } - - int64_t id = 0; - for (int i = 0; i < kExpectedByteSizeOfCredentialId; ++i) { - id |= (static_cast(processed_bytes.data()[i]) << (8 * i)); - } - if (id == std::numeric_limits::min()) - return std::numeric_limits::max(); - return std::abs(id); -} - -void CredentialManagerImpl::GenerateCredentials( - const DeviceIdentityMetaData& device_identity_metadata, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) { - std::vector public_credentials; - std::vector private_credentials; - - for (auto identity_type : identity_types) { - absl::Time start_time = SystemClock::ElapsedRealtime(); - absl::Duration gap = credential_life_cycle_days * absl::Hours(24); - for (int index = 0; index < contiguous_copy_of_credentials; index++) { - auto public_private_credentials = - CreateLocalCredential(device_identity_metadata, identity_type, - start_time, start_time + gap); - if (public_private_credentials.second.identity_type() != - IdentityType::IDENTITY_TYPE_UNSPECIFIED) { - private_credentials.push_back(public_private_credentials.first); - public_credentials.push_back(public_private_credentials.second); - } - start_time += gap; - } - } - - // Create credential_storage object and invoke SaveCredentials. - credential_storage_ptr_->SaveCredentials( - manager_app_id, kEmptyAccountName, private_credentials, - public_credentials, PublicCredentialType::kLocalPublicCredential, - SaveCredentialsResultCallback{ - .credentials_saved_cb = - [this, manager_app_id = std::string(manager_app_id), - account_name = kEmptyAccountName, - callback = std::move(credentials_generated_cb), - public_credentials](absl::Status status) mutable { - if (!status.ok()) { - LOG(WARNING) << "Save credentials failed with: " << status; - std::move(callback.credentials_generated_cb)(status); - return; - } - std::move(callback.credentials_generated_cb)( - std::move(public_credentials)); - RunOnServiceControllerThread( - "local-creds-changed", - [this, manager_app_id = std::string(manager_app_id), - account_name = std::string(account_name)]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - OnCredentialsChanged( - manager_app_id, account_name, - PublicCredentialType::kLocalPublicCredential); - }); - }}); -} - -void CredentialManagerImpl::UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) { - credential_storage_ptr_->SaveCredentials( - manager_app_id, account_name, /* private_credentials */ {}, - remote_public_creds, PublicCredentialType::kRemotePublicCredential, - SaveCredentialsResultCallback{ - .credentials_saved_cb = - [this, manager_app_id = std::string(manager_app_id), - account_name = std::string(account_name), - callback = std::move(credentials_updated_cb)]( - absl::Status status) mutable { - if (!status.ok()) { - LOG(WARNING) - << "Update remote credentials failed with: " << status; - } else { - RunOnServiceControllerThread( - "remote-creds-changed", - [this, manager_app_id = std::string(manager_app_id), - account_name = std::string(account_name)]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - OnCredentialsChanged( - manager_app_id, account_name, - PublicCredentialType::kRemotePublicCredential); - }); - } - std::move(callback.credentials_updated_cb)(status); - }}); -} - -std::pair -CredentialManagerImpl::CreateLocalCredential( - const DeviceIdentityMetaData& device_identity_metadata, - IdentityType identity_type, absl::Time start_time, absl::Time end_time) { - LocalCredential private_credential; - private_credential.set_start_time_millis(absl::ToUnixMillis(start_time)); - private_credential.set_end_time_millis(absl::ToUnixMillis(end_time)); - private_credential.set_identity_type(identity_type); - - // Creates an AES key to encrypt the whole broadcast. - std::string secret_key(kAuthenticityKeyByteSize, 0); - RandBytes(const_cast(secret_key.data()), - secret_key.size()); - private_credential.set_key_seed(secret_key); - - // Uses SHA-256 algorithm to generate the credential ID from the - // authenticity key - auto secret_id = Crypto::Sha256(secret_key); - // Does not expect to fail here since Crypto::Sha256 should not return - // empty ByteArray. - CHECK(!secret_id.Empty()) << "Crypto::Sha256 failed!"; - - private_credential.set_id(GenerateIdFromByteArray(secret_id)); - - std::string alias = Base64Utils::Encode(secret_id); - auto prefixedAlias = kPairedKeyAliasPrefix + alias; - - // Generate key pair. Store the private key in private credential. - auto key_pair = crypto::ECPrivateKey::Create(); - std::vector private_key; - key_pair->ExportPrivateKey(&private_key); - private_credential.mutable_connection_signing_key()->set_key( - std::string(private_key.begin(), private_key.end())); - // Create an AES key to encrypt the device identity metadata. - std::string metadata_key(kBaseMetadataSize, 0); - RandBytes(const_cast(metadata_key.data()), - metadata_key.size()); - private_credential.set_metadata_encryption_key_v0(metadata_key); - - // Generate the public credential - std::vector public_key; - key_pair->ExportPublicKey(&public_key); - - return std::pair( - private_credential, - CreatePublicCredential(private_credential, device_identity_metadata, - public_key)); -} - -SharedCredential CredentialManagerImpl::CreatePublicCredential( - const LocalCredential& private_credential, - const DeviceIdentityMetaData& device_identity_metadata, - const std::vector& public_key) { - // The start time in the public credential should be decreased by a random - // value in 0 - 3 hours range. - // The end time should be increased by a random value in 0 - 3 hours range. - // This improves privacy by making it harder to correlate certificates. - absl::Time start_time = - absl::FromUnixMillis(private_credential.start_time_millis()) - - RandomDuration(absl::Hours(3)); - absl::Time end_time = - absl::FromUnixMillis(private_credential.end_time_millis()) + - RandomDuration(absl::Hours(3)); - SharedCredential public_credential; - public_credential.set_identity_type(private_credential.identity_type()); - public_credential.set_id(private_credential.id()); - public_credential.set_key_seed(private_credential.key_seed()); - public_credential.set_start_time_millis(absl::ToUnixMillis(start_time)); - public_credential.set_end_time_millis(absl::ToUnixMillis(end_time)); - // Set up the public key. Note, we are setting the "connection" key but we are - // not setting the "advertisement" key because the latter is not used yet. - public_credential.set_connection_signature_verification_key( - std::string(public_key.begin(), public_key.end())); - - auto metadata_encryption_key_tag = - Crypto::Sha256(private_credential.metadata_encryption_key_v0()); - public_credential.set_metadata_encryption_key_tag_v0( - std::string(metadata_encryption_key_tag.AsStringView())); - - auto encrypted_meta_data = EncryptDeviceIdentityMetaData( - private_credential.metadata_encryption_key_v0(), - private_credential.key_seed(), - device_identity_metadata.SerializeAsString()); - - if (encrypted_meta_data.empty()) { - LOG(ERROR) << "Fails to encrypt the device identity metadata."; - public_credential.set_identity_type( - IdentityType::IDENTITY_TYPE_UNSPECIFIED); - return public_credential; - } - - public_credential.set_encrypted_metadata_bytes_v0(encrypted_meta_data); - return public_credential; -} - -std::string CredentialManagerImpl::DecryptDeviceIdentityMetaData( - absl::string_view metadata_encryption_key, absl::string_view key_seed, - absl::string_view metadata_string) { - crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM); - - std::vector derived_key = - ExtendMetadataEncryptionKey(metadata_encryption_key); - aead.Init(derived_key); - - auto iv = CustomizeBytesSize(key_seed, CredentialManagerImpl::kAesGcmIVSize); - std::vector iv_bytes(iv.begin(), iv.end()); - std::vector encrypted_metadata_bytes(metadata_string.begin(), - metadata_string.end()); - - auto result = aead.Open(encrypted_metadata_bytes, - /*nonce=*/ - iv_bytes, - /*additional_data=*/absl::Span()); - - return std::string(result.value().begin(), result.value().end()); -} - -std::string CredentialManagerImpl::EncryptDeviceIdentityMetaData( - absl::string_view metadata_encryption_key, absl::string_view key_seed, - absl::string_view metadata_string) { - crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM); - - std::vector derived_key = - ExtendMetadataEncryptionKey(metadata_encryption_key); - - aead.Init(derived_key); - - auto iv = CustomizeBytesSize(key_seed, kAesGcmIVSize); - std::vector iv_bytes(iv.begin(), iv.end()); - - std::vector metadata_bytes(metadata_string.begin(), - metadata_string.end()); - metadata_bytes.resize(metadata_string.size()); - - auto encrypted = aead.Seal(metadata_bytes, - /*nonce=*/ - iv_bytes, - /*additional_data=*/absl::Span()); - - return std::string(encrypted.begin(), encrypted.end()); -} - -std::vector CredentialManagerImpl::ExtendMetadataEncryptionKey( - absl::string_view metadata_encryption_key) { - return crypto::HkdfSha256( - std::vector(metadata_encryption_key.begin(), - metadata_encryption_key.end()), - /*salt=*/absl::Span(), - /*info=*/absl::Span(), kNearbyPresenceNumBytesAesGcmKeySize); -} - -void CredentialManagerImpl::GetLocalCredentials( - const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - credential_storage_ptr_->GetLocalCredentials( - credential_selector, - GetLocalCredentialsResultCallback{ - .credentials_fetched_cb = - [this, credential_selector, callback = std::move(callback)]( - absl::StatusOr> - get_local_credentials_result) mutable { - if (!get_local_credentials_result.ok()) { - callback.credentials_fetched_cb( - get_local_credentials_result.status()); - return; - } - - CheckCredentialsAndRefillIfNeeded( - credential_selector, - /* credentials_list_variant */ - &get_local_credentials_result.value(), - /* callback_for_local_credentials */ - std::move(callback), - /* callback_for_shared_credentials */ - std::nullopt); - }, - }); -} - -void CredentialManagerImpl::GetPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) { - // Not going to refill for remote SharedCredentials. - if (public_credential_type == PublicCredentialType::kRemotePublicCredential) { - credential_storage_ptr_->GetPublicCredentials( - credential_selector, public_credential_type, std::move(callback)); - return; - } - - credential_storage_ptr_->GetPublicCredentials( - credential_selector, public_credential_type, - GetPublicCredentialsResultCallback{ - .credentials_fetched_cb = - [this, credential_selector, callback = std::move(callback)]( - absl::StatusOr> - get_shared_credentials_result) mutable { - if (!get_shared_credentials_result.ok()) { - callback.credentials_fetched_cb( - get_shared_credentials_result.status()); - return; - } - - CheckCredentialsAndRefillIfNeeded( - credential_selector, - /* credentials_list_variant */ - &get_shared_credentials_result.value(), - /* callback_for_local_credentials */ std::nullopt, - /* callback_for_shared_credentials */ - std::move(callback)); - }, - }); -} - -ExceptionOr> -CredentialManagerImpl::GetLocalCredentialsSync( - const CredentialSelector& credential_selector, absl::Duration timeout) { - Future> result; - GetLocalCredentials(credential_selector, - {.credentials_fetched_cb = - [result](absl::StatusOr> - credentials) mutable { - if (!credentials.ok()) { - result.SetException({Exception::kFailed}); - } else { - result.Set(std::move(*credentials)); - } - }}); - return result.Get(timeout); -} - -ExceptionOr> -CredentialManagerImpl::GetPublicCredentialsSync( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, absl::Duration timeout) { - Future> result; - GetPublicCredentials( - credential_selector, public_credential_type, - {.credentials_fetched_cb = - [result](absl::StatusOr> - credentials) mutable { - if (!credentials.ok()) { - result.SetException({Exception::kFailed}); - } else { - result.Set(std::move(*credentials)); - } - }}); - return result.Get(timeout); -} - -// TODO(b/326063431): The intent of this method is likely for -// GetPublicCredentials() to be called after the AddSubscriber() calls, but -// it's unlikely that this is happening on a real device. Manually verify. -SubscriberId CredentialManagerImpl::SubscribeForPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) { - SubscriberId id = nearby::RandData(); - RunOnServiceControllerThread( - "add-subscriber", - [this, key = SubscriberKey{credential_selector, public_credential_type}, - id, callback = std::move(callback)]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable { - AddSubscriber(key, id, std::move(callback)); - }); - GetPublicCredentials(credential_selector, public_credential_type, - CreateNotifySubscribersCallback( - {credential_selector, public_credential_type})); - return id; -} - -void CredentialManagerImpl::UnsubscribeFromPublicCredentials(SubscriberId id) { - RunOnServiceControllerThread("remove-subscriber", - [this, id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED( - *executor_) { RemoveSubscriber(id); }); -} - -void CredentialManagerImpl::AddSubscriber( - SubscriberKey key, SubscriberId id, - GetPublicCredentialsResultCallback callback) { - subscribers_[key].push_back(Subscriber(id, std::move(callback))); -} - -void CredentialManagerImpl::RemoveSubscriber(SubscriberId id) { - for (auto& entry : subscribers_) { - auto it = std::find_if( - entry.second.begin(), entry.second.end(), - [&](Subscriber& subscriber) { return subscriber.GetId() == id; }); - if (it != entry.second.end()) { - entry.second.erase(it); - if (subscribers_[entry.first].empty()) { - subscribers_.erase(entry.first); - } - return; - } - } -} - -absl::flat_hash_set -CredentialManagerImpl::GetSubscribedIdentities( - absl::string_view manager_app_id, absl::string_view account_name, - PublicCredentialType credential_type) const { - absl::flat_hash_set identities; - for (auto& entry : subscribers_) { - const SubscriberKey& key = entry.first; - if (key.public_credential_type == credential_type && - key.credential_selector.manager_app_id == manager_app_id && - key.credential_selector.account_name == account_name) { - identities.insert(key.credential_selector.identity_type); - } - } - return identities; -} - -void CredentialManagerImpl::OnCredentialsChanged( - absl::string_view manager_app_id, absl::string_view account_name, - PublicCredentialType credential_type) { - LOG(INFO) << "OnCredentialsChanged for app " << manager_app_id << ", account " - << account_name; - for (IdentityType identity_type : - GetSubscribedIdentities(manager_app_id, account_name, credential_type)) { - CredentialSelector credential_selector = { - .manager_app_id = std::string(manager_app_id), - .account_name = std::string(account_name), - .identity_type = identity_type}; - GetPublicCredentials(credential_selector, credential_type, - CreateNotifySubscribersCallback( - {credential_selector, credential_type})); - } -} - -GetPublicCredentialsResultCallback -CredentialManagerImpl::CreateNotifySubscribersCallback(SubscriberKey key) { - return GetPublicCredentialsResultCallback{ - .credentials_fetched_cb = - [this, - key](absl::StatusOr> credentials) { - if (!credentials.ok()) { - LOG(WARNING) << "Failed to get public credentials: error code: " - << credentials.status(); - return; - } - RunOnServiceControllerThread( - "notify-subscribers", - [this, key, credentials = std::move(*credentials)]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - NotifySubscribers(key, credentials); - }); - }}; -} - -void CredentialManagerImpl::NotifySubscribers( - const SubscriberKey& key, std::vector credentials) { - // We are on `executor_` thread, so we can iterate over `subscribers_` - // without locking. - auto it = subscribers_.find(key); - if (it == subscribers_.end()) { - LOG(WARNING) << "No subscribers for (app: " - << key.credential_selector.manager_app_id - << ", account: " << key.credential_selector.account_name - << ", identity type: " - << static_cast(key.credential_selector.identity_type) - << ", credential type: " - << static_cast(key.public_credential_type) << ")"; - return; - } - for (auto& subscriber : it->second) { - subscriber.NotifyCredentialsFetched(credentials); - } -} - -void CredentialManagerImpl::Subscriber::NotifyCredentialsFetched( - std::vector& credentials) { - callback_.credentials_fetched_cb(credentials); -} - -void CredentialManagerImpl::UpdateLocalCredential( - const CredentialSelector& credential_selector, - nearby::internal::LocalCredential credential, - SaveCredentialsResultCallback result_callback) { - credential_storage_ptr_->UpdateLocalCredential( - credential_selector.manager_app_id, credential_selector.account_name, - std::move(credential), std::move(result_callback)); -} - -void CredentialManagerImpl::CheckCredentialsAndRefillIfNeeded( - const CredentialSelector& credential_selector, - absl::variant*, - std::vector*> - credential_list_variant, - std::optional - callback_for_local_credentials, - std::optional - callback_for_shared_credentials) { - bool invoked_for_local = false; - int valid_credentials_count = 0; - int64_t current_time_millis = - absl::ToUnixMillis(SystemClock::ElapsedRealtime()); - int64_t last_valid_end_time_millis = current_time_millis; - - std::vector valid_local_credentials; - std::vector valid_shared_credentials; - if (absl::holds_alternative*>( - credential_list_variant) && - callback_for_local_credentials.has_value()) { - invoked_for_local = true; - for (auto& credential : - *absl::get*>( - credential_list_variant)) { - if (credential.end_time_millis() < current_time_millis) { - continue; - } - valid_credentials_count++; - if (last_valid_end_time_millis < credential.end_time_millis()) { - last_valid_end_time_millis = credential.end_time_millis(); - } - valid_local_credentials.push_back(credential); - } - } else if (absl::holds_alternative< - std::vector*>( - credential_list_variant) && - callback_for_shared_credentials.has_value()) { - for (auto& credential : - *absl::get*>( - credential_list_variant)) { - if (credential.end_time_millis() < current_time_millis) { - continue; - } - valid_credentials_count++; - if (last_valid_end_time_millis < credential.end_time_millis()) { - last_valid_end_time_millis = credential.end_time_millis(); - } - valid_shared_credentials.push_back(credential); - } - } else { - LOG(ERROR) << "Bad parameters for CheckCredentialsAndRefillIfNeeded"; - return; - } - - // Most invokes are expected to return early here as it already got enough - // valid credentials, no need to refill. - // Otherwise, the long process of refill (another read, merge, then save) - // would start. - if (valid_credentials_count >= kExpectedValidLocalCredtialSize) { - if (invoked_for_local) { - callback_for_local_credentials.value().credentials_fetched_cb( - valid_local_credentials); - } else { - callback_for_shared_credentials.value().credentials_fetched_cb( - valid_shared_credentials); - } - return; - } - - // Already got the valid credential list for either local or shared. - // Now get the other credentials list from storage, prune them, and begin - // the process of appending new credentials onto them. - if (invoked_for_local) { - credential_storage_ptr_->GetPublicCredentials( - credential_selector, PublicCredentialType::kLocalPublicCredential, - GetPublicCredentialsResultCallback{ - .credentials_fetched_cb = - [this, current_time_millis, last_valid_end_time_millis, - credential_selector, - valid_local_credentials = std::move(valid_local_credentials), - valid_shared_credentials = std::move(valid_shared_credentials), - callback_for_local_credentials = - std::move(callback_for_local_credentials), - callback_for_shared_credentials = - std::move(callback_for_shared_credentials)]( - absl::StatusOr< - std::vector> - result) mutable { - if (!result.ok()) { - callback_for_local_credentials.value() - .credentials_fetched_cb(result.status()); - return; - } - for (const auto& credential : result.value()) { - if (credential.end_time_millis() >= current_time_millis) { - valid_shared_credentials.push_back(credential); - } - } - - RefillRemainingValidCredentialsWithNewCredentials( - credential_selector, valid_local_credentials, - valid_shared_credentials, - /*start_time_to_generate_new_credentials_millis=*/ - last_valid_end_time_millis, - std::move(callback_for_local_credentials), - std::move(callback_for_shared_credentials)); - }, - }); - } else { - credential_storage_ptr_->GetLocalCredentials( - credential_selector, - GetLocalCredentialsResultCallback{ - .credentials_fetched_cb = - [this, current_time_millis, last_valid_end_time_millis, - credential_selector, - valid_local_credentials = std::move(valid_local_credentials), - valid_shared_credentials = std::move(valid_shared_credentials), - callback_for_local_credentials = - std::move(callback_for_local_credentials), - callback_for_shared_credentials = - std::move(callback_for_shared_credentials)]( - absl::StatusOr< - std::vector> - result) mutable { - if (!result.ok()) { - callback_for_local_credentials.value() - .credentials_fetched_cb(result.status()); - return; - } - for (const auto& credential : result.value()) { - if (credential.end_time_millis() >= current_time_millis) { - valid_local_credentials.push_back( - credential); // RESTORE TODO - } - } - - RefillRemainingValidCredentialsWithNewCredentials( - credential_selector, valid_local_credentials, - valid_shared_credentials, - /*start_time_to_generate_new_credentials_millis=*/ - last_valid_end_time_millis, - std::move(callback_for_local_credentials), - std::move(callback_for_shared_credentials)); - }, - }); - } -} - -void CredentialManagerImpl::RefillRemainingValidCredentialsWithNewCredentials( - const CredentialSelector& credential_selector, - std::vector valid_local_credentials, - std::vector valid_shared_credentials, - int64_t start_time_to_generate_new_credentials_millis, - std::optional - callback_for_local_credentials, - std::optional - callback_for_shared_credentials) { - // The number of valid credentials has already been determined by pruning - // valid_local_credentials and valid_shared_credentials. They must match - // in size. - int valid_credentials_count = valid_local_credentials.size(); - CHECK_EQ(valid_credentials_count, valid_shared_credentials.size()); - - std::vector newly_generated_local_credentials; - std::vector newly_generated_shared_credentials; - - // Generate more credential pairs to refill the expired ones. - auto start_time = - absl::FromUnixMillis(start_time_to_generate_new_credentials_millis); - auto gap = kCredentialLifeCycleDays * absl::Hours(24); - for (int i = 0; i < kExpectedValidLocalCredtialSize - valid_credentials_count; - i++) { - auto pair = CreateLocalCredential(device_identity_metadata_, - credential_selector.identity_type, - start_time, start_time + gap); - newly_generated_local_credentials.push_back(std::move(pair.first)); - newly_generated_shared_credentials.push_back(std::move(pair.second)); - start_time += gap; - } - - // Now merge newly generated credentials to already existing valid ones. - valid_local_credentials.insert(valid_local_credentials.end(), - newly_generated_local_credentials.begin(), - newly_generated_local_credentials.end()); - valid_shared_credentials.insert(valid_shared_credentials.end(), - newly_generated_shared_credentials.begin(), - newly_generated_shared_credentials.end()); - - // Save merged local and shared credential lists to storage - credential_storage_ptr_->SaveCredentials( - credential_selector.manager_app_id, credential_selector.account_name, - valid_local_credentials, valid_shared_credentials, - PublicCredentialType::kLocalPublicCredential, - SaveCredentialsResultCallback{ - .credentials_saved_cb = - [this, valid_local_credentials, valid_shared_credentials, - callback_for_local_credentials = - std::move(callback_for_local_credentials), - callback_for_shared_credentials = - std::move(callback_for_shared_credentials)]( - absl::Status status) mutable { - OnCredentialRefillComplete( - std::move(status), valid_local_credentials, - valid_shared_credentials, - std::move(callback_for_local_credentials), - std::move(callback_for_shared_credentials)); - }, - }); -} - -void CredentialManagerImpl::OnCredentialRefillComplete( - absl::Status save_credentials_status, - std::vector valid_local_credentials, - std::vector valid_shared_credentials, - std::optional - callback_for_local_credentials, - std::optional - callback_for_shared_credentials) { - if (!save_credentials_status.ok()) { - LOG(ERROR) << "Save credentials failed with: " << save_credentials_status; - if (callback_for_local_credentials.has_value()) { - callback_for_local_credentials.value().credentials_fetched_cb( - save_credentials_status); - } else { - callback_for_shared_credentials.value().credentials_fetched_cb( - save_credentials_status); - } - return; - } - - if (callback_for_local_credentials.has_value()) { - callback_for_local_credentials.value().credentials_fetched_cb( - valid_local_credentials); - } else { - callback_for_shared_credentials.value().credentials_fetched_cb( - valid_shared_credentials); - } -} - -bool CredentialManagerImpl::WaitForLatch(absl::string_view method_name, - CountDownLatch* latch) { - Exception await_exception = latch->Await(); - if (!await_exception.Ok()) { - LOG(ERROR) << "Blocked in " << method_name - << " with exeception code: " << await_exception.value; - return false; - } - return true; -} -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/credential_manager_impl.h b/presence/implementation/credential_manager_impl.h deleted file mode 100644 index 9cd2c99e..00000000 --- a/presence/implementation/credential_manager_impl.h +++ /dev/null @@ -1,262 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_ - -#include -#include -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/log/die_if_null.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "absl/types/variant.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/credential_storage_impl.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/runnable.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/metadata.pb.h" -#include "presence/implementation/credential_manager.h" - -namespace nearby { -namespace presence { - -class CredentialManagerImpl : public CredentialManager { - public: - using IdentityType = ::nearby::internal::IdentityType; - using DeviceIdentityMetaData = ::nearby::internal::DeviceIdentityMetaData; - - explicit CredentialManagerImpl(SingleThreadExecutor* executor) - : executor_(ABSL_DIE_IF_NULL(executor)) { - credential_storage_ptr_ = std::make_unique(); - } - - // Test purpose only. - CredentialManagerImpl( - SingleThreadExecutor* executor, - std::unique_ptr credential_storage_ptr) - : executor_(ABSL_DIE_IF_NULL(executor)), - credential_storage_ptr_(std::move(credential_storage_ptr)) {} - - // AES only supports key sizes of 16, 24 or 32 bytes. - static constexpr int kAuthenticityKeyByteSize = 32; - - // Length of key in bytes required by AES-GCM encryption. - static constexpr size_t kNearbyPresenceNumBytesAesGcmKeySize = 32; - - // Modify this to 12 after use real AES. - static constexpr int kAesGcmIVSize = 12; - - void GenerateCredentials( - const DeviceIdentityMetaData& device_identity_metadata, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) override; - - void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) override; - - void UpdateLocalCredential( - const CredentialSelector& credential_selector, - nearby::internal::LocalCredential credential, - SaveCredentialsResultCallback result_callback) override; - - void GetLocalCredentials(const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) override; - - // Blocking version of `GetLocalCredentials` - nearby::ExceptionOr> - GetLocalCredentialsSync(const CredentialSelector& credential_selector, - absl::Duration timeout); - - // Used to fetch local/remote public creds based on the value of - // public_credential_type. - void GetPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) override; - - // Blocking version of `GetPublicCredentials`. - ::nearby::ExceptionOr> - GetPublicCredentialsSync(const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - absl::Duration timeout); - - SubscriberId SubscribeForPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) override; - - void UnsubscribeFromPublicCredentials(SubscriberId id) override; - - std::string DecryptDeviceIdentityMetaData( - absl::string_view metadata_encryption_key, absl::string_view key_seed, - absl::string_view metadata_string) override; - - std::pair - CreateLocalCredential(const DeviceIdentityMetaData& device_identity_metadata, - IdentityType identity_type, absl::Time start_time, - absl::Time end_time); - - nearby::internal::SharedCredential CreatePublicCredential( - const nearby::internal::LocalCredential& private_credential, - const DeviceIdentityMetaData& device_identity_metadata, - const std::vector& public_key); - - virtual std::string EncryptDeviceIdentityMetaData( - absl::string_view metadata_encryption_key, absl::string_view key_seed, - absl::string_view metadata_string); - - // Extend the key from 16 bytes to 32 bytes. - std::vector ExtendMetadataEncryptionKey( - absl::string_view metadata_encryption_key); - - void SetDeviceIdentityMetaData( - const DeviceIdentityMetaData& device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) override { - device_identity_metadata_ = device_identity_metadata; - if (regen_credentials) { - GenerateCredentials(device_identity_metadata, manager_app_id, - identity_types, credential_life_cycle_days, - contiguous_copy_of_credentials, - std::move(credentials_generated_cb)); - } - } - - ::nearby::internal::DeviceIdentityMetaData GetDeviceIdentityMetaData() - override { - return device_identity_metadata_; - } - - private: - struct SubscriberKey { - CredentialSelector credential_selector; - PublicCredentialType public_credential_type; - template - friend H AbslHashValue(H h, const SubscriberKey& key) { - return H::combine(std::move(h), key.credential_selector, - key.public_credential_type); - } - friend bool operator==(const SubscriberKey& a, const SubscriberKey& b) { - return a.public_credential_type == b.public_credential_type && - a.credential_selector == b.credential_selector; - } - }; - class Subscriber { - public: - Subscriber(SubscriberId id, GetPublicCredentialsResultCallback callback) - : callback_(std::move(callback)), id_(id) {} - - SubscriberId GetId() const { return id_; } - - // Notifies the subscriber about fetched credentials. - void NotifyCredentialsFetched( - std::vector<::nearby::internal::SharedCredential>& credentials); - - private: - GetPublicCredentialsResultCallback callback_; - SubscriberId id_; - }; - - void RunOnServiceControllerThread(absl::string_view name, - Runnable&& runnable) { - executor_->Execute(std::string(name), std::move(runnable)); - } - - bool WaitForLatch(absl::string_view method_name, CountDownLatch* latch); - - // The similar flow to check-expired-then-refill-if-needed is needed in both - // GetLocalCredentials() and GetPublicCredentials(). The high level flow is: - // check if there're expired creds from the result credentials list from - // GetLocal/GetPublic, if some creds expired, prune the expired, merge with - // newly generated ones. Then get the corresponding(local/shared) creds list - // from the storage, also prune expired, merge with newly - // generated. Then finally, save the newly merged two lists (local & shared) - // to storage. For re-use purpose, this private function is made to be able - // to take in different parameters from both GetLocalCredentials() and - // GetPublicCredentials(). - void CheckCredentialsAndRefillIfNeeded( - const CredentialSelector& credential_selector, - absl::variant*, - std::vector*> - credential_list_variant, - std::optional - callback_for_local_credentials, - std::optional - callback_for_shared_credentials); - void RefillRemainingValidCredentialsWithNewCredentials( - const CredentialSelector& credential_selector, - std::vector valid_local_credentials, - std::vector valid_shared_credentials, - int64_t start_time_to_generate_new_credentials_millis, - std::optional - callback_for_local_credentials, - std::optional - callback_for_shared_credentials); - void OnCredentialRefillComplete( - absl::Status save_credentials_status, - std::vector valid_local_credentials, - std::vector valid_shared_credentials, - std::optional - callback_for_local_credentials, - std::optional - callback_for_shared_credentials); - - void OnCredentialsChanged(absl::string_view manager_app_id, - absl::string_view account_name, - PublicCredentialType credential_type) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void NotifySubscribers( - const SubscriberKey& key, - std::vector<::nearby::internal::SharedCredential> credentials) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void AddSubscriber(SubscriberKey key, SubscriberId id, - GetPublicCredentialsResultCallback callback) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void RemoveSubscriber(SubscriberId id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - absl::flat_hash_set GetSubscribedIdentities( - absl::string_view manager_app_id, absl::string_view account_name, - PublicCredentialType credential_type) const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - GetPublicCredentialsResultCallback CreateNotifySubscribersCallback( - SubscriberKey key); - - absl::flat_hash_map> subscribers_ - ABSL_GUARDED_BY(*executor_); - SingleThreadExecutor* executor_; - std::unique_ptr credential_storage_ptr_; - DeviceIdentityMetaData device_identity_metadata_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_CREDENTIAL_MANAGER_IMPL_H_ diff --git a/presence/implementation/credential_manager_impl_test.cc b/presence/implementation/credential_manager_impl_test.cc deleted file mode 100644 index 44d37659..00000000 --- a/presence/implementation/credential_manager_impl_test.cc +++ /dev/null @@ -1,721 +0,0 @@ -// 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 "presence/implementation/credential_manager_impl.h" - -#include -#include -#include -#include -#include - -#include "net/proto2/contrib/parse_proto/testing.h" -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/credential_storage_impl.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/implementation/crypto.h" -#include "internal/platform/logging.h" -#include "internal/platform/medium_environment.h" -#include "internal/proto/credential.pb.h" -#include "presence/implementation/base_broadcast_request.h" - -namespace nearby { -namespace presence { -namespace { -using ::nearby::CountDownLatch; -using ::nearby::Crypto; -using ::nearby::MediumEnvironment; -using ::nearby::internal::IdentityType; -using ::nearby::internal::LocalCredential; - -using ::nearby::internal::DeviceIdentityMetaData; -using ::nearby::internal::SharedCredential; -using ::nearby::internal::IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; -using ::nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; -using ::protobuf_matchers::EqualsProto; -using ::testing::UnorderedPointwise; -using ::testing::status::StatusIs; - -constexpr absl::string_view kManagerAppId = "TEST_MANAGER_APP"; -constexpr absl::string_view kAccountName = ""; -constexpr int kExpectedPresenceCredentialListSize = 6; -constexpr int kExpectedPresenceCredentialValidDays = 5; - -DeviceIdentityMetaData CreateTestDeviceIdentityMetaData() { - DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_device_type( - internal::DeviceType::DEVICE_TYPE_PHONE); - device_identity_metadata.set_device_name("NP test device"); - device_identity_metadata.set_bluetooth_mac_address("FF:FF:FF:FF:FF:FF"); - device_identity_metadata.set_device_id("\x12\xab\xcd"); - return device_identity_metadata; -} - -CredentialSelector BuildDefaultCredentialSelector() { - CredentialSelector credential_selector; - credential_selector.manager_app_id = std::string(kManagerAppId); - credential_selector.account_name = std::string(kAccountName); - credential_selector.identity_type = IDENTITY_TYPE_PRIVATE_GROUP; - return credential_selector; -} - -class CredentialManagerImplTest : public ::testing::Test { - public: - class MockCredentialStorage : public nearby::CredentialStorageImpl { - public: - MOCK_METHOD(void, SaveCredentials, - (absl::string_view manager_app_id, - absl::string_view account_name, - const std::vector& private_credentials, - const std::vector& public_credentials, - PublicCredentialType public_credential_type, - SaveCredentialsResultCallback callback), - (override)); - MOCK_METHOD( - void, GetPublicCredentials, - (const ::nearby::presence::CredentialSelector& credential_selector, - ::nearby::presence::PublicCredentialType public_credential_type, - ::nearby::presence::GetPublicCredentialsResultCallback callback), - (override)); - }; - - class FakeCredentialStorage : public nearby::CredentialStorageImpl { - public: - // nearby::CredentialStorageImpl: - void SaveCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& private_credentials, - const std::vector& public_credentials, - PublicCredentialType public_credential_type, - SaveCredentialsResultCallback callback) override { - // Capture the credentials before actually saving them, so that they - // can be manipulated later on. - private_credentials_ = private_credentials; - public_credentials_ = public_credentials; - - nearby::CredentialStorageImpl::SaveCredentials( - manager_app_id, account_name, private_credentials, public_credentials, - public_credential_type, std::move(callback)); - } - void GetLocalCredentials( - const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) override { - if (private_credentials_.has_value()) { - callback.credentials_fetched_cb(private_credentials_.value()); - } else { - nearby::CredentialStorageImpl::GetLocalCredentials(credential_selector, - std::move(callback)); - } - } - void GetPublicCredentials( - const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) override { - if (public_credentials_.has_value()) { - callback.credentials_fetched_cb(public_credentials_.value()); - } else { - nearby::CredentialStorageImpl::GetPublicCredentials( - credential_selector, public_credential_type, std::move(callback)); - } - } - - std::optional> - public_credentials_; - std::optional> - private_credentials_; - }; - - class MockCredentialManager : public CredentialManagerImpl { - public: - explicit MockCredentialManager(SingleThreadExecutor* executor) - : CredentialManagerImpl(executor) {} - MOCK_METHOD(std::string, EncryptDeviceIdentityMetaData, - (absl::string_view metadata_encryption_key, - absl::string_view key_seed, absl::string_view metadata_string), - (override)); - }; - - ~CredentialManagerImplTest() override { executor_.Shutdown(); } - - // Waits for active tasks in the background thread to complete. - void Fence() { - // A runnable on medium environment thread can add a task on "our" executor, - // and vice-versa. We need to wait for tasks on both threads in a loop a few - // times to make sure that all tasks have finished. - for (int i = 0; i < 3; i++) { - MediumEnvironment::Instance().Sync(); - CountDownLatch latch(1); - executor_.Execute([&]() { latch.CountDown(); }); - latch.Await(); - } - } - - void AddLocalIdentity(absl::string_view manager_app_id, - absl::string_view account_name, - IdentityType identity_type) { - auto public_credentials = GenerateCredentialsSync( - CreateTestDeviceIdentityMetaData(), manager_app_id, {identity_type}, - /*credential_life_cycle_days=*/kExpectedPresenceCredentialValidDays, - /*contiguous_copy_of_credentials=*/1); - EXPECT_OK(public_credentials); - } - - absl::StatusOr> GenerateCredentialsSync( - const DeviceIdentityMetaData& device_identity_metadata, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials) { - absl::StatusOr> public_credentials; - - CountDownLatch latch(1); - credential_manager_.GenerateCredentials( - device_identity_metadata, manager_app_id, identity_types, - credential_life_cycle_days, contiguous_copy_of_credentials, - {.credentials_generated_cb = - [&](absl::StatusOr> credentials) { - public_credentials = credentials; - latch.CountDown(); - }}); - EXPECT_TRUE(latch.Await().Ok()); - - return public_credentials; - } - - std::vector GetLocalCredentialsSync( - CredentialSelector credential_selector) { - auto private_credentials = credential_manager_.GetLocalCredentialsSync( - credential_selector, absl::Seconds(1)); - EXPECT_TRUE(private_credentials.ok()); - return private_credentials.GetResult(); - } - - std::vector GetPublicCredentialsSync( - CredentialSelector credential_selector, - PublicCredentialType public_credential_type) { - auto public_credentials = credential_manager_.GetPublicCredentialsSync( - credential_selector, public_credential_type, absl::Seconds(1)); - EXPECT_TRUE(public_credentials.ok()); - return public_credentials.GetResult(); - } - - protected: - SingleThreadExecutor executor_; - CredentialManagerImpl credential_manager_{&executor_}; - MockCredentialManager mock_credential_manager_{&executor_}; -}; - -TEST_F(CredentialManagerImplTest, CreateOneCredentialSuccessfully) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - constexpr absl::Time kStartTime = absl::FromUnixSeconds(100000); - constexpr absl::Time kEndTime = absl::FromUnixSeconds(200000); - - auto credentials = credential_manager_.CreateLocalCredential( - device_identity_metadata, IDENTITY_TYPE_PRIVATE_GROUP, kStartTime, - kEndTime); - - LocalCredential private_credential = credentials.first; - // Verify the private credential. - EXPECT_EQ(private_credential.identity_type(), IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_NE(private_credential.id(), 0); - EXPECT_EQ(private_credential.start_time_millis(), - absl::ToUnixMillis(kStartTime)); - EXPECT_EQ(private_credential.end_time_millis(), absl::ToUnixMillis(kEndTime)); - EXPECT_EQ(private_credential.key_seed().size(), - CredentialManagerImpl::kAuthenticityKeyByteSize); - EXPECT_FALSE(private_credential.connection_signing_key().key().empty()); - EXPECT_EQ(private_credential.metadata_encryption_key_v0().size(), - kBaseMetadataSize); - - SharedCredential public_credential = credentials.second; - // Verify the public credential. - EXPECT_EQ(public_credential.identity_type(), IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_NE(public_credential.id(), 0); - EXPECT_EQ(private_credential.id(), public_credential.id()); - EXPECT_EQ(private_credential.key_seed(), public_credential.key_seed()); - EXPECT_LE(public_credential.start_time_millis(), - absl::ToUnixMillis(kStartTime)); - EXPECT_GE(public_credential.start_time_millis(), - absl::ToUnixMillis(kStartTime - absl::Hours(3))); - EXPECT_GE(public_credential.end_time_millis(), absl::ToUnixMillis(kEndTime)); - EXPECT_LE(public_credential.end_time_millis(), - absl::ToUnixMillis(kEndTime + absl::Hours(3))); - EXPECT_EQ(Crypto::Sha256(private_credential.metadata_encryption_key_v0()) - .AsStringView(), - public_credential.metadata_encryption_key_tag_v0()); - EXPECT_FALSE( - public_credential.connection_signature_verification_key().empty()); - EXPECT_FALSE(public_credential.encrypted_metadata_bytes_v0().empty()); - - auto decrypted_metadata = credential_manager_.DecryptDeviceIdentityMetaData( - private_credential.metadata_encryption_key_v0(), - public_credential.key_seed(), - public_credential.encrypted_metadata_bytes_v0()); - - EXPECT_EQ(device_identity_metadata.SerializeAsString(), decrypted_metadata); -} - -TEST_F(CredentialManagerImplTest, GenerateCredentialsSuccessfully) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - std::vector identityTypes{IDENTITY_TYPE_PRIVATE_GROUP}; - absl::Time previous_start_time; - absl::Time previous_end_time; - - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identityTypes, - kExpectedPresenceCredentialValidDays, - kExpectedPresenceCredentialListSize); - EXPECT_OK(public_credentials); - EXPECT_EQ(public_credentials->size(), kExpectedPresenceCredentialListSize); - - for (int i = 0; i < kExpectedPresenceCredentialListSize; i++) { - SharedCredential& public_credential = public_credentials->at(i); - EXPECT_EQ(public_credential.identity_type(), IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_NE(public_credential.id(), 0); - absl::Time start_time_millis = - absl::FromUnixMillis(public_credential.start_time_millis()); - absl::Time end_time_millis = - absl::FromUnixMillis(public_credential.end_time_millis()); - if (i > 0) { - EXPECT_GT(start_time_millis, previous_start_time); - EXPECT_GE(previous_end_time, start_time_millis); - EXPECT_GT(end_time_millis, previous_end_time); - } - EXPECT_LT(start_time_millis + - absl::Hours(24) * kExpectedPresenceCredentialValidDays, - end_time_millis); - EXPECT_FALSE(public_credential.encrypted_metadata_bytes_v0().empty()); - previous_start_time = start_time_millis; - previous_end_time = end_time_millis; - } -} - -TEST_F(CredentialManagerImplTest, - SubscribeCallsCallbackWithExistingCredentials) { - absl::StatusOr> public_credentials1; - absl::StatusOr> public_credentials2; - AddLocalIdentity(kManagerAppId, kAccountName, IDENTITY_TYPE_PRIVATE_GROUP); - - SubscriberId id1 = credential_manager_.SubscribeForPublicCredentials( - CredentialSelector{.manager_app_id = std::string(kManagerAppId), - .account_name = std::string(kAccountName), - .identity_type = IDENTITY_TYPE_PRIVATE_GROUP}, - PublicCredentialType::kLocalPublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - public_credentials1 = std::move(credentials); - }}); - SubscriberId id2 = credential_manager_.SubscribeForPublicCredentials( - CredentialSelector{.manager_app_id = std::string(kManagerAppId), - .account_name = std::string(kAccountName), - .identity_type = IDENTITY_TYPE_PRIVATE_GROUP}, - PublicCredentialType::kLocalPublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - public_credentials2 = std::move(credentials); - }}); - - Fence(); - EXPECT_OK(public_credentials1); - EXPECT_OK(public_credentials2); - EXPECT_EQ(public_credentials1->size(), kExpectedPresenceCredentialListSize); - EXPECT_EQ(public_credentials2->size(), kExpectedPresenceCredentialListSize); - // Cleanup - credential_manager_.UnsubscribeFromPublicCredentials(id1); - credential_manager_.UnsubscribeFromPublicCredentials(id2); - Fence(); -} - -TEST_F(CredentialManagerImplTest, - SubscribeCallsCallbackWithUpdatedCredentials) { - absl::StatusOr> public_credentials; - - SubscriberId id = credential_manager_.SubscribeForPublicCredentials( - CredentialSelector{.manager_app_id = std::string(kManagerAppId), - .account_name = std::string(kAccountName), - .identity_type = IDENTITY_TYPE_PRIVATE_GROUP}, - PublicCredentialType::kLocalPublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - public_credentials = std::move(credentials); - }}); - Fence(); - EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kUnknown)); - - AddLocalIdentity(kManagerAppId, kAccountName, IDENTITY_TYPE_PRIVATE_GROUP); - - Fence(); - ASSERT_OK(public_credentials); - EXPECT_EQ(public_credentials->size(), kExpectedPresenceCredentialListSize); - // Cleanup - credential_manager_.UnsubscribeFromPublicCredentials(id); - Fence(); -} - -TEST_F(CredentialManagerImplTest, NoCallbacksAfterUnsubscribe) { - absl::StatusOr> public_credentials; - SubscriberId id = credential_manager_.SubscribeForPublicCredentials( - CredentialSelector{.manager_app_id = std::string(kManagerAppId), - .account_name = std::string(kAccountName), - .identity_type = IDENTITY_TYPE_PRIVATE_GROUP}, - PublicCredentialType::kLocalPublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - public_credentials = std::move(credentials); - }}); - - credential_manager_.UnsubscribeFromPublicCredentials(id); - AddLocalIdentity(kManagerAppId, kAccountName, IDENTITY_TYPE_PRIVATE_GROUP); - - Fence(); - EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kUnknown)); -} - -TEST_F(CredentialManagerImplTest, - GenerateCredentialsSuccessfullyButStoreFailed) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - auto credential_storage_ptr = - std::make_unique(); - EXPECT_CALL(*credential_storage_ptr, SaveCredentials) - .WillOnce(::testing::Invoke( - [](absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& private_credentials, - const std::vector& public_credentials, - PublicCredentialType public_credential_type, - SaveCredentialsResultCallback callback) { - callback.credentials_saved_cb( - absl::FailedPreconditionError("Expected failure")); - })); - credential_manager_ = - CredentialManagerImpl(&executor_, std::move(credential_storage_ptr)); - std::vector identityTypes{IDENTITY_TYPE_PRIVATE_GROUP}; - - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identityTypes, - kExpectedPresenceCredentialValidDays, - kExpectedPresenceCredentialListSize); - EXPECT_THAT(public_credentials, - StatusIs(absl::StatusCode::kFailedPrecondition)); -} - -TEST_F(CredentialManagerImplTest, UpdateRemotePublicCredentialsSuccessfully) { - SharedCredential public_credential_for_test; - public_credential_for_test.set_identity_type( - IdentityType::IDENTITY_TYPE_CONTACTS_GROUP); - std::vector public_credentials{ - {public_credential_for_test}}; - - nearby::CountDownLatch updated_latch(1); - UpdateRemotePublicCredentialsCallback update_credentials_cb{ - .credentials_updated_cb = - [&updated_latch](absl::Status status) { - if (status.ok()) { - updated_latch.CountDown(); - } - }, - }; - - credential_manager_.UpdateRemotePublicCredentials( - kManagerAppId, kAccountName, public_credentials, - std::move(update_credentials_cb)); - - EXPECT_TRUE(updated_latch.Await().Ok()); -} - -TEST_F(CredentialManagerImplTest, - UpdateRemotePublicCredentialsNotifiesSubscribers) { - absl::StatusOr> subscribed_credentials; - SharedCredential public_credential_for_test; - public_credential_for_test.set_identity_type( - IdentityType::IDENTITY_TYPE_PRIVATE_GROUP); - std::vector public_credentials{ - {public_credential_for_test}}; - nearby::CountDownLatch updated_latch(1); - UpdateRemotePublicCredentialsCallback update_credentials_cb{ - .credentials_updated_cb = - [&updated_latch](absl::Status status) { - if (status.ok()) { - updated_latch.CountDown(); - } - }, - }; - SubscriberId id1 = credential_manager_.SubscribeForPublicCredentials( - CredentialSelector{ - .manager_app_id = std::string(kManagerAppId), - .account_name = std::string(kAccountName), - .identity_type = internal::IDENTITY_TYPE_PRIVATE_GROUP}, - PublicCredentialType::kRemotePublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - subscribed_credentials = std::move(credentials); - }}); - SubscriberId id2 = credential_manager_.SubscribeForPublicCredentials( - CredentialSelector{ - .manager_app_id = std::string(kManagerAppId), - .account_name = std::string(kAccountName), - .identity_type = internal::IDENTITY_TYPE_CONTACTS_GROUP}, - PublicCredentialType::kRemotePublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - // This callback should not be called because there are no Trusted - // credentials in this test. - GTEST_FAIL(); - }}); - - credential_manager_.UpdateRemotePublicCredentials( - kManagerAppId, kAccountName, public_credentials, - std::move(update_credentials_cb)); - - EXPECT_TRUE(updated_latch.Await().Ok()); - Fence(); - EXPECT_OK(subscribed_credentials); - EXPECT_EQ(subscribed_credentials->size(), 1); - credential_manager_.UnsubscribeFromPublicCredentials(id1); - credential_manager_.UnsubscribeFromPublicCredentials(id2); -} - -TEST_F(CredentialManagerImplTest, GetLocalCredentialsFailed) { - absl::StatusOr> private_credentials; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - credential_manager_.GetLocalCredentials( - credential_selector, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - private_credentials = std::move(credentials); - }}); - - EXPECT_THAT(private_credentials, StatusIs(absl::StatusCode::kNotFound)); -} - -TEST_F(CredentialManagerImplTest, GetPublicCredentialsFailed) { - absl::StatusOr> public_credentials; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - CountDownLatch latch(1); - credential_manager_.GetPublicCredentials( - credential_selector, PublicCredentialType::kLocalPublicCredential, - {.credentials_fetched_cb = - [&](absl::StatusOr> credentials) { - public_credentials = std::move(credentials); - latch.CountDown(); - }}); - EXPECT_TRUE(latch.Await().Ok()); - - EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kNotFound)); -} - -TEST_F(CredentialManagerImplTest, GetCredentialsSuccessfully) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - std::vector identity_types{IDENTITY_TYPE_PRIVATE_GROUP}; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identity_types, - kExpectedPresenceCredentialValidDays, - kExpectedPresenceCredentialListSize); - EXPECT_OK(public_credentials); - EXPECT_EQ(public_credentials->size(), kExpectedPresenceCredentialListSize); - - auto private_credentials = GetLocalCredentialsSync(credential_selector); - EXPECT_FALSE(private_credentials.empty()); -} - -TEST_F(CredentialManagerImplTest, PublicCredentialsFailEncryption) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - absl::StatusOr> public_credentials; - auto credential_manager_ptr = - std::make_unique( - &executor_); - EXPECT_CALL(*credential_manager_ptr, EncryptDeviceIdentityMetaData) - .WillOnce(::testing::Invoke( - [](absl::string_view metadata_encryption_key, - absl::string_view key_seed, - absl::string_view metadata_string) { return ""; })); - std::vector identity_types{IDENTITY_TYPE_PRIVATE_GROUP}; - - CountDownLatch latch(1); - credential_manager_ptr->GenerateCredentials( - device_identity_metadata, kManagerAppId, identity_types, - kExpectedPresenceCredentialValidDays, 1, - {.credentials_generated_cb = - [&](absl::StatusOr> credentials) { - public_credentials = std::move(credentials); - latch.CountDown(); - }}); - EXPECT_TRUE(latch.Await().Ok()); - - EXPECT_THAT(public_credentials, StatusIs(absl::StatusCode::kInvalidArgument)); -} - -TEST_F(CredentialManagerImplTest, UpdateLocalCredential) { - constexpr int kSelectedCredentialId = 2; - constexpr uint16_t kSalt = 1000; - absl::Status update_status = absl::UnknownError(""); - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - std::vector identity_types{IDENTITY_TYPE_PRIVATE_GROUP, - IDENTITY_TYPE_CONTACTS_GROUP}; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identity_types, - kExpectedPresenceCredentialValidDays, - kExpectedPresenceCredentialListSize); - - auto private_credentials = GetLocalCredentialsSync(credential_selector); - EXPECT_EQ(kExpectedPresenceCredentialListSize, private_credentials.size()); - - ASSERT_OK(public_credentials); - - // Modify a private credential - auto credential = private_credentials.at(kSelectedCredentialId); - EXPECT_TRUE( - private_credentials.at(kSelectedCredentialId).consumed_salts().empty()); - credential.mutable_consumed_salts()->insert({kSalt, true}); - - credential_manager_.UpdateLocalCredential( - credential_selector, credential, - {[&](absl::Status status) { update_status = status; }}); - - EXPECT_OK(update_status); - - // Verify that the modified credential has the new field in the new - // retrieved list of credentials. - auto modified_private_credentials = - GetLocalCredentialsSync(credential_selector); - EXPECT_TRUE(modified_private_credentials.at(kSelectedCredentialId) - .consumed_salts() - .at(kSalt)); -} - -TEST_F(CredentialManagerImplTest, EncryptAndDecryptDeviceIdentityMetaData) { - constexpr absl::string_view kMetadataEncryptionKeyBase16 = - "6331578C6E244074111B2ED0BBDB"; - constexpr absl::string_view kSeed = "123456"; - - auto encrypted_meta_data = credential_manager_.EncryptDeviceIdentityMetaData( - kMetadataEncryptionKeyBase16, kSeed, - CreateTestDeviceIdentityMetaData().SerializeAsString()); - - auto decrypted_meta_data = credential_manager_.DecryptDeviceIdentityMetaData( - kMetadataEncryptionKeyBase16, kSeed, encrypted_meta_data); - - DeviceIdentityMetaData device_identity_metadata; - ASSERT_TRUE(device_identity_metadata.ParseFromString(decrypted_meta_data)); - EXPECT_EQ(device_identity_metadata.device_id(), "\x12\xab\xcd"); - EXPECT_EQ(device_identity_metadata.device_type(), - internal::DeviceType::DEVICE_TYPE_PHONE); - EXPECT_EQ(device_identity_metadata.device_name(), "NP test device"); - EXPECT_EQ(device_identity_metadata.bluetooth_mac_address(), - "FF:FF:FF:FF:FF:FF"); -} - -TEST_F(CredentialManagerImplTest, RefillCredentialsInGetLocalCredentials) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - std::vector identity_types{IDENTITY_TYPE_PRIVATE_GROUP}; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identity_types, - kExpectedPresenceCredentialValidDays, 1); - - EXPECT_OK(public_credentials); - EXPECT_EQ(1, public_credentials->size()); - - // only generate 1 creds, expecting GetLocal would trigger refill to - // kExpectedPresenceCredentialListSize. - auto private_credentials = GetLocalCredentialsSync(credential_selector); - EXPECT_EQ(kExpectedPresenceCredentialListSize, private_credentials.size()); -} - -TEST_F(CredentialManagerImplTest, RefillCredentialsInGetSharedCredentials) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - std::vector identity_types{IDENTITY_TYPE_PRIVATE_GROUP}; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identity_types, - kExpectedPresenceCredentialValidDays, 1); - EXPECT_OK(public_credentials); - EXPECT_EQ(1, public_credentials->size()); - - // Only generated 1 creds, expecting GetPublicCredentials for - // kLocalPublicCredential type would trigger refill to - // kExpectedPresenceCredentialListSize. - auto refilled_public_credentials = GetPublicCredentialsSync( - credential_selector, PublicCredentialType::kLocalPublicCredential); - EXPECT_EQ(kExpectedPresenceCredentialListSize, - refilled_public_credentials.size()); -} - -TEST_F(CredentialManagerImplTest, RefillExpiredCredsInGetLocal) { - auto device_identity_metadata = CreateTestDeviceIdentityMetaData(); - std::vector identity_types{IDENTITY_TYPE_PRIVATE_GROUP}; - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - auto credential_storage = - std::make_unique(); - auto* credential_storage_ptr = credential_storage.get(); - credential_manager_ = - CredentialManagerImpl(&executor_, std::move(credential_storage)); - - auto public_credentials = GenerateCredentialsSync( - device_identity_metadata, kManagerAppId, identity_types, - kExpectedPresenceCredentialValidDays, - kExpectedPresenceCredentialListSize); - - ASSERT_OK(public_credentials); - EXPECT_EQ(public_credentials->size(), kExpectedPresenceCredentialListSize); - - // Now that we have generated kExpectedPresenceCredentialListSize valid creds, - // tweak the first credential's end time, in both credential lists, to - // make them expired. - auto expiry_time = absl::ToUnixMillis(absl::Now() - absl::Hours(1)); - credential_storage_ptr->private_credentials_.value() - .at(0) - .set_end_time_millis(expiry_time); - credential_storage_ptr->public_credentials_.value().at(0).set_end_time_millis( - expiry_time); - - auto old_private_credentials = - credential_storage_ptr->private_credentials_.value(); - - auto refilled_private_credentials = - GetLocalCredentialsSync(credential_selector); - EXPECT_EQ(kExpectedPresenceCredentialListSize, - refilled_private_credentials.size()); - - // Verifying the expired one private_credentials->at(0) is pruned in the new - // list. - EXPECT_EQ(old_private_credentials.at(1).secret_id(), - refilled_private_credentials.at(0).secret_id()); - // Verifying the new generated cred's start time is the same as previously - // existing list's last cred's end time. - EXPECT_EQ( - old_private_credentials.at(5).end_time_millis(), - refilled_private_credentials.at(kExpectedPresenceCredentialListSize - 1) - .start_time_millis()); -} - -} // namespace - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/ldt.cc b/presence/implementation/ldt.cc deleted file mode 100644 index 28eac763..00000000 --- a/presence/implementation/ldt.cc +++ /dev/null @@ -1,109 +0,0 @@ -// 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 "presence/implementation/ldt.h" - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/str_format.h" -#include "absl/strings/string_view.h" -#ifdef NEARBY_CHROMIUM -#include "third_party/nearby/src/presence/implementation/np_ldt.h" -#else -#include "np_ldt.h" -#endif - -namespace nearby { -namespace presence { - -namespace { -// NP LDT library says that 0 is returned when `NpLdtCreate()` fails. -constexpr uint64_t kInvalidLdtHandle = 0; - -template -T FromStringView(absl::string_view data) { - T result{ - .bytes = {0}, - }; - memcpy(result.bytes, data.data(), - std::min(sizeof(result.bytes), data.size())); - return result; -} -} // namespace - -LdtEncryptor::LdtEncryptor(LdtEncryptor&& other) - : ldt_encrypt_handle_(other.ldt_encrypt_handle_), - ldt_decrypt_handle_(other.ldt_decrypt_handle_) { - other.ldt_encrypt_handle_.handle = kInvalidLdtHandle; - other.ldt_decrypt_handle_.handle = kInvalidLdtHandle; -} - -LdtEncryptor::~LdtEncryptor() { - if (ldt_encrypt_handle_.handle != kInvalidLdtHandle) { - NpLdtEncryptClose(ldt_encrypt_handle_); - } - if (ldt_decrypt_handle_.handle != kInvalidLdtHandle) { - NpLdtDecryptClose(ldt_decrypt_handle_); - } -} - -absl::StatusOr LdtEncryptor::Create( - absl::string_view key_seed, absl::string_view known_hmac) { - NpLdtEncryptHandle encrypt_handle = - NpLdtEncryptCreate(FromStringView(key_seed)); - NpLdtDecryptHandle decrypt_handle = - NpLdtDecryptCreate(FromStringView(key_seed), - FromStringView(known_hmac)); - if (encrypt_handle.handle == kInvalidLdtHandle) { - return absl::UnavailableError("Failed to create LDT encryptor"); - } - if (decrypt_handle.handle == kInvalidLdtHandle) { - return absl::UnavailableError("Failed to create LDT decrypter"); - } - - return LdtEncryptor(encrypt_handle, decrypt_handle); -} - -absl::StatusOr LdtEncryptor::Encrypt(absl::string_view data, - absl::string_view salt) { - std::string encrypted = std::string(data); - NP_LDT_RESULT result = NpLdtEncrypt( - ldt_encrypt_handle_, reinterpret_cast(encrypted.data()), - encrypted.size(), FromStringView(salt)); - if (result == NP_LDT_SUCCESS) { - return encrypted; - } - return absl::InternalError( - absl::StrFormat("LDT encryption failed, errorcode %d", result)); -} - -absl::StatusOr LdtEncryptor::DecryptAndVerify( - absl::string_view data, absl::string_view salt) { - std::string encrypted = std::string(data); - NP_LDT_RESULT result = NpLdtDecryptAndVerify( - ldt_decrypt_handle_, reinterpret_cast(encrypted.data()), - encrypted.size(), FromStringView(salt)); - if (result == NP_LDT_SUCCESS) { - return encrypted; - } - return absl::InternalError( - absl::StrFormat("LDT encryption failed, errorcode %d", result)); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/ldt.h b/presence/implementation/ldt.h deleted file mode 100644 index d86ecc10..00000000 --- a/presence/implementation/ldt.h +++ /dev/null @@ -1,76 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_LDT_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_LDT_H_ - -#include -#include - -#ifdef NEARBY_CHROMIUM -#include "third_party/nearby/src/presence/implementation/np_ldt.h" -#else -#include "np_ldt.h" -#endif - -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" - -namespace nearby { -namespace presence { - -// C++ abstraction on top of LDT C API. -class LdtEncryptor { - public: - LdtEncryptor(const LdtEncryptor&) = delete; - LdtEncryptor(LdtEncryptor&& other); - LdtEncryptor& operator=(const LdtEncryptor&) = delete; - LdtEncryptor& operator=(LdtEncryptor&& other) { - std::swap(ldt_encrypt_handle_, other.ldt_encrypt_handle_); - std::swap(ldt_decrypt_handle_, other.ldt_decrypt_handle_); - return *this; - } - ~LdtEncryptor(); - - // Creates an instance of `LdtEncryptor`. - // `key_seed` is used to generate LDT encryption and decryption keys. - // `known_hmac` is used during decryption to verify if the message was - // encrypted with the expected key. - static absl::StatusOr Create(absl::string_view key_seed, - absl::string_view known_hmac); - - // Encrypts `data`, which must be 16 - 31 bytes long. - absl::StatusOr Encrypt(absl::string_view data, - absl::string_view salt); - - // Decrypts `data` and verifies if it was encrypted with a key generated from - // `key_seed`. - absl::StatusOr DecryptAndVerify(absl::string_view data, - absl::string_view salt); - - private: - explicit LdtEncryptor(NpLdtEncryptHandle ldt_encrypt_handle, - NpLdtDecryptHandle ldt_decrypt_handle) - : ldt_encrypt_handle_(ldt_encrypt_handle), - ldt_decrypt_handle_(ldt_decrypt_handle) {} - // An opaque handle to the underlying LDT implementation. It can be null iff - // this object has already been destroyed. - NpLdtEncryptHandle ldt_encrypt_handle_; - NpLdtDecryptHandle ldt_decrypt_handle_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_LDT_H_ diff --git a/presence/implementation/ldt_stub.c b/presence/implementation/ldt_stub.c deleted file mode 100644 index cc930bd5..00000000 --- a/presence/implementation/ldt_stub.c +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2025 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 "presence/implementation/np_ldt.h" - -// Placeholder, empty implementations of LDT utilities. They will be replaced -// with implementations in Rust. - -NpLdtEncryptHandle NpLdtEncryptCreate(NpLdtKeySeed key_seed) { - NpLdtEncryptHandle handle = {0}; - return handle; -} - -NpLdtDecryptHandle NpLdtDecryptCreate(NpLdtKeySeed key_seed, - NpMetadataKeyHmac hmac_tag) { - NpLdtDecryptHandle handle = {0}; - return handle; -} - -NP_LDT_RESULT NpLdtEncryptClose(NpLdtEncryptHandle handle) { - return NP_LDT_SUCCESS; -} - -NP_LDT_RESULT NpLdtDecryptClose(NpLdtDecryptHandle handle) { - return NP_LDT_SUCCESS; -} - -NP_LDT_RESULT NpLdtEncrypt(NpLdtEncryptHandle handle, uint8_t* buffer, - size_t buffer_len, NpLdtSalt salt) { - return NP_LDT_SUCCESS; -} - -NP_LDT_RESULT NpLdtDecryptAndVerify(NpLdtDecryptHandle handle, uint8_t* buffer, - size_t buffer_len, NpLdtSalt salt) { - return NP_LDT_SUCCESS; -} \ No newline at end of file diff --git a/presence/implementation/ldt_test.cc b/presence/implementation/ldt_test.cc deleted file mode 100644 index b574cc7d..00000000 --- a/presence/implementation/ldt_test.cc +++ /dev/null @@ -1,98 +0,0 @@ -// 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 "presence/implementation/ldt.h" - -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/statusor.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "internal/platform/byte_array.h" - -namespace nearby { -namespace presence { - -namespace { -using ::nearby::ByteArray; - -// Test data from Android tests. -constexpr absl::string_view kKeySeedBase16 = - "CCDB2489E9FCAC42B39348B8941ED19A1D360E75E098C8C15E6B1CC2B620CD39"; -constexpr absl::string_view kKnownMacBase16 = - "B4C59FA599241B81758D976B5A621C05232FE1BF89AE5987CA254C3554DCE50E"; -constexpr absl::string_view kPlainTextBase16 = - "CD683FE1A1D1F846543D0A13D4AEA40040C8D67B"; -constexpr absl::string_view kCipherTextBase16 = - "61E481C12F4DE24F2D4AB22D8908F80D3A3F9B40"; -constexpr absl::string_view kSaltBase16 = "0C0F"; - -TEST(Ldt, EncryptAndDecrypt) { - // Test data copied from NP LDT tests - ByteArray seed({204, 219, 36, 137, 233, 252, 172, 66, 179, 147, 72, - 184, 148, 30, 209, 154, 29, 54, 14, 117, 224, 152, - 200, 193, 94, 107, 28, 194, 182, 32, 205, 57}); - ByteArray known_mac({0xB4, 0xC5, 0x9F, 0xA5, 0x99, 0x24, 0x1B, 0x81, - 0x75, 0x8D, 0x97, 0x6B, 0x5A, 0x62, 0x1C, 0x05, - 0x23, 0x2F, 0xE1, 0xBF, 0x89, 0xAE, 0x59, 0x87, - 0xCA, 0x25, 0x4C, 0x35, 0x54, 0xDC, 0xE5, 0x0E}); - ByteArray test_data({205, 104, 63, 225, 161, 209, 248, 70, 84, 61, - 10, 19, 212, 174, 164, 0, 64, 200, 214, 123}); - ByteArray salt({12, 15}); - - absl::StatusOr encryptor = - LdtEncryptor::Create(seed.AsStringView(), known_mac.AsStringView()); - ASSERT_OK(encryptor); - absl::StatusOr encrypted = - encryptor->Encrypt(test_data.AsStringView(), salt.AsStringView()); - ASSERT_OK(encrypted); - absl::StatusOr decrypted = - encryptor->DecryptAndVerify(*encrypted, salt.AsStringView()); - ASSERT_OK(decrypted); - EXPECT_EQ(*decrypted, test_data.AsStringView()); -} - -TEST(Ldt, EncryptAndroidData) { - absl::StatusOr encryptor = - LdtEncryptor::Create(absl::HexStringToBytes(kKeySeedBase16), - absl::HexStringToBytes(kKnownMacBase16)); - ASSERT_OK(encryptor); - - absl::StatusOr encrypted = - encryptor->Encrypt(absl::HexStringToBytes(kPlainTextBase16), - absl::HexStringToBytes(kSaltBase16)); - - ASSERT_OK(encrypted); - EXPECT_EQ(*encrypted, absl::HexStringToBytes(kCipherTextBase16)); -} - -TEST(Ldt, DecryptAndroidData) { - absl::StatusOr encryptor = - LdtEncryptor::Create(absl::HexStringToBytes(kKeySeedBase16), - absl::HexStringToBytes(kKnownMacBase16)); - ASSERT_OK(encryptor); - - absl::StatusOr decrypted = - encryptor->DecryptAndVerify(absl::HexStringToBytes(kCipherTextBase16), - absl::HexStringToBytes(kSaltBase16)); - - ASSERT_OK(decrypted); - EXPECT_EQ(*decrypted, absl::HexStringToBytes(kPlainTextBase16)); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/mediums/BUILD b/presence/implementation/mediums/BUILD deleted file mode 100644 index 80dc9214..00000000 --- a/presence/implementation/mediums/BUILD +++ /dev/null @@ -1,70 +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. - -load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") - -licenses(["notice"]) - -cc_library( - name = "mediums", - srcs = [ - ], - hdrs = [ - "advertisement_data.h", - "ble.h", - "mediums.h", - ], - visibility = [ - "//presence:__subpackages__", - ], - deps = [ - "//internal/platform:base", - "//internal/platform:comm", - "//internal/platform:uuid", - "//internal/platform/implementation:comm", - "//presence:types", - ], -) - -cc_test( - name = "mediums_test", - size = "small", - srcs = [ - "ble_test.cc", - ], - shard_count = 16, - deps = [ - ":mediums", - "//internal/platform:base", - "//internal/platform:comm", - "//internal/platform:test_util", - "//internal/platform:types", - "//internal/platform:uuid", - "//internal/platform/implementation:comm", - "//presence:types", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/status", - "@com_google_absl//absl/time", - "@com_google_absl//absl/types:variant", - "@com_google_googletest//:gtest_main", - ] + select({ - "@platforms//os:windows": [ - "//internal/platform/implementation/windows", - ], - "//conditions:default": [ - "//internal/platform/implementation/g3", - ], - }), -) diff --git a/presence/implementation/mediums/advertisement_data.h b/presence/implementation/mediums/advertisement_data.h deleted file mode 100644 index 654f89b9..00000000 --- a/presence/implementation/mediums/advertisement_data.h +++ /dev/null @@ -1,34 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_ADVERTISEMENT_DATA_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_ADVERTISEMENT_DATA_H_ - -#include - -namespace nearby { -namespace presence { - -// Nearby Presence advertisement data over the air. -struct AdvertisementData { - // If true, the advertisement needs to be broadcasted over BLE 5.0. - bool is_extended_advertisement; - // The advertised data. - std::string content; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_ADVERTISEMENT_DATA_H_ diff --git a/presence/implementation/mediums/ble.h b/presence/implementation/mediums/ble.h deleted file mode 100644 index 715c0b9b..00000000 --- a/presence/implementation/mediums/ble.h +++ /dev/null @@ -1,111 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_BLE_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_BLE_H_ - -#include -#include - -#include "internal/platform/ble.h" -#include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/uuid.h" -#include "presence/implementation/mediums/advertisement_data.h" -#include "presence/power_mode.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -/** Presence advertisement service data uuid. */ -ABSL_CONST_INIT const nearby::Uuid kPresenceServiceUuid(0x0000fcf100001000, - 0x800000805f9b34fb); - -/* - * This Ble class utilizes platform/ble BleMedium, provides ble functions - * for presence logic layer to invoke. - * This class would have states like if ble is available or not, if it's doing - * broadcast/scan. - */ -class Ble { - public: - using TxPowerLevel = ::nearby::api::ble::TxPowerLevel; - using ScanningSession = ::nearby::api::ble::BleMedium::ScanningSession; - using ScanningCallback = ::nearby::api::ble::BleMedium::ScanningCallback; - using AdvertiseParameters = ::nearby::api::ble::AdvertiseParameters; - using AdvertisingSession = ::nearby::api::ble::BleMedium::AdvertisingSession; - using AdvertisingCallback = - ::nearby::api::ble::BleMedium::AdvertisingCallback; - using BleAdvertisementData = ::nearby::api::ble::BleAdvertisementData; - using BleMedium = ::nearby::api::ble::BleMedium; - - explicit Ble(nearby::BluetoothAdapter& bluetooth_adapter) - : medium_(bluetooth_adapter) {} - - bool IsAvailable() const { return medium_.IsValid(); } - - // Starts broadcasting NP advertisement in `payload`. The caller should use - // the returned `AdvertisingSession` to stop the broadcast. - std::unique_ptr StartAdvertising( - const AdvertisementData& payload, PowerMode power_mode, - AdvertisingCallback callback) { - BleAdvertisementData advertising_data = { - .is_extended_advertisement = payload.is_extended_advertisement}; - advertising_data.service_data.insert( - {kPresenceServiceUuid, nearby::ByteArray(payload.content)}); - AdvertiseParameters advertise_set_parameters = { - .tx_power_level = ConvertPowerModeToPowerLevel(power_mode), - .is_connectable = true, - }; - return medium_.StartAdvertising(advertising_data, advertise_set_parameters, - std::move(callback)); - } - - // Starts scanning for NP advertisements. The caller should use the returned - // `ScanningSession` to stop scanning. - std::unique_ptr StartScanning(ScanRequest scan_request, - ScanningCallback callback) { - return medium_.StartScanning( - kPresenceServiceUuid, - ConvertPowerModeToPowerLevel(scan_request.power_mode), - std::move(callback)); - } - - // Provides access to platform implementation. It's used in tests. - BleMedium* GetImpl() const { return medium_.GetImpl(); } - - private: - TxPowerLevel ConvertPowerModeToPowerLevel(PowerMode power_mode) { - switch (power_mode) { - case PowerMode::kNoPower: - return TxPowerLevel::kUnknown; - case PowerMode::kLowPower: - return TxPowerLevel::kLow; - case PowerMode::kBalanced: - return TxPowerLevel::kMedium; - case PowerMode::kLowLatency: - return TxPowerLevel::kHigh; - } - return TxPowerLevel::kUnknown; - } - - nearby::BleMedium medium_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_BLE_H_ diff --git a/presence/implementation/mediums/ble_test.cc b/presence/implementation/mediums/ble_test.cc deleted file mode 100644 index 70633ad7..00000000 --- a/presence/implementation/mediums/ble_test.cc +++ /dev/null @@ -1,177 +0,0 @@ -// 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 "presence/implementation/mediums/ble.h" - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "absl/time/time.h" -#include "absl/types/variant.h" -#include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/feature_flags.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/medium_environment.h" -#include "internal/platform/uuid.h" -#include "presence/data_element.h" -#include "presence/implementation/mediums/advertisement_data.h" -#include "presence/power_mode.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { -namespace { - -using FeatureFlags = ::nearby::FeatureFlags::Flags; -using BleMediumStatus = ::nearby::MediumEnvironment::BleMediumStatus; -using ScanningSession = ::nearby::api::ble::BleMedium::ScanningSession; -using TxPowerLevel = ::nearby::api::ble::TxPowerLevel; -using ScanningCallback = ::nearby::api::ble::BleMedium::ScanningCallback; -using Uuid = ::nearby::Uuid; -using ::nearby::api::ble::BleAdvertisementData; -using ::nearby::api::ble::BlePeripheral; -using AdvertisingCallback = ::nearby::api::ble::BleMedium::AdvertisingCallback; -using AdvertisingSession = ::nearby::api::ble::BleMedium::AdvertisingSession; - -constexpr FeatureFlags kTestCases[] = { - FeatureFlags{}, -}; - -class BleTest : public testing::TestWithParam { - public: - constexpr static absl::Duration kWaitDuration = absl::Milliseconds(1000); - - std::string account_name_ = "Test-Name"; - constexpr static PowerMode kPowerMode = PowerMode::kBalanced; - std::vector identity_types_ = { - nearby::internal::IdentityType::IDENTITY_TYPE_CONTACTS_GROUP, - }; - std::vector extended_properties_ = { - DataElement{DataElement::kTxPowerFieldType, "-10"}}; - std::vector > - filters_ = {PresenceScanFilter{ - .scan_type = ScanType::kPresenceScan, - .extended_properties = extended_properties_, - }}; - constexpr static bool kUseBle = true; - constexpr static ScanType kScanType = ScanType::kPresenceScan; - constexpr static bool kScanOnlyWhenScreenOn = true; - - ScanRequest scan_request_ = { - .account_name = account_name_, - .identity_types = identity_types_, - .scan_filters = filters_, - .use_ble = kUseBle, - .scan_type = kScanType, - .power_mode = kPowerMode, - .scan_only_when_screen_on = kScanOnlyWhenScreenOn, - }; - - protected: - std::optional GetBleStatus(const Ble& ble) { - return env_.GetBleMediumStatus(*ble.GetImpl()); - } - nearby::MediumEnvironment& env_{nearby::MediumEnvironment::Instance()}; -}; - -INSTANTIATE_TEST_SUITE_P(ParametrisedBleTest, BleTest, - ::testing::ValuesIn(kTestCases)); - -// Using MediumEnvironment to verify the start&stop StartScanning callback flows -// are working as intended. -TEST_P(BleTest, CanStartThenStopScanning) { - env_.Start(); - ::nearby::BluetoothAdapter adapter; - Ble ble(adapter); - - ScanRequest scan_request{ - .power_mode = PowerMode::kBalanced, - }; - ScanningCallback scanning_callback; - nearby::CountDownLatch started_scanning_latch(1); - - std::unique_ptr scannning_session = ble.StartScanning( - scan_request, ScanningCallback{ - .start_scanning_result = - [&started_scanning_latch](absl::Status status) { - if (status.ok()) { - started_scanning_latch.CountDown(); - } - }, - }); - - EXPECT_TRUE(started_scanning_latch.Await(kWaitDuration).result()); - EXPECT_TRUE(GetBleStatus(ble).has_value() && - GetBleStatus(ble).value().is_scanning == true); - absl::Status stop_scanning_status = scannning_session->stop_scanning(); - EXPECT_OK(stop_scanning_status); - EXPECT_TRUE(GetBleStatus(ble).has_value() && - GetBleStatus(ble).value().is_scanning == false); - env_.Stop(); -} - -TEST_P(BleTest, AdvertiseAndScan) { - // Create two Ble devices, one advertises, the other one scans, and verify - // that the NP advertisement was sent from one to the other. - env_.Start(); - nearby::BluetoothAdapter client_adapter; - Ble client(client_adapter); - nearby::BluetoothAdapter server_adapter; - Ble server(server_adapter); - AdvertisementData advert_data = {.is_extended_advertisement = false, - .content = "my advertisement"}; - ScanRequest scan_request{ - .power_mode = PowerMode::kBalanced, - }; - nearby::CountDownLatch advertise_latch(1); - nearby::CountDownLatch scan_latch(1); - std::vector advertisements; - std::unique_ptr scanning_session = client.StartScanning( - scan_request, - ScanningCallback{.advertisement_found_cb = - [&](BlePeripheral::UniqueId peripheral_id, - BleAdvertisementData advertisement_data) { - advertisements.push_back(advertisement_data); - scan_latch.CountDown(); - }}); - std::unique_ptr - advertising_session = server.StartAdvertising( - advert_data, PowerMode::kBalanced, - AdvertisingCallback{ - .start_advertising_result = [&](absl::Status status) { - advertise_latch.CountDown(); - }}); - - EXPECT_TRUE(advertise_latch.Await(kWaitDuration).result()); - EXPECT_TRUE(scan_latch.Await(kWaitDuration).result()); - EXPECT_OK(scanning_session->stop_scanning()); - EXPECT_OK(advertising_session->stop_advertising()); - ASSERT_FALSE(advertisements.empty()); - EXPECT_EQ(advertisements[0] - .service_data.find(kPresenceServiceUuid) - ->second.AsStringView(), - advert_data.content); - env_.Stop(); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/mediums/mediums.h b/presence/implementation/mediums/mediums.h deleted file mode 100644 index a47679da..00000000 --- a/presence/implementation/mediums/mediums.h +++ /dev/null @@ -1,41 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_MEDIUMS_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_MEDIUMS_H_ - -#include "internal/platform/bluetooth_adapter.h" -#include "presence/implementation/mediums/ble.h" - -namespace nearby { -namespace presence { - -/* - * This class owns medium instance like Ble and etc. And the instance of - * this class will be owned in {@code ServiceControllerImpl}. - */ -class Mediums { - public: - // Returns a handle to the Ble medium. - Ble& GetBle() { return ble_; } - - private: - nearby::BluetoothAdapter adapter_; - Ble ble_{adapter_}; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MEDIUMS_MEDIUMS_H_ diff --git a/presence/implementation/mock_connection_authenticator.h b/presence/implementation/mock_connection_authenticator.h deleted file mode 100644 index 24e860eb..00000000 --- a/presence/implementation/mock_connection_authenticator.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_IMPLEMENTATION_MOCK_CONNECTION_AUTHENTICATOR_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CONNECTION_AUTHENTICATOR_H_ - -#include -#include - -#include "gmock/gmock.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" -#include "presence/implementation/connection_authenticator.h" - -namespace nearby { -namespace presence { - -/* - * This class is for unit tests, mocking {@code ConnectionAuthenticator} - * functions in `PresenceDeviceProviderTest`. - */ -class MockConnectionAuthenticator : public ConnectionAuthenticator { - public: - MOCK_METHOD(absl::StatusOr, BuildSignedMessageAsInitiator, - (absl::string_view ukey2_secret, - std::optional local_credential, - const internal::SharedCredential& shared_credential), - (const, override)); - MOCK_METHOD(absl::StatusOr, BuildSignedMessageAsResponder, - (absl::string_view ukey2_secret, - const internal::LocalCredential& local_credential), - (const, override)); - MOCK_METHOD( - absl::Status, VerifyMessageAsInitiator, - (ResponderData authentication_data, absl::string_view ukey2_secret, - const std::vector& shared_credentials), - (const, override)); - MOCK_METHOD( - absl::StatusOr, VerifyMessageAsResponder, - (absl::string_view ukey2_secret, InitiatorData initiator_data, - const std::vector& local_credentials, - const std::vector& shared_credentials), - (const, override)); -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CONNECTION_AUTHENTICATOR_H_ diff --git a/presence/implementation/mock_credential_manager.h b/presence/implementation/mock_credential_manager.h deleted file mode 100644 index 64d6e848..00000000 --- a/presence/implementation/mock_credential_manager.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_IMPLEMENTATION_MOCK_CREDENTIAL_MANAGER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CREDENTIAL_MANAGER_H_ - -#include -#include - -#include "gmock/gmock.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "presence/implementation/credential_manager.h" - -namespace nearby { -namespace presence { - -class MockCredentialManager : public CredentialManager { - public: - MOCK_METHOD( - void, GenerateCredentials, - (const nearby::internal::DeviceIdentityMetaData& device_identity_metadata, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb), - (override)); - MOCK_METHOD(void, UpdateRemotePublicCredentials, - (absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb), - (override)); - MOCK_METHOD(void, UpdateLocalCredential, - (const CredentialSelector& credential_selector, - nearby::internal::LocalCredential credential, - SaveCredentialsResultCallback result_callback), - (override)); - MOCK_METHOD(void, GetLocalCredentials, - (const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback), - (override)); - MOCK_METHOD(void, GetPublicCredentials, - (const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback), - (override)); - MOCK_METHOD(SubscriberId, SubscribeForPublicCredentials, - (const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback), - (override)); - MOCK_METHOD(void, UnsubscribeFromPublicCredentials, (SubscriberId id), - (override)); - MOCK_METHOD(std::string, DecryptDeviceIdentityMetaData, - (absl::string_view metadata_encryption_key, - absl::string_view key_seed, absl::string_view metadata_string), - (override)); - MOCK_METHOD( - void, SetDeviceIdentityMetaData, - (const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb), - (override)); - MOCK_METHOD(::nearby::internal::DeviceIdentityMetaData, - GetDeviceIdentityMetaData, (), (override)); -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_CREDENTIAL_MANAGER_H_ diff --git a/presence/implementation/mock_service_controller.h b/presence/implementation/mock_service_controller.h deleted file mode 100644 index 90c3b31d..00000000 --- a/presence/implementation/mock_service_controller.h +++ /dev/null @@ -1,82 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_SERVICE_CONTROLLER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_SERVICE_CONTROLLER_H_ - -#include -#include - -#include "gmock/gmock.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "presence/implementation/service_controller.h" - -namespace nearby { -namespace presence { - -/* - * This class is for unit test, mocking {@code ServiceController} functions. - */ -class MockServiceController : public ServiceController { - public: - MockServiceController() = default; - ~MockServiceController() override = default; - - MOCK_METHOD(absl::StatusOr, StartScan, - (ScanRequest scan_request, ScanCallback callback), (override)); - MOCK_METHOD(void, StopScan, (ScanSessionId session_id), (override)); - MOCK_METHOD(absl::StatusOr, StartBroadcast, - (BroadcastRequest broadcast_request, BroadcastCallback callback), - (override)); - MOCK_METHOD(void, StopBroadcast, (BroadcastSessionId session_id), (override)); - MOCK_METHOD( - void, UpdateLocalDeviceMetadata, - (const ::nearby::internal::Metadata& metadata, bool regen_credentials, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb), - (override)); - MOCK_METHOD( - void, UpdateDeviceIdentityMetaData, - (const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb), - (override)); - MOCK_METHOD(::nearby::internal::DeviceIdentityMetaData, - GetDeviceIdentityMetaData, (), (override)); - MOCK_METHOD(void, GetLocalPublicCredentials, - (const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback), - (override)); - MOCK_METHOD(void, UpdateRemotePublicCredentials, - (absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb), - (override)); - MOCK_METHOD(void, GetLocalCredentials, - (const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback), - (override)); -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_MOCK_SERVICE_CONTROLLER_H_ diff --git a/presence/implementation/np_ldt.h b/presence/implementation/np_ldt.h deleted file mode 100644 index 9047c12a..00000000 --- a/presence/implementation/np_ldt.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_NP_LDT_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_NP_LDT_H_ - -// 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. -// C API for Rust implementation of LDT [1], tailored to Nearby Presence's -// BLE 4.2 legacy format advertisement parsing usecase. -// -// [1] https://eprint.iacr.org/2017/841.pdf - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -// Individual encrypt/decrypt API, useful when creating advertisements or when -// decrypting advertisements from a known origin - -// The allocated handle to use for encryption -typedef struct { - uint64_t handle; -} NpLdtEncryptHandle; - -// The allocated handle to use for decryption -typedef struct { - uint64_t handle; -} NpLdtDecryptHandle; - -// Key material from the Nearby Presence credential from which keys will be -// derived. -typedef struct { - uint8_t bytes[32]; -} NpLdtKeySeed; - -typedef struct { - uint8_t bytes[32]; -} NpMetadataKeyHmac; - -typedef struct { - uint8_t bytes[2]; -} NpLdtSalt; - -// Possible result codes returned from the LDT NP API's -typedef enum { - // Call to api was succesful - NP_LDT_SUCCESS = 0, - // Payload of invalid length was provided must be >= 16 and <=31 bytes - NP_LDT_ERROR_INVALID_LENGTH = -1, - // The provided metadata hmac did not match the calculated hmac on call to - // decrypt and verify - NP_LDT_ERROR_MAC_MISMATCH = -2, -} NP_LDT_RESULT; - -// Allocate an LDT-XTS-AES128 Decryption cipher using the "swap" mix function. -// -// `key_seed` is the key material from the Nearby Presence credential from which -// the LDT key will be derived. -// 'hmac_tag' is the hmac auth tag calculated on the metadata key used to verify -// decryption was successful -// -// Returns 0 on error, or a non-zero handle on success. -NpLdtDecryptHandle NpLdtDecryptCreate(NpLdtKeySeed key_seed, - NpMetadataKeyHmac hmac_tag); - -// Allocate an LDT-XTS-AES128 Encryption cipher using the "swap" mix function. -// -// `key_seed` is the key material from the Nearby Presence credential from which -// the LDT key will be derived. -// -// Returns 0 on error, or a non-zero handle on success. -NpLdtEncryptHandle NpLdtEncryptCreate(NpLdtKeySeed key_seed); - -// Release allocated resources for an NpLdtEncryptHandle -// -// Returns 0 on success or an NP_LDT_RESULT error code on failure -NP_LDT_RESULT NpLdtEncryptClose(NpLdtEncryptHandle handle); - -// Release allocated resources for an NpLdtDecryptHandle -// -// Returns 0 on success or an NP_LDT_RESULT error code on failure -NP_LDT_RESULT NpLdtDecryptClose(NpLdtDecryptHandle handle); - -// Encrypt a 16-31 byte buffer in-place. -// -// `buffer` is a pointer to a 16-31 byte plaintext, with length in `buffer_len`. -// `salt` is the big-endian 2 byte salt that will be used in the Nearby -// Presence advertisement, which will be incorporated into the tweaks LDT uses -// while encrypting. -// -// Returns 0 on success, in which case `buffer` will now contain ciphertext. -// Returns an NP_LDT_RESULT error code on failure -NP_LDT_RESULT NpLdtEncrypt(NpLdtEncryptHandle handle, uint8_t* buffer, - size_t buffer_len, NpLdtSalt salt); - -// Decrypt a 16-31 byte buffer in-place. -// -// `buffer` is a pointer to a 16-31 byte ciphertext, with length in -// `buffer_len`. -// `salt` is the big-endian 2 byte salt found in the Nearby Presence -// advertisement, which will be incorporated into the tweaks LDT uses while -// decrypting. -// -// Returns 0 on success, in which case `buffer` will now contain plaintext. -// Returns an NP_LDT_RESULT error code on failure -NP_LDT_RESULT NpLdtDecryptAndVerify(NpLdtDecryptHandle handle, uint8_t* buffer, - size_t buffer_len, NpLdtSalt salt); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_NP_LDT_H_ diff --git a/presence/implementation/scan_manager.cc b/presence/implementation/scan_manager.cc deleted file mode 100644 index 3f6d7e03..00000000 --- a/presence/implementation/scan_manager.cc +++ /dev/null @@ -1,280 +0,0 @@ -// 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 "presence/implementation/scan_manager.h" - -#include - -#include -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/status/status.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "internal/platform/future.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/implementation/crypto.h" -#include "internal/platform/logging.h" -#include "presence//implementation/advertisement_filter.h" -#include "presence/data_element.h" -#include "presence/data_types.h" -#include "presence/device_motion.h" -#include "presence/implementation/advertisement_decoder.h" -#include "presence/implementation/mediums/ble.h" -#include "presence/presence_action.h" -#include "presence/presence_device.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -namespace { -using BleAdvertisementData = ::nearby::api::ble::BleAdvertisementData; -using BlePeripheral = ::nearby::api::ble::BlePeripheral; -using ScanningSession = ::nearby::api::ble::BleMedium::ScanningSession; -using ScanningCallback = ::nearby::api::ble::BleMedium::ScanningCallback; -} // namespace - -ScanSessionId ScanManager::StartScan(ScanRequest scan_request, - ScanCallback cb) { - ScanSessionId id = nearby::RandData(); - RunOnServiceControllerThread( - "start-scan", - [this, id, scan_request, - scan_callback = - std::move(cb)]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) mutable { - ScanningCallback callback = ScanningCallback{ - .start_scanning_result = - [start_scan_client = std::move(scan_callback.start_scan_cb)]( - absl::Status ble_status) mutable { - start_scan_client(ble_status); - }, - .advertisement_found_cb = - [this, id](BlePeripheral::UniqueId peripheral_id, - BleAdvertisementData data) { - RunOnServiceControllerThread( - "notify-found-ble", - [this, id, data = std::move(data), peripheral_id]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - NotifyFoundBle(id, data, peripheral_id); - }); - }, - .advertisement_lost_cb = - [this, id](BlePeripheral::UniqueId peripheral_id) { - RunOnServiceControllerThread( - "notify-lost-ble", - [this, id, peripheral_id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED( - *executor_) { NotifyLostBle(id, peripheral_id); }); - }}; - FetchCredentials(id, scan_request); - scan_sessions_.insert( - {id, ScanSessionState{ - .request = scan_request, - .callback = std::move(scan_callback), - .decoder = AdvertisementDecoderImpl(), - .advertisement_filter = AdvertisementFilter(scan_request), - .scanning_session = mediums_->GetBle().StartScanning( - scan_request, std::move(callback))}}); - }); - return id; -} - -void ScanManager::StopScan(ScanSessionId id) { - RunOnServiceControllerThread( - "stop-scan", [this, id]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - auto it = scan_sessions_.find(id); - if (it == scan_sessions_.end()) { - return; - } - if (it->second.scanning_session) { - absl::Status status = it->second.scanning_session->stop_scanning(); - if (!status.ok()) { - LOG(WARNING) << "StopScan error: " << status; - } - } - scan_sessions_.erase(it); - }); -} - -void ScanManager::NotifyFoundBle(ScanSessionId id, BleAdvertisementData data, - BlePeripheral::UniqueId peripheral_id) { - auto it = scan_sessions_.find(id); - if (it == scan_sessions_.end()) { - return; - } - - auto advertisement_data = - data.service_data[kPresenceServiceUuid].AsStringView(); - - auto advert = it->second.decoder.DecodeAdvertisement(advertisement_data); - if (!advert.ok()) { - // This advertisement is not relevant to the current element, skip. - return; - } - - std::string remote_address = absl::StrCat(absl::Hex(peripheral_id)); - if (it->second.advertisement_filter.MatchesScanFilter(*advert)) { - internal::DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_bluetooth_mac_address(remote_address); - - if (!device_unique_id_to_endpoint_id_map_.contains(peripheral_id)) { - PresenceDevice device(DeviceMotion(), device_identity_metadata, - advert->identity_type); - // Ok if the advertisement is for trusted/private identity. - if (advert->public_credential.ok()) { - device.SetDecryptSharedCredential(*(advert->public_credential)); - } - device.AddExtendedProperties(advert->data_elements); - for (const auto& data_element : advert->data_elements) { - if (data_element.GetType() == DataElement::kActionFieldType) { - device.AddAction(PresenceAction(static_cast( - static_cast(data_element.GetValue()[0])))); - } - } - - device_unique_id_to_endpoint_id_map_.emplace(peripheral_id, - device.GetEndpointId()); - - it->second.callback.on_discovered_cb(std::move(device)); - } else { - PresenceDevice device( - device_unique_id_to_endpoint_id_map_.at(peripheral_id)); - device.SetDeviceIdentityMetaData(device_identity_metadata); - // Ok if the advertisement is for trusted/private identity. - if (advert->public_credential.ok()) { - device.SetDecryptSharedCredential(*(advert->public_credential)); - } - device.AddExtendedProperties(advert->data_elements); - for (const auto& data_element : advert->data_elements) { - if (data_element.GetType() == DataElement::kActionFieldType) { - device.AddAction(PresenceAction(static_cast( - static_cast(data_element.GetValue()[0])))); - } - } - - it->second.callback.on_updated_cb(std::move(device)); - } - } -} - -void ScanManager::NotifyLostBle(ScanSessionId id, - BlePeripheral::UniqueId peripheral_id) { - auto it = scan_sessions_.find(id); - if (it == scan_sessions_.end()) { - return; - } - - std::string remote_address = absl::StrCat(absl::Hex(peripheral_id)); - if (device_unique_id_to_endpoint_id_map_.contains(peripheral_id)) { - internal::DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_bluetooth_mac_address( - std::string(remote_address)); - PresenceDevice device( - device_unique_id_to_endpoint_id_map_.at(peripheral_id)); - device.SetDeviceIdentityMetaData(device_identity_metadata); - - device_unique_id_to_endpoint_id_map_.erase(peripheral_id); - - it->second.callback.on_lost_cb(std::move(device)); - } -} - -std::vector GetCredentialSelectors( - const ScanRequest& scan_request) { - std::vector all_types = { - nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP, - nearby::internal::IdentityType::IDENTITY_TYPE_CONTACTS_GROUP, - nearby::internal::IdentityType::IDENTITY_TYPE_PUBLIC}; - std::vector selectors; - for (auto identity_type : - (scan_request.identity_types.empty() ? all_types - : scan_request.identity_types)) { - selectors.push_back( - CredentialSelector{.manager_app_id = scan_request.manager_app_id, - .account_name = scan_request.account_name, - .identity_type = identity_type}); - } - return selectors; -} - -void ScanManager::FetchCredentials(ScanSessionId id, - const ScanRequest& scan_request) { - std::vector credential_selectors = - GetCredentialSelectors(scan_request); - for (const CredentialSelector& selector : credential_selectors) { - // Not fetching for PUBLIC. - if (selector.identity_type == internal::IDENTITY_TYPE_UNSPECIFIED || - selector.identity_type == internal::IDENTITY_TYPE_PUBLIC) { - LOG(INFO) << __func__ << ": skip feteching creds for identity type: " - << selector.identity_type; - continue; - } - credential_manager_->GetPublicCredentials( - selector, PublicCredentialType::kRemotePublicCredential, - {.credentials_fetched_cb = - [this, id, identity_type = selector.identity_type]( - absl::StatusOr< - std::vector<::nearby::internal::SharedCredential>> - credentials) { - if (!credentials.ok()) { - LOG(WARNING) - << "Failed to fetch credentials: " << credentials.status(); - return; - } - RunOnServiceControllerThread( - "update-credentials", - [this, id, identity_type, - credentials = std::move(*credentials)]() - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - UpdateCredentials(id, identity_type, - std::move(credentials)); - }); - }}); - } -} - -void ScanManager::UpdateCredentials(ScanSessionId id, - IdentityType identity_type, - std::vector credentials) { - // Credentials should never get fetched for PUBLIC of No-Identity requests - assert(identity_type != internal::IDENTITY_TYPE_UNSPECIFIED); - assert(identity_type != internal::IDENTITY_TYPE_PUBLIC); - - auto it = scan_sessions_.find(id); - - if (it == scan_sessions_.end()) { - return; - } - - ScanSessionState& session = it->second; - session.credentials[identity_type] = std::move(credentials); - session.decoder = AdvertisementDecoderImpl(&session.credentials); -} - -int ScanManager::ScanningCallbacksLengthForTest() { - ::nearby::Future count; - RunOnServiceControllerThread("callbacks-size", - [&]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_) { - count.Set(scan_sessions_.size()); - }); - return count.Get().GetResult(); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/scan_manager.h b/presence/implementation/scan_manager.h deleted file mode 100644 index a174884f..00000000 --- a/presence/implementation/scan_manager.h +++ /dev/null @@ -1,109 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SCAN_MANAGER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SCAN_MANAGER_H_ - -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/mutex.h" -#include "internal/platform/mutex_lock.h" -#include "internal/platform/runnable.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_types.h" -#include "presence/implementation/advertisement_filter.h" -#include "presence/implementation/credential_manager.h" -#include "presence/implementation/mediums/mediums.h" -#include "presence/scan_request.h" - -#ifdef USE_RUST_DECODER -#include "presence/implementation/advertisement_decoder_rust_impl.h" -#else -#include "presence/implementation/advertisement_decoder_impl.h" -#endif - -namespace nearby { -namespace presence { - -// The instance of ScanManager is owned by `ServiceControllerImpl`. -// Helping service controller to manage scan requests and callbacks. -class ScanManager { - public: - using SingleThreadExecutor = ::nearby::SingleThreadExecutor; - using Mutex = ::nearby::Mutex; - using MutexLock = ::nearby::MutexLock; - using ScanningSession = ::nearby::api::ble::BleMedium::ScanningSession; - using Runnable = ::nearby::Runnable; - using BleAdvertisementData = ::nearby::api::ble::BleAdvertisementData; - using SharedCredential = ::nearby::internal::SharedCredential; - using IdentityType = ::nearby::internal::IdentityType; - - ScanManager(Mediums& mediums, CredentialManager& credential_manager, - SingleThreadExecutor& executor) { - mediums_ = &mediums, credential_manager_ = &credential_manager; - executor_ = &executor; - } - ~ScanManager() = default; - - ScanSessionId StartScan(ScanRequest scan_request, ScanCallback cb); - void StopScan(ScanSessionId session_id); - // Below functions are test only. - // Reference: go/totw/135#augmenting-the-public-api-for-tests - int ScanningCallbacksLengthForTest(); - - private: - struct ScanSessionState { - ScanRequest request; - ScanCallback callback; - absl::flat_hash_map> - credentials; - AdvertisementDecoderImpl decoder; - AdvertisementFilter advertisement_filter; - std::unique_ptr scanning_session; - }; - void NotifyFoundBle(ScanSessionId id, BleAdvertisementData data, - nearby::api::ble::BlePeripheral::UniqueId peripheral_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void NotifyLostBle(ScanSessionId id, - nearby::api::ble::BlePeripheral::UniqueId peripheral_id) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void FetchCredentials(ScanSessionId id, const ScanRequest& scan_request) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void UpdateCredentials(ScanSessionId id, IdentityType identity_type, - std::vector credentials) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(*executor_); - void RunOnServiceControllerThread(absl::string_view name, Runnable runnable) { - executor_->Execute(std::string(name), std::move(runnable)); - } - Mediums* mediums_; - CredentialManager* credential_manager_; - absl::flat_hash_map scan_sessions_ - ABSL_GUARDED_BY(*executor_); - absl::flat_hash_map - device_unique_id_to_endpoint_id_map_ ABSL_GUARDED_BY(*executor_); - SingleThreadExecutor* executor_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SCAN_MANAGER_H_ diff --git a/presence/implementation/scan_manager_test.cc b/presence/implementation/scan_manager_test.cc deleted file mode 100644 index 4ddee9ee..00000000 --- a/presence/implementation/scan_manager_test.cc +++ /dev/null @@ -1,453 +0,0 @@ -// 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 "presence/implementation/scan_manager.h" - -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "absl/types/variant.h" -#include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/byte_array.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/implementation/ble.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/logging.h" -#include "internal/platform/mac_address.h" -#include "internal/platform/medium_environment.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/proto/credential.proto.h" -#include "presence/data_element.h" -#include "presence/data_types.h" -#include "presence/implementation/credential_manager_impl.h" -#include "presence/implementation/mediums/advertisement_data.h" -#include "presence/implementation/mediums/ble.h" -#include "presence/implementation/mediums/mediums.h" -#include "presence/implementation/mock_credential_manager.h" -#include "presence/power_mode.h" -#include "presence/presence_action.h" -#include "presence/presence_device.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { -namespace { - -using AdvertisingSession = ::nearby::api::ble::BleMedium::AdvertisingSession; -using AdvertisingCallback = - ::nearby::api::ble::BleMedium::AdvertisingCallback; -using ::nearby::SingleThreadExecutor; - -using CountDownLatch = ::nearby::CountDownLatch; -using ::testing::Contains; - -class ScanManagerTest : public testing::Test { - protected: - void SetUp() override { env_.Start(); } - void TearDown() override { - executor_.Shutdown(); - env_.Stop(); - } - - std::unique_ptr StartAdvertisingOn(Ble& ble) { - auto advertisement = AdvertisementData{ - .is_extended_advertisement = false, - .content = {0x00, 0x26, 0x00, 0x40}, - }; - std::unique_ptr session = ble.StartAdvertising( - advertisement, PowerMode::kLowPower, - AdvertisingCallback{.start_advertising_result = [](absl::Status) {}}); - env_.Sync(); - return session; - } - - ScanRequest MakeDefaultScanRequest() { - std::vector> - filters = {PresenceScanFilter{ - .scan_type = ScanType::kPresenceScan, - .extended_properties = MakeDefaultExtendedProperties(), - }}; - return { - .account_name = "Test account", - .identity_types = MakeDefaultIdentityTypes(), - .scan_filters = filters, - .use_ble = true, - .scan_type = ScanType::kPresenceScan, - .power_mode = PowerMode::kBalanced, - .scan_only_when_screen_on = true, - }; - } - - ScanCallback MakeDefaultScanCallback() { - return { - .start_scan_cb = - [this](absl::Status status) { - if (status.ok()) { - start_latch_.CountDown(); - } - }, - .on_discovered_cb = - [this](PresenceDevice pd) { found_latch_.CountDown(); }, - .on_updated_cb = - [this](PresenceDevice pd) { updated_latch_.CountDown(); }, - .on_lost_cb = [this](PresenceDevice pd) { lost_latch_.CountDown(); }}; - } - - std::vector MakeDefaultIdentityTypes() { - return { - nearby::internal::IdentityType::IDENTITY_TYPE_PUBLIC, - }; - } - std::vector MakeDefaultExtendedProperties() { - return {DataElement(ActionBit::kNearbyShareAction)}; - } - SingleThreadExecutor executor_; - CredentialManagerImpl credential_manager_{&executor_}; - nearby::MediumEnvironment& env_ = {nearby::MediumEnvironment::Instance()}; - CountDownLatch start_latch_{1}; - CountDownLatch found_latch_{1}; - CountDownLatch updated_latch_{1}; - CountDownLatch lost_latch_{1}; -}; - -TEST_F(ScanManagerTest, CanStartThenStopScanning) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - // Set up advertiser - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::unique_ptr advertising_session = - StartAdvertisingOn(ble2); - - // Start scanning - ScanSessionId scan_session = - manager.StartScan(MakeDefaultScanRequest(), MakeDefaultScanCallback()); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1); - EXPECT_TRUE(start_latch_.Await().Ok()); - EXPECT_TRUE(found_latch_.Await().Ok()); - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -TEST_F(ScanManagerTest, CannotStopScanTwice) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - - ScanSessionId scan_session = - manager.StartScan(MakeDefaultScanRequest(), MakeDefaultScanCallback()); - - LOG(INFO) << "Start scan"; - EXPECT_TRUE(start_latch_.Await().Ok()); - // Ensure that we have started scanning before we try to stop. - env_.Sync(); - LOG(INFO) << "Stop scan"; - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); - LOG(INFO) << "Stop scan again"; - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -TEST_F(ScanManagerTest, TestNoFilter) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - // Set up advertiser - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::unique_ptr advertising_session = - StartAdvertisingOn(ble2); - - // Start scanning - ScanRequest scan_request_no_filter = MakeDefaultScanRequest(); - scan_request_no_filter.scan_filters.clear(); - ScanSessionId scan_session = - manager.StartScan(scan_request_no_filter, MakeDefaultScanCallback()); - - ASSERT_EQ(manager.ScanningCallbacksLengthForTest(), 1); - ASSERT_TRUE(mediums.GetBle().IsAvailable()); - EXPECT_TRUE(start_latch_.Await().Ok()); - EXPECT_TRUE(found_latch_.Await().Ok()); - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -TEST_F(ScanManagerTest, PresenceMetadataIsRetained) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - // Set up advertiser - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::unique_ptr advertising_session = - StartAdvertisingOn(ble2); - std::string address = - absl::StrCat(absl::Hex(server_adapter.GetAddress().address())); - ScanCallback callback = { - .start_scan_cb = - [this](absl::Status status) { - if (status.ok()) { - start_latch_.CountDown(); - } - }, - .on_discovered_cb = - [this, &address](PresenceDevice pd) { - if (pd.GetDeviceIdentityMetadata().bluetooth_mac_address() == - address) { - EXPECT_THAT(pd.GetExtendedProperties(), - Contains(DataElement(ActionBit::kNearbyShareAction)) - .Times(1)); - EXPECT_THAT( - pd.GetActions(), - Contains(PresenceAction{(int)ActionBit::kNearbyShareAction}) - .Times(1)); - - found_latch_.CountDown(); - } - }, - .on_updated_cb = - [this, &address](PresenceDevice pd) { - if (pd.GetDeviceIdentityMetadata().bluetooth_mac_address() == - address) { - EXPECT_THAT(pd.GetExtendedProperties(), - Contains(DataElement(ActionBit::kNearbyShareAction)) - .Times(1)); - EXPECT_THAT( - pd.GetActions(), - Contains(PresenceAction{(int)ActionBit::kNearbyShareAction}) - .Times(1)); - - updated_latch_.CountDown(); - } - }}; - // Start scanning - ScanRequest scan_request_no_filter = MakeDefaultScanRequest(); - scan_request_no_filter.scan_filters.clear(); - auto scan_session = - manager.StartScan(scan_request_no_filter, std::move(callback)); - - ASSERT_EQ(manager.ScanningCallbacksLengthForTest(), 1); - ASSERT_TRUE(mediums.GetBle().IsAvailable()); - EXPECT_TRUE(start_latch_.Await().Ok()); - EXPECT_TRUE(found_latch_.Await().Ok()); - - // Advertise again to trigger `on_updated_cb` - advertising_session = StartAdvertisingOn(ble2); - - EXPECT_TRUE(updated_latch_.Await().Ok()); - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -TEST_F(ScanManagerTest, DiscoverThenLoseAdvertisement) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - // Set up advertiser - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::unique_ptr advertising_session = - StartAdvertisingOn(ble2); - - // Start scanning - ScanSessionId scan_session = - manager.StartScan(MakeDefaultScanRequest(), MakeDefaultScanCallback()); - - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1); - EXPECT_TRUE(start_latch_.Await().Ok()); - EXPECT_TRUE(found_latch_.Await().Ok()); - - // Stop advertising to trigger `on_lost_cb` - EXPECT_OK(advertising_session->stop_advertising()); - env_.Sync(); - - EXPECT_TRUE(lost_latch_.Await().Ok()); - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -TEST_F(ScanManagerTest, StopOneSessionFromAnotherDeadlock) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - CountDownLatch start_latch2{1}; - CountDownLatch found_latch2{1}; - - // Start scanning - std::vector extended_properties_mismatch = { - DataElement(ActionBit::kInstantTetheringAction)}; - std::vector> - mismatch_filters = {PresenceScanFilter{ - .scan_type = ScanType::kPresenceScan, - .extended_properties = extended_properties_mismatch, - }}; - ScanRequest scan_request_mismatch = { - .account_name = "Test account", - .identity_types = MakeDefaultIdentityTypes(), - .scan_filters = mismatch_filters, - .use_ble = true, - .scan_type = ScanType::kPresenceScan, - .power_mode = PowerMode::kBalanced, - .scan_only_when_screen_on = true, - }; - // we use scan_request_mismatch so this session's discovery doesn't get - // triggered. - ScanSessionId scan_session = - manager.StartScan(scan_request_mismatch, MakeDefaultScanCallback()); - ScanCallback scanning_callback2 = {.start_scan_cb = - [&](absl::Status status) { - if (status.ok()) { - start_latch2.CountDown(); - } - }, - .on_discovered_cb = - [&](PresenceDevice pd) { - LOG(INFO) << "scansession2 found"; - found_latch2.CountDown(); - manager.StopScan(scan_session); - }}; - ScanSessionId scan_session2 = manager.StartScan( - MakeDefaultScanRequest(), std::move(scanning_callback2)); - - ASSERT_EQ(manager.ScanningCallbacksLengthForTest(), 2); - - // Set up advertiser - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::unique_ptr advertising_session = - StartAdvertisingOn(ble2); - - EXPECT_TRUE(found_latch2.Await().Ok()); - // Session was stopped before, this should not be able to stop successfully. - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1); - ASSERT_TRUE(mediums.GetBle().IsAvailable()); - manager.StopScan(scan_session2); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -// Receive a BLE advertisement after StopScan. `on_discovered_cb` -// must not be called. -TEST_F(ScanManagerTest, NoDeviceFoundAfterStopScan) { - Mediums mediums; - ScanManager manager(mediums, credential_manager_, executor_); - CountDownLatch start_scan_latch{1}; - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::atomic_bool stopped = false; - ScanSessionId scan_session = manager.StartScan( - MakeDefaultScanRequest(), - ScanCallback{.start_scan_cb = - [&start_scan_latch](absl::Status status) { - if (status.ok()) { - start_scan_latch.CountDown(); - } - }, - .on_discovered_cb = - [&](PresenceDevice pd) { EXPECT_FALSE(stopped); }}); - - start_scan_latch.Await(); - manager.StopScan(scan_session); - stopped = true; - std::unique_ptr advertising_session = - StartAdvertisingOn(ble2); - - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); - executor_.Shutdown(); -} - -internal::SharedCredential GetPublicCredential() { - // Values copied from LDT tests - ByteArray seed({ - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - }); - ByteArray known_mac({0x09, 0xFE, 0x9E, 0x81, 0xB7, 0x3E, 0x5E, 0xCC, - 0x76, 0x59, 0x57, 0x71, 0xE0, 0x1F, 0xFB, 0x34, - 0x38, 0xE7, 0x5F, 0x24, 0xA7, 0x69, 0x56, 0xA0, - 0xB8, 0xEA, 0x67, 0xD1, 0x1C, 0x3E, 0x36, 0xFD}); - internal::SharedCredential public_credential; - public_credential.set_key_seed(seed.AsStringView()); - public_credential.set_metadata_encryption_key_tag_v0( - known_mac.AsStringView()); - return public_credential; -} - -std::vector BuildSharedCredentials() { - return {GetPublicCredential()}; -} - -TEST_F(ScanManagerTest, ScanningE2EWithEncryptedAdvertisementAndCredentials) { - Mediums mediums; - auto mock_credential_manager = MockCredentialManager(); - EXPECT_CALL(mock_credential_manager, GetPublicCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - PublicCredentialType public_credential_type, - GetPublicCredentialsResultCallback callback) { - callback.credentials_fetched_cb(BuildSharedCredentials()); - }); - ScanManager manager(mediums, mock_credential_manager, executor_); - - // Set up advertiser to broadcast a private identity adv - nearby::BluetoothAdapter server_adapter; - Ble ble2(server_adapter); - std::string V0AdvEncryptedBytes = "042222D82212EF16DBF872F2A3A7C0FA5248EC"; - std::string payload = absl::HexStringToBytes(V0AdvEncryptedBytes); - auto advertisement = AdvertisementData{ - .is_extended_advertisement = false, - .content = payload, - }; - - std::unique_ptr session = ble2.StartAdvertising( - advertisement, PowerMode::kLowPower, - AdvertisingCallback{.start_advertising_result = [](absl::Status) {}}); - env_.Sync(); - - std::vector< - absl::variant> // NOLINT - filters = {PresenceScanFilter{ - .scan_type = ScanType::kPresenceScan, - .extended_properties = {DataElement(DataElement::kTxPowerFieldType, - 3)}, - }}; - - ScanRequest scan_request = { - .account_name = "Test account", - .identity_types = - {nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP}, - .scan_filters = filters, - .use_ble = true, - .scan_type = ScanType::kPresenceScan, - .power_mode = PowerMode::kBalanced, - .scan_only_when_screen_on = true, - }; - - // Start scanning - ScanSessionId scan_session = - manager.StartScan(scan_request, MakeDefaultScanCallback()); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 1); - EXPECT_TRUE(start_latch_.Await().Ok()); - EXPECT_TRUE(found_latch_.Await().Ok()); - manager.StopScan(scan_session); - EXPECT_EQ(manager.ScanningCallbacksLengthForTest(), 0); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/sensor_fusion.h b/presence/implementation/sensor_fusion.h deleted file mode 100644 index 31639bd7..00000000 --- a/presence/implementation/sensor_fusion.h +++ /dev/null @@ -1,153 +0,0 @@ -// 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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_ - -#include -#include -#include -#include - -#include "absl/functional/any_invocable.h" -#include "absl/status/status.h" -#include "presence/device_motion.h" -#include "presence/presence_zone.h" - -namespace nearby { -namespace presence { - -enum class DataSource { - kUnknown = 0, - kBle = 1, - kUwb = 2, - kNanRtt = 4, -}; - -struct RangingMeasurement { - // [0.0, 1.0], 1.0 is the max confidence. - float confidence_level; - float value; -}; - -struct RangingPosition { - RangingMeasurement distance; - std::optional azimuth; - std::optional elevation; - uint64_t elapsed_realtime_millis; -}; - -struct ZoneTransition { - PresenceZone::DistanceBoundary::RangeType distance_range_type; - float confidence_level; -}; - -struct RangingData { - DataSource data_source; - RangingPosition position; - std::optional zone_transition; - std::vector device_motions; -}; - -struct ZoneTransitionCallback { - absl::AnyInvocable - on_proximity_zone_changed = - [](uint64_t device_id, - PresenceZone::DistanceBoundary::RangeType proximity_zone) {}; - absl::AnyInvocable on_callback_id_generated = - [](uint64_t callback_id) {}; -}; - -class SensorFusion { - public: - virtual ~SensorFusion() = default; - - // Called when a device motion gesture is detected. - typedef std::function - DeviceMotionCallback; - - /** - * Returns a list of data sources would be used by the sensor fusion if they - * are available. - * This is to control what kinds of sources the NP scan engine should use for - * ranging. For instance, if both NAN RTT and UWB are supported, FPP may - * decide NAN RTT isn't useful at a certain moment, so NP scan engine won't - * try to request NAN RTT. - * - * @param elapsed_realtime_millis Elapsed timestamp since boot of the data - * source query. - * @param available_sources A bit mask of data sources that are available. - */ - virtual std::vector GetDataSources( - uint64_t elapsed_realtime_millis, - const std::vector& available_sources) = 0; - - /** - * Updates BLE scanned results to Sensor Fusion. - * - * @param device_id A unique device id of the peer device. - * @param txPower Calibrated TX power of the scan result, {@code - * std::nullopt} if the calibrated TX power is not available. - * @param rssi Received signal strength indicator for the scan result. - * @param elapsed_realtime_millis Elapsed timestamp since boot when the - * scan result is discovered. - */ - virtual absl::Status UpdateBleScanResult( - uint64_t device_id, std::optional txPower, int rssi, - uint64_t elapsed_realtime_millis) = 0; - /** - * Updates UWB ranging results to Sensor Fusion. - * - * @param device_id A unique device id of the peer device. - * @param position UWB ranging result (distance and optionally angle) - */ - virtual void UpdateUwbRangingResult(uint64_t device_id, - RangingPosition position) = 0; - - /** - * Adds callback for updates of proximity zone transitions. - */ - virtual void RequestZoneTransitionUpdates( - ZoneTransitionCallback callback) = 0; - - /** - * Removes callback for updates of proximity zone transitions. - */ - virtual void RemoveZoneTransitionUpdates(uint64_t callback_id) = 0; - - /** - * Adds callback for updates of device motion events. - */ - virtual void RequestDeviceMotionUpdates(DeviceMotionCallback callback) = 0; - - /** - * Remove callback for updates of device motion events. - */ - virtual void RemoveDeviceMotionUpdates(DeviceMotionCallback callback) = 0; - - /** - * Returns the best ranging estimate to a given device. Returns {@code - * std::nullopt} if the sensor fusion cannot produce a ranging estimate. - * - * @param device_id Id of the peer device. - */ - virtual std::optional GetRangingData(uint64_t device_id) = 0; -}; - -} // namespace presence -} // namespace nearby -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SENSOR_FUSION_H_ - diff --git a/presence/implementation/service_controller.h b/presence/implementation/service_controller.h deleted file mode 100644 index 9389741e..00000000 --- a/presence/implementation/service_controller.h +++ /dev/null @@ -1,76 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_H_ - -#include - -#include "absl/status/statusor.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/proto/metadata.pb.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -/* - * This class is owned in {@code PresenceService}. It specifies the function - * signatures. {@code ServiceControllerImpl} and {@code MockServiceController} - * inherit this class and provides real implementation and mock impl for tests. - */ -class ServiceController { - public: - ServiceController() = default; - virtual ~ServiceController() = default; - virtual absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) = 0; - virtual void StopScan(ScanSessionId session_id) = 0; - virtual absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) = 0; - virtual void StopBroadcast(BroadcastSessionId session_id) = 0; - virtual void UpdateLocalDeviceMetadata( - const ::nearby::internal::Metadata& metadata, bool regen_credentials, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) = 0; - virtual void UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) = 0; - virtual ::nearby::internal::DeviceIdentityMetaData - GetDeviceIdentityMetaData() = 0; - virtual void GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) = 0; - virtual void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) = 0; - virtual void GetLocalCredentials( - const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) = 0; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_H_ diff --git a/presence/implementation/service_controller_impl.cc b/presence/implementation/service_controller_impl.cc deleted file mode 100644 index 3c158fc6..00000000 --- a/presence/implementation/service_controller_impl.cc +++ /dev/null @@ -1,91 +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 "presence/implementation/service_controller_impl.h" - -#include -#include - -#include "absl/status/statusor.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "presence/data_types.h" -#include "presence/implementation/credential_manager.h" - -namespace nearby { -namespace presence { - -absl::StatusOr ServiceControllerImpl::StartScan( - ScanRequest scan_request, ScanCallback callback) { - return scan_manager_.StartScan(scan_request, std::move(callback)); -} -void ServiceControllerImpl::StopScan(ScanSessionId id) { - scan_manager_.StopScan(id); -} - -absl::StatusOr ServiceControllerImpl::StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) { - return broadcast_manager_.StartBroadcast(broadcast_request, - std::move(callback)); -} - -void ServiceControllerImpl::StopBroadcast(BroadcastSessionId id) { - broadcast_manager_.StopBroadcast(id); -} - -// TODO(b/327629276): Remove this function. -void ServiceControllerImpl::UpdateLocalDeviceMetadata( - const ::nearby::internal::Metadata& metadata, bool regen_credentials, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) {} - -void ServiceControllerImpl::UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) { - credential_manager_.SetDeviceIdentityMetaData( - device_identity_metadata, regen_credentials, manager_app_id, - identity_types, credential_life_cycle_days, - contiguous_copy_of_credentials, std::move(credentials_generated_cb)); -} - -void ServiceControllerImpl::GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) { - credential_manager_.GetPublicCredentials( - credential_selector, PublicCredentialType::kLocalPublicCredential, - std::move(callback)); -} - -void ServiceControllerImpl::UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) { - credential_manager_.UpdateRemotePublicCredentials( - manager_app_id, account_name, remote_public_creds, - std::move(credentials_updated_cb)); -} - -void ServiceControllerImpl::GetLocalCredentials( - const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - credential_manager_.GetLocalCredentials(credential_selector, - std::move(callback)); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/implementation/service_controller_impl.h b/presence/implementation/service_controller_impl.h deleted file mode 100644 index b858b7b3..00000000 --- a/presence/implementation/service_controller_impl.h +++ /dev/null @@ -1,110 +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 THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_IMPL_H_ - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/runnable.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/proto/metadata.pb.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/implementation/broadcast_manager.h" -#include "presence/implementation/credential_manager.h" -#include "presence/implementation/scan_manager.h" -#include "presence/implementation/service_controller.h" -#include "presence/scan_request.h" - -/* - * This class implements {@code ServiceController} functions. Owns mediums and - * other managers instances. - */ -namespace nearby { -namespace presence { - -class ServiceControllerImpl : public ServiceController { - public: - using SingleThreadExecutor = ::nearby::SingleThreadExecutor; - - ServiceControllerImpl(SingleThreadExecutor* executor, - CredentialManager* credential_manager, - ScanManager* scan_manager, - BroadcastManager* broadcast_manager) - : executor_(*executor), - credential_manager_(*credential_manager), - scan_manager_(*scan_manager), - broadcast_manager_(*broadcast_manager) {} - ~ServiceControllerImpl() override { executor_.Shutdown(); } - - absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) override; - void StopScan(ScanSessionId session_id) override; - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) override; - void StopBroadcast(BroadcastSessionId) override; - void UpdateLocalDeviceMetadata( - const ::nearby::internal::Metadata& metadata, bool regen_credentials, - absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) override; - void UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) override; - - ::nearby::internal::DeviceIdentityMetaData GetDeviceIdentityMetaData() - override { - return credential_manager_.GetDeviceIdentityMetaData(); - } - void GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) override; - void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) override; - void GetLocalCredentials(const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) override; - - SingleThreadExecutor& GetBackgroundExecutor() { return executor_; } - - private: - void NotifyStartCallbackStatus(BroadcastSessionId id, absl::Status status); - void RunOnServiceControllerThread(absl::string_view name, Runnable runnable) { - executor_.Execute(std::string(name), std::move(runnable)); - } - - SingleThreadExecutor& executor_; - CredentialManager& credential_manager_; - ScanManager& scan_manager_; - BroadcastManager& broadcast_manager_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_IMPL_H_ diff --git a/presence/implementation/service_controller_impl_test.cc b/presence/implementation/service_controller_impl_test.cc deleted file mode 100644 index 5d638186..00000000 --- a/presence/implementation/service_controller_impl_test.cc +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 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. -// 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 "presence/implementation/service_controller_impl.h" - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/proto/credential.pb.h" -#include "presence/implementation/broadcast_manager.h" -#include "presence/implementation/mediums/mediums.h" -#include "presence/implementation/mock_credential_manager.h" -#include "presence/implementation/scan_manager.h" - -namespace nearby { -namespace presence { -namespace { - -constexpr absl::string_view kManagerAppId = "TEST_MANAGER_APP"; -constexpr absl::string_view kAccountName = "test account"; -constexpr absl::string_view kSecretId1 = "1111111"; -constexpr absl::string_view kSecretId2 = "2222222"; -constexpr absl::string_view kSecretId3 = "3333333"; - -CredentialSelector BuildDefaultCredentialSelector() { - CredentialSelector credential_selector; - credential_selector.manager_app_id = std::string(kManagerAppId); - credential_selector.account_name = std::string(kAccountName); - credential_selector.identity_type = - ::nearby::internal::IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; - return credential_selector; -} - -std::vector BuildLocalCredentials() { - internal::LocalCredential local_credential1; - local_credential1.set_secret_id(kSecretId1); - internal::LocalCredential local_credential2; - local_credential2.set_secret_id(kSecretId2); - internal::LocalCredential local_credential3; - local_credential3.set_secret_id(kSecretId3); - return {local_credential1, local_credential2, local_credential3}; -} - -TEST(ServiceControllerImplTest, GetLocalCredentials) { - auto mock_credential_manager = std::make_unique(); - EXPECT_CALL(*mock_credential_manager.get(), GetLocalCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - callback.credentials_fetched_cb(BuildLocalCredentials()); - }); - - Mediums mediums; - SingleThreadExecutor executor; - ScanManager scan_manager{mediums, *mock_credential_manager, executor}; - BroadcastManager broadcast_manager{mediums, *mock_credential_manager, - executor}; - - auto service_controller = std::make_unique( - &executor, mock_credential_manager.get(), &scan_manager, - &broadcast_manager); - CredentialSelector credential_selector = BuildDefaultCredentialSelector(); - - absl::StatusOr> - private_credentials; - service_controller->GetLocalCredentials( - credential_selector, - {.credentials_fetched_cb = - [&](absl::StatusOr> - credentials) { - private_credentials = std::move(credentials); - }}); - - EXPECT_OK(private_credentials); - ASSERT_EQ(3u, private_credentials->size()); - ASSERT_EQ(private_credentials->at(0).secret_id(), kSecretId1); - ASSERT_EQ(private_credentials->at(1).secret_id(), kSecretId2); - ASSERT_EQ(private_credentials->at(2).secret_id(), kSecretId3); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/power_mode.h b/presence/power_mode.h deleted file mode 100644 index 229c59fd..00000000 --- a/presence/power_mode.h +++ /dev/null @@ -1,35 +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 THIRD_PARTY_NEARBY_PRESENCE_POWER_MODE_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_POWER_MODE_H_ - -namespace nearby { -namespace presence { - -// High level concept of Power mode for Scan and Broadcast. -// More frequent, more power consumption, but less interval and latency. -// Native platforms would decide the specific interval based on their own -// configs. -enum class PowerMode { - kNoPower = 0, - kLowPower = 1, - kBalanced = 2, - kLowLatency = 3, -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_POWER_MODE_H_ diff --git a/presence/presence_action.cc b/presence/presence_action.cc deleted file mode 100644 index 1265eada..00000000 --- a/presence/presence_action.cc +++ /dev/null @@ -1,31 +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 "presence/presence_action.h" - -#include "internal/platform/logging.h" - -namespace nearby { -namespace presence { - -PresenceAction::PresenceAction(int action_identifier) - : action_identifier_(action_identifier) { - CHECK(kMinActionIdentifierValue <= action_identifier_ && - action_identifier_ <= kMaxActionIdentifierValue); -} - -int PresenceAction::GetActionIdentifier() const { return action_identifier_; } - -} // namespace presence -} // namespace nearby diff --git a/presence/presence_action.h b/presence/presence_action.h deleted file mode 100644 index a073f6b6..00000000 --- a/presence/presence_action.h +++ /dev/null @@ -1,41 +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 THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_ACTION_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_ACTION_H_ - -namespace nearby { -namespace presence { -class PresenceAction { - public: - PresenceAction(int action_identifier = 1); - int GetActionIdentifier() const; - - private: - static constexpr int kMinActionIdentifierValue = 1; - static constexpr int kMaxActionIdentifierValue = 255; - const int action_identifier_; -}; - -inline bool operator==(const PresenceAction& a1, const PresenceAction& a2) { - return a1.GetActionIdentifier() == a2.GetActionIdentifier(); -} - -inline bool operator!=(const PresenceAction& a1, const PresenceAction& a2) { - return !(a1 == a2); -} -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_ACTION_H_ diff --git a/presence/presence_action_test.cc b/presence/presence_action_test.cc deleted file mode 100644 index 64b5e78e..00000000 --- a/presence/presence_action_test.cc +++ /dev/null @@ -1,59 +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 "presence/presence_action.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" - -namespace nearby { -namespace presence { -namespace { -constexpr int kDefaultActionIdentifier = 1; -constexpr int kTestActionIdentifier = 2; -TEST(PresenceActionTest, DefaultConstructorWorks) { - PresenceAction action; - EXPECT_EQ(action.GetActionIdentifier(), kDefaultActionIdentifier); -} - -TEST(PresenceActionTest, DefaultEquals) { - PresenceAction action1; - PresenceAction action2; - EXPECT_EQ(action1, action2); -} - -TEST(PresenceActionTest, ExplicitInitEquals) { - PresenceAction action1 = {kTestActionIdentifier}; - PresenceAction action2 = {kTestActionIdentifier}; - EXPECT_EQ(action1, action2); - EXPECT_EQ(action1.GetActionIdentifier(), kTestActionIdentifier); -} - -TEST(PresenceActionTest, ExplicitInitNotEquals) { - PresenceAction action1 = {kDefaultActionIdentifier}; - PresenceAction action2 = {kTestActionIdentifier}; - EXPECT_NE(action1, action2); -} - -TEST(PresenceActionTest, CopyInitEquals) { - PresenceAction action1 = {kTestActionIdentifier}; - PresenceAction action2 = {action1}; - - EXPECT_EQ(action1, action2); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/presence_client.h b/presence/presence_client.h deleted file mode 100644 index 92807d95..00000000 --- a/presence/presence_client.h +++ /dev/null @@ -1,85 +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 THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_H_ - -#include - -#include "absl/status/statusor.h" -#include "internal/platform/borrowable.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/presence_device.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -class PresenceService; -/** - * Interface for detecting and interacting with nearby devices that are also - * part of the Presence ecosystem. - */ -class PresenceClient { - public: - using BorrowablePresenceService = ::nearby::Borrowable; - - virtual ~PresenceClient() = default; - - // Starts a Nearby Presence scan and registers `ScanCallback` - // which will be invoked when a matching `PresenceDevice` is detected, - // lost, and status changed. - // The session can be terminated with `StopScan()`. - // - // `ScanCallback` is kept in the Nearby Presence service until `StopScan()` is - // called. - // - // `ScanRequest` contains the options like scan power mode - // and type; the filters including credentials, actions and extended - // properties. - virtual absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) = 0; - - // Terminates the scan session. Does nothing if the session is already - // terminated. - virtual void StopScan(ScanSessionId session_id) = 0; - - // Starts a Nearby Presence broadcast and registers `BroadcastCallback` - // which will be invoked after broadcast is started. - // The session can be terminated with `StopBroadcast()`. - // - // `BroadcastCallback` is kept in the Nearby Presence service until - // `StopBroadcast()` is called. - // - // `BroadcastRequest` contains the options like tx_power, - // the credential info like salt and private credential, the actions and - // extended properties. - virtual absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) = 0; - - // Terminates a broadcast session. Does nothing if the session is already - // terminated. - virtual void StopBroadcast(BroadcastSessionId session_id) = 0; - - // Returns the local PresenceDevice describing the current device's actions, - // connectivity info and unique identifier for use in Connections and - // Presence. - virtual std::optional GetLocalDevice() = 0; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_H_ diff --git a/presence/presence_client_impl.cc b/presence/presence_client_impl.cc deleted file mode 100644 index 706e52f2..00000000 --- a/presence/presence_client_impl.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 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. -// 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 "presence/presence_client_impl.h" - -#include -#include -#include - -#include "absl/status/status.h" -#include "internal/platform/borrowable.h" -#include "internal/platform/logging.h" -#include "presence/presence_device.h" -#include "presence/presence_service.h" - -namespace nearby { -namespace presence { - -// static -PresenceClientImpl::Factory* PresenceClientImpl::Factory::g_test_factory_ = - nullptr; - -// static -std::unique_ptr PresenceClientImpl::Factory::Create( - BorrowablePresenceService service) { - if (g_test_factory_) { - return g_test_factory_->CreateInstance(service); - } - return absl::WrapUnique(new PresenceClientImpl(service)); -} - -// static -void PresenceClientImpl::Factory::SetFactoryForTesting( - Factory* g_test_factory) { - g_test_factory_ = g_test_factory; -} - -PresenceClientImpl::Factory::~Factory() = default; - -absl::StatusOr PresenceClientImpl::StartScan( - ScanRequest scan_request, ScanCallback callback) { - ::nearby::Borrowed borrowed = service_.Borrow(); - if (!borrowed) { - return absl::FailedPreconditionError( - "Can't start scan, presence service is gone"); - } - return (*borrowed)->StartScan(scan_request, std::move(callback)); -} - -void PresenceClientImpl::StopScan(ScanSessionId id) { - ::nearby::Borrowed borrowed = service_.Borrow(); - if (borrowed) { - (*borrowed)->StopScan(id); - } -} - -absl::StatusOr PresenceClientImpl::StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) { - ::nearby::Borrowed borrowed = service_.Borrow(); - if (!borrowed) { - return absl::FailedPreconditionError( - "Can't start broadcast, presence service is gone"); - } - return (*borrowed)->StartBroadcast(broadcast_request, std::move(callback)); -} - -void PresenceClientImpl::StopBroadcast(BroadcastSessionId session_id) { - ::nearby::Borrowed borrowed = service_.Borrow(); - if (borrowed) { - (*borrowed)->StopBroadcast(session_id); - } else { - VLOG(1) << "Session already finished, id: " << session_id; - } -} - -std::optional PresenceClientImpl::GetLocalDevice() { - ::nearby::Borrowed borrowed = service_.Borrow(); - if (borrowed) { - const PresenceDevice* device = static_cast( - (*borrowed)->GetLocalDeviceProvider()->GetLocalDevice()); - return PresenceDevice(*device); - } - return std::nullopt; -} - -} // namespace presence -} // namespace nearby diff --git a/presence/presence_client_impl.h b/presence/presence_client_impl.h deleted file mode 100644 index e7f376c8..00000000 --- a/presence/presence_client_impl.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_PRESENCE_CLIENT_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_IMPL_H_ - -#include -#include - -#include "absl/status/statusor.h" -#include "internal/platform/borrowable.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/presence_client.h" -#include "presence/presence_device.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -class PresenceClientImpl : public PresenceClient{ - public: - using BorrowablePresenceService = ::nearby::Borrowable; - - class Factory { - public: - static std::unique_ptr Create( - BorrowablePresenceService service); - static void SetFactoryForTesting(Factory* test_factory); - - protected: - virtual ~Factory(); - virtual std::unique_ptr CreateInstance( - BorrowablePresenceService service) = 0; - - private: - static Factory* g_test_factory_; - }; - - PresenceClientImpl(const PresenceClientImpl&) = delete; - PresenceClientImpl(PresenceClientImpl&&) = default; - PresenceClientImpl& operator=(const PresenceClientImpl&) = delete; - ~PresenceClientImpl() override = default; - - // PresenceClient: - absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) override; - void StopScan(ScanSessionId session_id) override; - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) override; - void StopBroadcast(BroadcastSessionId session_id) override; - std::optional GetLocalDevice() override; - - private: - explicit PresenceClientImpl(BorrowablePresenceService service) - : service_(service) {} - - BorrowablePresenceService service_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_CLIENT_IMPL_H_ diff --git a/presence/presence_client_test.cc b/presence/presence_client_test.cc deleted file mode 100644 index 2c43f26f..00000000 --- a/presence/presence_client_test.cc +++ /dev/null @@ -1,151 +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 "presence/presence_client.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/future.h" -#include "internal/platform/medium_environment.h" -#include "presence/data_types.h" -#include "presence/presence_device.h" -#include "presence/presence_service_impl.h" - -namespace nearby { -namespace presence { -namespace { - -using ::nearby::internal::DeviceIdentityMetaData; -using ::testing::status::StatusIs; - -constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; - -// Creates a PresenceClient and destroys PresenceServiceImpl that was used to -// create it. -std::unique_ptr CreateDefunctPresenceClient() { - PresenceServiceImpl presence_service; - return presence_service.CreatePresenceClient(); -} - -DeviceIdentityMetaData CreateTestDeviceIdentityMetaData() { - DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_device_type( - internal::DeviceType::DEVICE_TYPE_PHONE); - device_identity_metadata.set_device_name("NP test device"); - device_identity_metadata.set_bluetooth_mac_address(kMacAddr); - device_identity_metadata.set_device_id("\x12\xab\xcd"); - return device_identity_metadata; -} - -class PresenceClientTest : public testing::Test { - protected: - nearby::MediumEnvironment& env_{nearby::MediumEnvironment::Instance()}; -}; - -TEST_F(PresenceClientTest, StartBroadcastWithDefaultConstructor) { - env_.Start(); - absl::Status broadcast_result; - - PresenceServiceImpl presence_service; - std::unique_ptr presence_client = - presence_service.CreatePresenceClient(); - auto unused = presence_client->StartBroadcast( - {}, { - .start_broadcast_cb = - [&](absl::Status status) { broadcast_result = status; }, - }); - - EXPECT_THAT(broadcast_result, StatusIs(absl::StatusCode::kInvalidArgument)); - env_.Stop(); -} - -TEST_F(PresenceClientTest, StartBroadcastFailsWhenPresenceServiceIsGone) { - env_.Start(); - absl::Status broadcast_result = absl::UnknownError(""); - - absl::StatusOr session_id = - CreateDefunctPresenceClient()->StartBroadcast( - {}, { - .start_broadcast_cb = - [&](absl::Status status) { broadcast_result = status; }, - }); - - EXPECT_THAT(session_id, StatusIs(absl::StatusCode::kFailedPrecondition)); - EXPECT_THAT(broadcast_result, StatusIs(absl::StatusCode::kUnknown)); - env_.Stop(); -} - -TEST_F(PresenceClientTest, StartScanWithDefaultConstructor) { - env_.Start(); - ::nearby::Future scan_result; - ScanCallback scan_callback = { - .start_scan_cb = [&](absl::Status status) { scan_result.Set(status); }, - }; - - PresenceServiceImpl presence_service; - std::unique_ptr presence_client = - presence_service.CreatePresenceClient(); - EXPECT_OK(presence_client->StartScan({}, std::move(scan_callback))); - - EXPECT_TRUE(scan_result.Get().ok()); - EXPECT_OK(scan_result.Get().GetResult()); - env_.Stop(); -} - -TEST_F(PresenceClientTest, StartScanFailsWhenPresenceServiceIsGone) { - env_.Start(); - absl::Status scan_result = absl::UnknownError(""); - - absl::StatusOr session_id = - CreateDefunctPresenceClient()->StartScan( - {}, { - .start_scan_cb = - [&](absl::Status status) { scan_result = status; }, - }); - - EXPECT_THAT(session_id, StatusIs(absl::StatusCode::kFailedPrecondition)); - EXPECT_THAT(scan_result, StatusIs(absl::StatusCode::kUnknown)); - env_.Stop(); -} - -TEST_F(PresenceClientTest, GettingDeviceWorks) { - PresenceServiceImpl presence_service; - std::unique_ptr presence_client = - presence_service.CreatePresenceClient(); - presence_service.UpdateDeviceIdentityMetaData( - CreateTestDeviceIdentityMetaData(), false, "", {}, 0, 0, {}); - auto device = presence_client->GetLocalDevice(); - ASSERT_NE(device, std::nullopt); - EXPECT_EQ(device->GetEndpointId().length(), kEndpointIdLength); - EXPECT_EQ(device->GetDeviceIdentityMetadata().SerializeAsString(), - CreateTestDeviceIdentityMetaData().SerializeAsString()); -} - -TEST_F(PresenceClientTest, TestGettingDeviceDefunct) { - std::unique_ptr presence_client = - CreateDefunctPresenceClient(); - auto device = presence_client->GetLocalDevice(); - EXPECT_EQ(device, std::nullopt); -} -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/presence_device.cc b/presence/presence_device.cc deleted file mode 100644 index e2651089..00000000 --- a/presence/presence_device.cc +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 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. -// 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 "presence/presence_device.h" - -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/types/variant.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" -#include "internal/interop/device.h" -#include "internal/platform/ble_connection_info.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/prng.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/metadata.pb.h" -#include "presence/device_motion.h" - -namespace nearby { -namespace presence { - -namespace { -constexpr char kEndpointIdChars[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}; - -// LINT.IfChange -constexpr int kAndroidIdentityTypeUnknown = -1; -constexpr int kAndroidIdentityTypePrivateGroup = 0; -constexpr int kAndroidIdentityTypeContactsGroup = 1; -constexpr int kAndroidIdentityTypePublic = 2; -// LINT.ThenChange( -// //depot/google3/java/com/google/android/gmscore/integ/client/nearby/src/com/google/android/gms/nearby/presence/PresenceIdentity.java -// ) - -std::string GenerateRandomEndpointId() { - std::string result(kEndpointIdLength, 0); - nearby::Prng prng; - for (int i = 0; i < kEndpointIdLength; i++) { - result[i] = kEndpointIdChars[prng.NextUint32() % sizeof(kEndpointIdChars)]; - } - return result; -} - -location::nearby::connections::PresenceDevice::DeviceType -ConvertToConnectionsDeviceType(internal::DeviceType device_type) { - switch (device_type) { - case internal::DEVICE_TYPE_FOLDABLE: - case internal::DEVICE_TYPE_PHONE: - return location::nearby::connections::PresenceDevice::PHONE; - case internal::DEVICE_TYPE_TABLET: - return location::nearby::connections::PresenceDevice::TABLET; - case internal::DEVICE_TYPE_DISPLAY: - return location::nearby::connections::PresenceDevice::DISPLAY; - case internal::DEVICE_TYPE_CHROMEOS: - case internal::DEVICE_TYPE_LAPTOP: - return location::nearby::connections::PresenceDevice::LAPTOP; - case internal::DEVICE_TYPE_TV: - return location::nearby::connections::PresenceDevice::TV; - case internal::DEVICE_TYPE_WATCH: - return location::nearby::connections::PresenceDevice::WATCH; - default: - return location::nearby::connections::PresenceDevice::UNKNOWN; - } -} - -int ConvertToAndroidIdentityType(nearby::internal::IdentityType identity_type) { - switch (identity_type) { - case internal::IDENTITY_TYPE_PRIVATE_GROUP: - return kAndroidIdentityTypePrivateGroup; - case internal::IDENTITY_TYPE_CONTACTS_GROUP: - return kAndroidIdentityTypeContactsGroup; - case internal::IDENTITY_TYPE_PUBLIC: - return kAndroidIdentityTypePublic; - default: - // Unknown identity. - return kAndroidIdentityTypeUnknown; - } -} -} // namespace - -PresenceDevice::PresenceDevice(absl::string_view endpoint_id) noexcept - : endpoint_id_(endpoint_id) {} - -PresenceDevice::PresenceDevice( - DeviceIdentityMetaData device_identity_metadata) noexcept - : discovery_timestamp_(nearby::SystemClock::ElapsedRealtime()), - device_motion_(DeviceMotion()), - device_identity_metadata_(device_identity_metadata) { - endpoint_id_ = GenerateRandomEndpointId(); -} -PresenceDevice::PresenceDevice( - DeviceMotion device_motion, - DeviceIdentityMetaData device_identity_metadata) noexcept - : discovery_timestamp_(nearby::SystemClock::ElapsedRealtime()), - device_motion_(device_motion), - device_identity_metadata_(device_identity_metadata) { - endpoint_id_ = GenerateRandomEndpointId(); -} - -PresenceDevice::PresenceDevice( - DeviceMotion device_motion, DeviceIdentityMetaData device_identity_metadata, - nearby::internal::IdentityType identity_type) noexcept - : discovery_timestamp_(nearby::SystemClock::ElapsedRealtime()), - device_motion_(device_motion), - device_identity_metadata_(device_identity_metadata), - identity_type_(identity_type) { - endpoint_id_ = GenerateRandomEndpointId(); -} - -std::vector PresenceDevice::GetConnectionInfos() - const { - std::vector transformed_actions; - transformed_actions.reserve(actions_.size()); - for (const auto& action : actions_) { - transformed_actions.push_back(action.GetActionIdentifier()); - } - return {nearby::BleConnectionInfo( - device_identity_metadata_.bluetooth_mac_address(), - /*gatt_characteristic=*/"", /*psm=*/"", transformed_actions)}; -} - -std::string PresenceDevice::ToProtoBytes() const { - location::nearby::connections::PresenceDevice device; - device.set_endpoint_id(endpoint_id_); - device.add_identity_type(ConvertToAndroidIdentityType(identity_type_)); - device.set_endpoint_type( - location::nearby::connections::EndpointType::PRESENCE_ENDPOINT); - auto* actions = device.mutable_actions(); - for (const auto& action : actions_) { - actions->Add(action.GetActionIdentifier()); - } - std::string connection_infos = ""; - for (const auto& connection_info : GetConnectionInfos()) { - if (absl::holds_alternative(connection_info)) { - continue; - } - if (absl::holds_alternative(connection_info)) { - connection_infos += - absl::get(connection_info).ToDataElementBytes(); - } - if (absl::holds_alternative(connection_info)) { - connection_infos += absl::get(connection_info) - .ToDataElementBytes(); - } - if (absl::holds_alternative(connection_info)) { - connection_infos += absl::get(connection_info) - .ToDataElementBytes(); - } - } - device.set_device_type( - ConvertToConnectionsDeviceType(device_identity_metadata_.device_type())); - device.set_device_name(device_identity_metadata_.device_name()); - device.set_connectivity_info_list(connection_infos); - device.set_device_image_url("dummy url"); // Not used. - return device.SerializeAsString(); -} -} // namespace presence -} // namespace nearby diff --git a/presence/presence_device.h b/presence/presence_device.h deleted file mode 100644 index 93bac818..00000000 --- a/presence/presence_device.h +++ /dev/null @@ -1,129 +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 THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_H_ - -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "internal/interop/device.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/metadata.pb.h" -#include "presence/data_element.h" -#include "presence/device_motion.h" -#include "presence/presence_action.h" - -namespace nearby { -namespace presence { - -inline constexpr int kEndpointIdLength = 4; - -class PresenceDevice : public nearby::NearbyDevice { - using Metadata = ::nearby::internal::Metadata; - using DeviceIdentityMetaData = ::nearby::internal::DeviceIdentityMetaData; - - public: - explicit PresenceDevice(absl::string_view endpoint_id) noexcept; - explicit PresenceDevice( - DeviceIdentityMetaData device_identity_metadata) noexcept; - explicit PresenceDevice( - DeviceMotion device_motion, - DeviceIdentityMetaData device_identity_metadata) noexcept; - explicit PresenceDevice( - DeviceMotion device_motion, - DeviceIdentityMetaData device_identity_metadata, - nearby::internal::IdentityType identity_type) noexcept; - std::string GetEndpointId() const override { return endpoint_id_; } - std::vector GetConnectionInfos() - const override; - std::string ToProtoBytes() const override; - void AddExtendedProperty(const DataElement& data_element) { - extended_properties_.push_back(data_element); - } - void AddExtendedProperties(const std::vector& properties) { - extended_properties_.insert(extended_properties_.end(), properties.begin(), - properties.end()); - } - std::vector GetExtendedProperties() const { - return extended_properties_; - } - void AddAction(const PresenceAction& action) { actions_.push_back(action); } - std::vector GetActions() const { return actions_; } - NearbyDevice::Type GetType() const override { - return NearbyDevice::Type::kPresenceDevice; - } - DeviceMotion GetDeviceMotion() const { return device_motion_; } - DeviceIdentityMetaData GetDeviceIdentityMetadata() const { - return device_identity_metadata_; - } - void SetDeviceIdentityMetaData( - const DeviceIdentityMetaData& device_identity_metadata) { - device_identity_metadata_ = device_identity_metadata; - } - void SetDecryptSharedCredential( - const internal::SharedCredential& decrypt_shared_credential) { - decrypt_shared_credential_ = decrypt_shared_credential; - } - const std::optional& GetDecryptSharedCredential() - const { - return decrypt_shared_credential_; - } - absl::Time GetDiscoveryTimestamp() const { return discovery_timestamp_; } - internal::IdentityType GetIdentityType() const { return identity_type_; } - - private: - const absl::Time discovery_timestamp_; - const DeviceMotion device_motion_; - DeviceIdentityMetaData device_identity_metadata_; - std::vector extended_properties_; - std::vector actions_; - std::string endpoint_id_; - internal::IdentityType identity_type_ = internal::IDENTITY_TYPE_UNSPECIFIED; - std::optional decrypt_shared_credential_; -}; - -// Timestamp is not used for equality since if the same device is discovered -// twice, they will have different timestamps and thus will show up as two -// different devices when they are the same device. -inline bool operator==(const PresenceDevice& d1, const PresenceDevice& d2) { - bool shared_credential_equality = true; - shared_credential_equality &= d1.GetDecryptSharedCredential().has_value() == - d2.GetDecryptSharedCredential().has_value(); - if (shared_credential_equality && - d1.GetDecryptSharedCredential().has_value()) { - shared_credential_equality &= - d1.GetDecryptSharedCredential()->SerializeAsString() == - d2.GetDecryptSharedCredential()->SerializeAsString(); - } - return d1.GetDeviceMotion() == d2.GetDeviceMotion() && - d1.GetDeviceIdentityMetadata().SerializeAsString() == - d2.GetDeviceIdentityMetadata().SerializeAsString() && - d1.GetActions() == d2.GetActions() && - d1.GetExtendedProperties() == d2.GetExtendedProperties() && - d1.GetIdentityType() == d2.GetIdentityType() && - shared_credential_equality; -} - -inline bool operator!=(const PresenceDevice& d1, const PresenceDevice& d2) { - return !(d1 == d2); -} - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_H_ diff --git a/presence/presence_device_provider.cc b/presence/presence_device_provider.cc deleted file mode 100644 index 1b0d4258..00000000 --- a/presence/presence_device_provider.cc +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 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. -// 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 "presence/presence_device_provider.h" - -#include -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "absl/types/variant.h" -#include "internal/interop/authentication_status.h" -#include "internal/interop/authentication_transport.h" -#include "internal/interop/device.h" -#include "internal/platform/exception.h" -#include "internal/platform/future.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/platform/logging.h" -#include "presence/implementation/connection_authenticator.h" -#include "presence/implementation/service_controller.h" -#include "presence/presence_device.h" -#include "presence/proto/presence_frame.pb.h" - -namespace nearby { -namespace presence { - -namespace { - -constexpr int kPresenceVersion = 1; - -// TODO(b/317215548): Use Status code rather than custom defined -// authentication status. -std::string AuthenticationErrorToString(AuthenticationStatus status) { - switch (status) { - case AuthenticationStatus::kUnknown: - return "AuthenticationStatus::kUnknown"; - case AuthenticationStatus::kSuccess: - return "AuthenticationStatus::kSuccess"; - case AuthenticationStatus::kFailure: - return "AuthenticationStatus::kFailure"; - } - LOG(ERROR) << "Unexpected value for AuthenticationStatus: " - << static_cast(status); - return "AuthenticationStatus::kUnknown"; -} - -std::optional GetValidCredential( - std::vector local_credentials) { - absl::Time now = SystemClock::ElapsedRealtime(); - for (auto& credential : local_credentials) { - if (absl::FromUnixMillis(credential.start_time_millis()) <= now && - absl::FromUnixMillis(credential.end_time_millis()) > now) { - return credential; - } - } - return std::nullopt; -} - -PresenceAuthenticationFrame BuildInitiatorPresenceAuthenticationFrame( - ConnectionAuthenticator::InitiatorData initiator_data_variant) { - // It is expected that the `PresenceAuthenticationFrame` built for the - // initator role always is `TwoWayInitiatorData`, since the local device is - // always expected to have a valid local credential to be used, and this is - // verified in AuthenticateAsInitiator(), which returns failure if no valid - // local credential is found (which is expected to not happen, since valid - // credentials will be generated if needed before the authentiation is - // called). - // - // Note: std::holds_alternative and std::get cannot be used here because - // they are not supported in Chromium. - DCHECK(absl::holds_alternative( - initiator_data_variant)); - auto two_way_initiator_data = - absl::get( - initiator_data_variant); - - PresenceAuthenticationFrame authentication_frame; - authentication_frame.set_version(kPresenceVersion); - authentication_frame.set_private_key_signature( - two_way_initiator_data.private_key_signature); - authentication_frame.set_shared_credential_id_hash( - two_way_initiator_data.shared_credential_hash); - return authentication_frame; -} - -} // namespace - -PresenceDeviceProvider::PresenceDeviceProvider( - ServiceController* service_controller, - const ConnectionAuthenticator* connection_authenticator) - : service_controller_(*service_controller), - device_(service_controller_.GetDeviceIdentityMetaData()), - connection_authenticator_(*connection_authenticator) { - CHECK(connection_authenticator); -} - -AuthenticationStatus PresenceDeviceProvider::AuthenticateAsInitiator( - const NearbyDevice& remote_device, absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport) const { - Future response; - - // 1. Fetch the local credentials and select the correct one to use - // for authentication by calling `GetValidCredential()`, which - // iterates over the returned list and returns the local credential - // that corresponds with the current time. - // - // TODO(b/304843571): Add support for additional IdentityTypes and for - // AuthenticationStatus::kUnknown. Currently, only `IDENTITY_TYPE_PRIVATE` is - // supported in order to unblock Nearby Presence MVP on CrOS, however in - // order to support future IdentityTypes, there needs to be a way to - // plumb in the requested identity type, as well as report back the - // unknown result to callers in NC. - service_controller_.GetLocalCredentials( - /*credential_selector=*/{.manager_app_id = manager_app_id_, - .account_name = "dummy_account_name", - .identity_type = ::nearby::internal:: - IdentityType::IDENTITY_TYPE_PRIVATE_GROUP}, - /*callback=*/{.credentials_fetched_cb = [this, &response, &remote_device, - &authentication_transport, - &shared_secret]( - auto status_or_credentials) { - if (!status_or_credentials.ok()) { - LOG(INFO) << __func__ << ": failure to fetch local credentials"; - response.Set(AuthenticationStatus::kFailure); - return; - } - - auto credential = GetValidCredential(status_or_credentials.value()); - if (!credential.has_value()) { - LOG(INFO) << __func__ << ": failure to find a valid local credential"; - response.Set(AuthenticationStatus::kFailure); - return; - } - - // 2. Construct the frame and write to the - // |authentication_transport|. - if (!WriteToRemoteDevice( - /*remote_device=*/remote_device, - /*shared_secret=*/shared_secret, - /*authentication_transport=*/authentication_transport, - /*local_credential=*/credential.value(), - /*response=*/response)) { - response.Set(AuthenticationStatus::kFailure); - return; - } - - // 3. Read the message from the remote device via - // |authentication_transport| and verify the response data. - if (!ReadAndVerifyRemoteDeviceData( - /*remote_device=*/remote_device, - /*shared_secret=*/shared_secret, - /*authentication_transport=*/authentication_transport)) { - response.Set(AuthenticationStatus::kFailure); - return; - } - - // 4. Return the status of the authentication to the callers. - response.Set(AuthenticationStatus::kSuccess); - }}); - - LOG(INFO) << __func__ << ": Waiting for future to complete"; - ExceptionOr result = response.Get(); - CHECK(result.ok()); - - LOG(INFO) << "Future:[" << __func__ << "] completed with status:" - << AuthenticationErrorToString(result.result()); - return result.result(); -} - -bool PresenceDeviceProvider::WriteToRemoteDevice( - const NearbyDevice& remote_device, absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport, - const internal::LocalCredential& local_credential, - Future& response) const { - // Cast the |remote_device| to a `PresenceDevice` in order to retrieve - // it's shared credentials, which is safe to do since the |remote_device| - // passed to the `PresenceDeviceProvider` will always be a `PresenceDevice`. - const PresenceDevice* remote_presence_device = - static_cast(&remote_device); - auto shared_credential = remote_presence_device->GetDecryptSharedCredential(); - if (!shared_credential.has_value()) { - LOG(INFO) - << __func__ - << ": failure due to no decrypt shared credential from remote device"; - return false; - } - - auto status_or_initiator_data = - connection_authenticator_.BuildSignedMessageAsInitiator( - /*ukey2_secret=*/shared_secret, /*local_credential=*/local_credential, - /*shared_credential=*/shared_credential.value()); - if (!status_or_initiator_data.ok()) { - LOG(INFO) << __func__ << ": failure to build signed message as initiator"; - return false; - } - - // Once the initiator data has been built, construct the Presence frame - // which will be written to the device with the built data. - authentication_transport.WriteMessage( - BuildInitiatorPresenceAuthenticationFrame( - status_or_initiator_data.value()) - .SerializeAsString()); - return true; -} - -bool PresenceDeviceProvider::ReadAndVerifyRemoteDeviceData( - const NearbyDevice& remote_device, absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport) const { - // Fetch the local public credentials to be used to verify the response data. - Future read_and_verify_result; - service_controller_.GetLocalPublicCredentials( - /*credential_selector=*/{.manager_app_id = manager_app_id_, - .account_name = "dummy_account_name", - .identity_type = ::nearby::internal:: - IdentityType::IDENTITY_TYPE_PRIVATE_GROUP}, - /*callback=*/{.credentials_fetched_cb = [this, &read_and_verify_result, - &authentication_transport, - &shared_secret]( - auto status_or_credentials) { - if (!status_or_credentials.ok()) { - LOG(INFO) << __func__ - << ": failure to fetch local public credentials"; - read_and_verify_result.Set(/*success=*/false); - return; - } - - std::string response_data = authentication_transport.ReadMessage(); - auto status = connection_authenticator_.VerifyMessageAsInitiator( - /*authentication_data=*/{.private_key_signature = response_data}, - /*ukey2_secret=*/shared_secret, - /*shared_credential=*/status_or_credentials.value()); - if (!status.ok()) { - LOG(INFO) << __func__ << ": failure to verify remote device"; - read_and_verify_result.Set(/*success=*/false); - return; - } - - read_and_verify_result.Set(/*success=*/true); - }}); - - LOG(INFO) << __func__ << ": Waiting for future to complete"; - ExceptionOr result = read_and_verify_result.Get(); - LOG(INFO) << "Future:[" << __func__ - << "] completed with status:" << result.result(); - return result.result(); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/presence_device_provider.h b/presence/presence_device_provider.h deleted file mode 100644 index afa1df51..00000000 --- a/presence/presence_device_provider.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_PRESENCE_DEVICE_PROVIDER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_PROVIDER_H_ - -#include -#include - -#include "absl/strings/string_view.h" -#include "internal/interop/authentication_status.h" -#include "internal/interop/authentication_transport.h" -#include "internal/interop/device.h" -#include "internal/interop/device_provider.h" -#include "internal/platform/future.h" -#include "internal/proto/local_credential.pb.h" -#include "internal/proto/metadata.pb.h" -#include "presence/implementation/connection_authenticator.h" -#include "presence/presence_device.h" - -namespace nearby { -namespace presence { - -class ServiceController; - -class PresenceDeviceProvider : public NearbyDeviceProvider { - public: - PresenceDeviceProvider( - ServiceController* service_controller, - const ConnectionAuthenticator* connection_authenticator); - - const NearbyDevice* GetLocalDevice() override { return &device_; } - - // To authenticate as an initiator (when the device is in the scanning role), - // the PresenceDeviceProvider will block and: - // 1. Fetch the local credentials and select the correct one to use for - // authentication. - // 2. Construct the frame and write to the |authentication_transport|. - // 3. Read the message from the remote device via |authentication_transport|. - // 4. Return the status of the authentication to the callers. - AuthenticationStatus AuthenticateAsInitiator( - const NearbyDevice& remote_device, absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport) const override; - - AuthenticationStatus AuthenticateAsResponder( - absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport) const override { - // TODO(b/282027237): Implement. - return AuthenticationStatus::kUnknown; - } - - void UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata) { - device_.SetDeviceIdentityMetaData(device_identity_metadata); - } - - void SetManagerAppId(absl::string_view manager_app_id) { - manager_app_id_ = manager_app_id; - } - - std::string GetManagerAppId() { return manager_app_id_; } - - private: - bool WriteToRemoteDevice( - const NearbyDevice& remote_device, absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport, - const internal::LocalCredential& local_credential, - Future& response) const; - bool ReadAndVerifyRemoteDeviceData( - const NearbyDevice& remote_device, absl::string_view shared_secret, - const AuthenticationTransport& authentication_transport) const; - - ServiceController& service_controller_; - PresenceDevice device_; - std::string manager_app_id_; - const ConnectionAuthenticator& connection_authenticator_; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_PROVIDER_H_ diff --git a/presence/presence_device_provider_test.cc b/presence/presence_device_provider_test.cc deleted file mode 100644 index a8985270..00000000 --- a/presence/presence_device_provider_test.cc +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 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. -// 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 "presence/presence_device_provider.h" - -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "internal/crypto/ed25519.h" -#include "internal/interop/authentication_status.h" -#include "internal/interop/authentication_transport.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/implementation/system_clock.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/local_credential.pb.h" -#include "internal/proto/metadata.pb.h" -#include "presence/implementation/connection_authenticator.h" -#include "presence/implementation/mock_connection_authenticator.h" -#include "presence/implementation/mock_service_controller.h" -#include "presence/presence_device.h" -#include "presence/proto/presence_frame.pb.h" - -namespace nearby { -namespace presence { -namespace { -using ::nearby::internal::DeviceIdentityMetaData; - -constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; -constexpr absl::string_view kManagerAppId = "test_app_id"; -constexpr char kUkey2Secret[] = {0x34, 0x56, 0x78, 0x90}; -constexpr char kKeySeed[] = {1, 2, 3, 4, 5, 6, 7, 8}; -constexpr int kPresenceVersion = 1; -constexpr absl::string_view kSharedCredentialHash = "shared_cred_hash"; -constexpr absl::string_view kPrivateKeySignature = "private_key_signature"; - -DeviceIdentityMetaData CreateTestDeviceIdentityMetaData() { - DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_device_type( - internal::DeviceType::DEVICE_TYPE_PHONE); - device_identity_metadata.set_device_name("NP test device"); - device_identity_metadata.set_bluetooth_mac_address(kMacAddr); - device_identity_metadata.set_device_id("\x12\xab\xcd"); - return device_identity_metadata; -} - -nearby::internal::LocalCredential CreateValidLocalCredential( - const crypto::Ed25519KeyPair& key_pair) { - nearby::internal::LocalCredential credential; - absl::Time now = SystemClock::ElapsedRealtime(); - credential.set_start_time_millis(absl::ToUnixMillis(now)); - credential.set_end_time_millis(absl::ToUnixMillis(now + absl::Minutes(10))); - credential.mutable_connection_signing_key()->set_key( - absl::StrCat(key_pair.private_key, key_pair.public_key)); - credential.set_key_seed(kKeySeed); - return credential; -} - -nearby::internal::LocalCredential CreateExpiredLocalCredential() { - nearby::internal::LocalCredential credential; - absl::Time now = SystemClock::ElapsedRealtime(); - credential.set_start_time_millis(absl::ToUnixMillis(now - absl::Minutes(30))); - credential.set_end_time_millis(absl::ToUnixMillis(now - absl::Minutes(10))); - return credential; -} - -internal::SharedCredential BuildSharedCredential( - const crypto::Ed25519KeyPair& key_pair) { - internal::SharedCredential shared_credential; - shared_credential.set_connection_signature_verification_key( - key_pair.public_key); - shared_credential.set_key_seed(kKeySeed); - return shared_credential; -} - -ConnectionAuthenticator::TwoWayInitiatorData BuildDefaultInitiatorData() { - ConnectionAuthenticator::TwoWayInitiatorData data; - data.shared_credential_hash = kSharedCredentialHash; - data.private_key_signature = kPrivateKeySignature; - return data; -} - -class MockAuthenticationTransport : public AuthenticationTransport { - public: - MOCK_METHOD(void, WriteMessage, (absl::string_view), (const, override)); - MOCK_METHOD(std::string, ReadMessage, (), (const, override)); -}; - -class PresenceDeviceProviderTest : public ::testing::Test { - public: - PresenceDeviceProviderTest() { - ON_CALL(mock_service_controller_, GetDeviceIdentityMetaData) - .WillByDefault(testing::Return(CreateTestDeviceIdentityMetaData())); - provider_ = std::make_unique( - &mock_service_controller_, &mock_connection_authenticator_); - } - - void SetUp() override { - auto key_pair_or_status = crypto::Ed25519Signer::CreateNewKeyPair(); - ASSERT_OK_AND_ASSIGN(key_pair_, key_pair_or_status); - } - - protected: - MockServiceController mock_service_controller_; - std::unique_ptr provider_; - crypto::Ed25519KeyPair key_pair_; - MockConnectionAuthenticator mock_connection_authenticator_; -}; - -TEST_F(PresenceDeviceProviderTest, ProviderIsNotTriviallyConstructible) { - EXPECT_FALSE(std::is_trivially_constructible::value); -} - -TEST_F(PresenceDeviceProviderTest, DeviceProviderWorks) { - auto device = provider_->GetLocalDevice(); - ASSERT_EQ(device->GetType(), NearbyDevice::Type::kPresenceDevice); - auto presence_device = static_cast(device); - EXPECT_EQ(presence_device->GetDeviceIdentityMetadata().SerializeAsString(), - CreateTestDeviceIdentityMetaData().SerializeAsString()); -} - -TEST_F(PresenceDeviceProviderTest, DeviceProviderCanUpdateDevice) { - auto device = provider_->GetLocalDevice(); - ASSERT_EQ(device->GetType(), NearbyDevice::Type::kPresenceDevice); - auto presence_device = static_cast(device); - EXPECT_EQ(presence_device->GetDeviceIdentityMetadata().SerializeAsString(), - CreateTestDeviceIdentityMetaData().SerializeAsString()); - auto new_metadata = CreateTestDeviceIdentityMetaData(); - new_metadata.set_device_name("NP interop device"); - provider_->UpdateDeviceIdentityMetaData(new_metadata); - EXPECT_EQ(presence_device->GetDeviceIdentityMetadata().SerializeAsString(), - new_metadata.SerializeAsString()); -} - -TEST_F(PresenceDeviceProviderTest, SetGetManagerAppId) { - provider_->SetManagerAppId(kManagerAppId); - EXPECT_EQ(provider_->GetManagerAppId(), kManagerAppId); -} - -TEST_F(PresenceDeviceProviderTest, - AuthenticateAsInitiatorFails_FailToFetchCredentials) { - EXPECT_CALL(mock_service_controller_, GetLocalCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - std::move(callback.credentials_fetched_cb)( - absl::Status(absl::StatusCode::kCancelled, /*msg=*/std::string())); - }); - - PresenceDevice remote_device(CreateTestDeviceIdentityMetaData()); - MockAuthenticationTransport authentication_transport; - auto status = provider_->AuthenticateAsInitiator( - /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, - /*authentication_transport=*/authentication_transport); - EXPECT_EQ(AuthenticationStatus::kFailure, status); -} - -TEST_F(PresenceDeviceProviderTest, - AuthenticateAsInitiatorFails_NoValidCredentials) { - EXPECT_CALL(mock_service_controller_, GetLocalCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - std::vector credentials; - credentials.push_back(CreateExpiredLocalCredential()); - std::move(callback.credentials_fetched_cb)(credentials); - }); - - PresenceDevice remote_device(CreateTestDeviceIdentityMetaData()); - MockAuthenticationTransport authentication_transport; - auto status = provider_->AuthenticateAsInitiator( - /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, - /*authentication_transport=*/authentication_transport); - EXPECT_EQ(AuthenticationStatus::kFailure, status); -} - -TEST_F(PresenceDeviceProviderTest, - AuthenticateAsInitiator_NoRemoteSharedCredential) { - EXPECT_CALL(mock_service_controller_, GetLocalCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - std::vector credentials; - credentials.push_back(CreateValidLocalCredential(key_pair_)); - std::move(callback.credentials_fetched_cb)(credentials); - }); - - PresenceDevice remote_device(CreateTestDeviceIdentityMetaData()); - MockAuthenticationTransport authentication_transport; - auto status = provider_->AuthenticateAsInitiator( - /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, - /*authentication_transport=*/authentication_transport); - - EXPECT_EQ(AuthenticationStatus::kFailure, status); -} - -TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_FailureToVerify) { - EXPECT_CALL(mock_service_controller_, GetLocalCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - std::vector credentials; - credentials.push_back(CreateValidLocalCredential(key_pair_)); - std::move(callback.credentials_fetched_cb)(credentials); - }); - EXPECT_CALL(mock_service_controller_, GetLocalPublicCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) { - std::vector credentials; - credentials.push_back(BuildSharedCredential(key_pair_)); - std::move(callback.credentials_fetched_cb)(credentials); - }); - - PresenceDevice remote_device(CreateTestDeviceIdentityMetaData()); - remote_device.SetDecryptSharedCredential(BuildSharedCredential(key_pair_)); - - MockAuthenticationTransport authentication_transport; - EXPECT_CALL(authentication_transport, WriteMessage) - .WillOnce([&](absl::string_view message) { - PresenceAuthenticationFrame authentication_frame; - EXPECT_TRUE(authentication_frame.ParseFromString(message)); - EXPECT_EQ(kPresenceVersion, authentication_frame.version()); - }); - EXPECT_CALL(authentication_transport, ReadMessage).WillOnce([&]() { - PresenceAuthenticationFrame authentication_frame; - return authentication_frame.SerializeAsString(); - }); - - EXPECT_CALL(mock_connection_authenticator_, BuildSignedMessageAsInitiator) - .WillOnce(testing::Return(BuildDefaultInitiatorData())); - EXPECT_CALL(mock_connection_authenticator_, VerifyMessageAsInitiator) - .WillOnce(testing::Return( - absl::Status(absl::StatusCode::kCancelled, /*msg=*/std::string()))); - - auto status = provider_->AuthenticateAsInitiator( - /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, - /*authentication_transport=*/authentication_transport); - EXPECT_EQ(AuthenticationStatus::kFailure, status); -} - -TEST_F(PresenceDeviceProviderTest, AuthenticateAsInitiator_Success) { - EXPECT_CALL(mock_service_controller_, GetLocalCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetLocalCredentialsResultCallback callback) { - std::vector credentials; - credentials.push_back(CreateValidLocalCredential(key_pair_)); - std::move(callback.credentials_fetched_cb)(credentials); - }); - EXPECT_CALL(mock_service_controller_, GetLocalPublicCredentials) - .WillOnce([&](const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) { - std::vector credentials; - credentials.push_back(BuildSharedCredential(key_pair_)); - std::move(callback.credentials_fetched_cb)(std::move(credentials)); - }); - - PresenceDevice remote_device(CreateTestDeviceIdentityMetaData()); - remote_device.SetDecryptSharedCredential(BuildSharedCredential(key_pair_)); - - ON_CALL(mock_connection_authenticator_, BuildSignedMessageAsInitiator) - .WillByDefault(testing::Return(BuildDefaultInitiatorData())); - - MockAuthenticationTransport authentication_transport; - EXPECT_CALL(authentication_transport, WriteMessage) - .WillOnce([&](absl::string_view message) { - PresenceAuthenticationFrame authentication_frame; - EXPECT_TRUE(authentication_frame.ParseFromString(message)); - EXPECT_EQ(kPresenceVersion, authentication_frame.version()); - }); - - auto status = provider_->AuthenticateAsInitiator( - /*remote_device=*/remote_device, /*shared_secret=*/kUkey2Secret, - /*authentication_transport=*/authentication_transport); - - EXPECT_EQ(AuthenticationStatus::kSuccess, status); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/presence_device_test.cc b/presence/presence_device_test.cc deleted file mode 100644 index e567d749..00000000 --- a/presence/presence_device_test.cc +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 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. -// 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 "presence/presence_device.h" - -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "connections/implementation/proto/offline_wire_formats.pb.h" -#include "internal/platform/ble_connection_info.h" -#include "internal/proto/credential.pb.h" -#include "internal/proto/metadata.pb.h" -#include "presence/data_element.h" -#include "presence/presence_action.h" - -namespace nearby { -namespace presence { -namespace { - -using ::nearby::internal::DeviceIdentityMetaData; -using ::testing::Contains; - -constexpr DeviceMotion::MotionType kDefaultMotionType = - DeviceMotion::MotionType::kPointAndHold; -constexpr float kDefaultConfidence = 0; -constexpr float kTestConfidence = 0.1; -constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; -constexpr int kDataElementType = DataElement::kBatteryFieldType; -constexpr absl::string_view kDataElementValue = "15"; -constexpr char kEndpointId[] = "endpoint_id"; -constexpr int kTestAction = 3; - -DeviceIdentityMetaData CreateTestDeviceIdentityMetaData() { - DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_device_type( - internal::DeviceType::DEVICE_TYPE_LAPTOP); - device_identity_metadata.set_device_name("NP test device"); - device_identity_metadata.set_bluetooth_mac_address(kMacAddr); - device_identity_metadata.set_device_id("\x12\xab\xcd"); - return device_identity_metadata; -} -TEST(PresenceDeviceTest, EndpointIdConstructor) { - PresenceDevice device(kEndpointId); - EXPECT_EQ(device.GetEndpointId(), kEndpointId); -} - -TEST(PresenceDeviceTest, DefaultMotionEquals) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device1(device_identity_metadata); - PresenceDevice device2(device_identity_metadata); - EXPECT_EQ(device1, device2); -} - -TEST(PresenceDeviceTest, ExplicitInitEquals) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - internal::SharedCredential shared_credential; - shared_credential.set_credential_type(internal::CREDENTIAL_TYPE_GAIA); - PresenceDevice device1 = - PresenceDevice({kDefaultMotionType, kTestConfidence}, - device_identity_metadata, internal::IDENTITY_TYPE_PUBLIC); - device1.SetDecryptSharedCredential(shared_credential); - PresenceDevice device2 = - PresenceDevice({kDefaultMotionType, kTestConfidence}, - device_identity_metadata, internal::IDENTITY_TYPE_PUBLIC); - device2.SetDecryptSharedCredential(shared_credential); - EXPECT_EQ(device1, device2); -} - -TEST(PresenceDeviceTest, ExplicitInitNotEquals) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device1 = - PresenceDevice({kDefaultMotionType}, device_identity_metadata, - internal::IDENTITY_TYPE_PUBLIC); - PresenceDevice device2 = PresenceDevice( - {kDefaultMotionType, kTestConfidence}, device_identity_metadata, - internal::IDENTITY_TYPE_PRIVATE_GROUP); - EXPECT_NE(device1, device2); -} - -TEST(PresenceDeviceTest, TestGetBleConnectionInfo) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = - PresenceDevice({kDefaultMotionType}, device_identity_metadata); - device.AddAction(PresenceAction(kTestAction)); - auto info = (device.GetConnectionInfos().at(0)); - ASSERT_TRUE(std::holds_alternative(info)); - auto ble_info = std::get(info); - EXPECT_EQ(ble_info.GetMacAddress(), kMacAddr); - EXPECT_EQ(ble_info.GetActions(), std::vector{kTestAction}); -} - -TEST(PresenceDeviceTest, TestGetAddExtendedProperties) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = - PresenceDevice({kDefaultMotionType}, device_identity_metadata); - device.AddExtendedProperty({kDataElementType, kDataElementValue}); - ASSERT_EQ(device.GetExtendedProperties().size(), 1); - EXPECT_EQ(device.GetExtendedProperties()[0], - DataElement(kDataElementType, kDataElementValue)); -} - -TEST(PresenceDeviceTest, TestGetAddExtendedPropertiesVector) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = - PresenceDevice({kDefaultMotionType}, device_identity_metadata); - device.AddExtendedProperties( - {DataElement(kDataElementType, kDataElementValue)}); - ASSERT_EQ(device.GetExtendedProperties().size(), 1); - EXPECT_EQ(device.GetExtendedProperties()[0], - DataElement(kDataElementType, kDataElementValue)); -} - -TEST(PresenceDeviceTest, TestAddGetActions) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = - PresenceDevice({kDefaultMotionType}, device_identity_metadata); - device.AddAction({kTestAction}); - ASSERT_EQ(device.GetActions().size(), 1); - EXPECT_EQ(device.GetActions()[0], PresenceAction(kTestAction)); -} - -TEST(PresenceDeviceTest, TestEndpointIdIsCorrectLength) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = - PresenceDevice({kDefaultMotionType}, device_identity_metadata); - EXPECT_EQ(device.GetEndpointId().length(), kEndpointIdLength); -} - -TEST(PresenceDeviceTest, TestEndpointIdIsRandom) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = - PresenceDevice({kDefaultMotionType}, device_identity_metadata); - EXPECT_EQ(device.GetEndpointId().length(), kEndpointIdLength); - EXPECT_NE(device.GetEndpointId(), std::string(kEndpointIdLength, 0)); -} - -TEST(PresenceDeviceTest, TestGetIdentityType) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = PresenceDevice( - DeviceMotion(), device_identity_metadata, internal::IDENTITY_TYPE_PUBLIC); - EXPECT_EQ(device.GetIdentityType(), internal::IDENTITY_TYPE_PUBLIC); -} - -TEST(PresenceDeviceTest, TestGetDecryptSharedCredential) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = PresenceDevice( - DeviceMotion(), device_identity_metadata, internal::IDENTITY_TYPE_PUBLIC); - EXPECT_EQ(device.GetDecryptSharedCredential(), std::nullopt); - internal::SharedCredential shared_credential; - shared_credential.set_credential_type(internal::CREDENTIAL_TYPE_GAIA); - device.SetDecryptSharedCredential(shared_credential); - EXPECT_EQ(device.GetDecryptSharedCredential()->SerializeAsString(), - shared_credential.SerializeAsString()); -} - -TEST(PresenceDeviceTest, TestToProtoBytes) { - DeviceIdentityMetaData device_identity_metadata = - CreateTestDeviceIdentityMetaData(); - PresenceDevice device = PresenceDevice( - DeviceMotion(), device_identity_metadata, internal::IDENTITY_TYPE_PUBLIC); - std::string proto_bytes = device.ToProtoBytes(); - location::nearby::connections::PresenceDevice device_frame; - ASSERT_TRUE(device_frame.ParseFromString(proto_bytes)); - // Public identity. - EXPECT_THAT(device_frame.identity_type(), Contains(2)); - EXPECT_EQ(device_frame.endpoint_type(), - location::nearby::connections::PRESENCE_ENDPOINT); - EXPECT_EQ(device_frame.endpoint_id(), device.GetEndpointId()); - EXPECT_EQ(device_frame.device_type(), - location::nearby::connections::PresenceDevice::LAPTOP); - EXPECT_EQ(device_frame.device_name(), "NP test device"); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/presence_identity_test.cc b/presence/presence_identity_test.cc deleted file mode 100644 index 5b45704d..00000000 --- a/presence/presence_identity_test.cc +++ /dev/null @@ -1,44 +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 "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "internal/proto/credential.pb.h" - -namespace nearby { -namespace presence { -namespace { -using ::nearby::internal::IdentityType; - -constexpr IdentityType kTestIdentityType = - IdentityType::IDENTITY_TYPE_CONTACTS_GROUP; - -TEST(PresenceIdentityTest, ExplicitInitEquals) { - IdentityType identity1 = {kTestIdentityType}; - IdentityType identity2 = {kTestIdentityType}; - EXPECT_EQ(identity1, identity2); - EXPECT_EQ(identity1, kTestIdentityType); -} - - -TEST(PresenceIdentityTest, CopyInitEquals) { - IdentityType identity1 = {kTestIdentityType}; - IdentityType identity2 = {identity1}; - EXPECT_EQ(identity1, identity2); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/presence_service.h b/presence/presence_service.h deleted file mode 100644 index 8fe11637..00000000 --- a/presence/presence_service.h +++ /dev/null @@ -1,72 +0,0 @@ -// 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. -// 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_PRESENCE_PRESENCE_SERVICE_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_SERVICE_H_ - -#include -#include - -#include "internal/interop/device_provider.h" -#include "internal/proto/metadata.pb.h" -#include "presence/data_types.h" -#include "presence/presence_client.h" - -namespace nearby { -namespace presence { - -class PresenceService { - public: - virtual ~PresenceService() = default; - - virtual std::unique_ptr CreatePresenceClient() = 0; - - virtual absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) = 0; - virtual void StopScan(ScanSessionId session_id) = 0; - - virtual absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) = 0; - - virtual void StopBroadcast(BroadcastSessionId session_id) = 0; - - virtual void UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) = 0; - - virtual NearbyDeviceProvider* GetLocalDeviceProvider() = 0; - - virtual void GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) = 0; - - virtual void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) = 0; - - // Testing only. - virtual ::nearby::internal::DeviceIdentityMetaData - GetDeviceIdentityMetaData() = 0; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_SERVICE_H_ diff --git a/presence/presence_service_impl.cc b/presence/presence_service_impl.cc deleted file mode 100644 index d107e618..00000000 --- a/presence/presence_service_impl.cc +++ /dev/null @@ -1,83 +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 "presence/presence_service_impl.h" - -#include -#include -#include - -#include "internal/platform/borrowable.h" -#include "presence/data_types.h" -#include "presence/presence_client_impl.h" -#include "presence/presence_device_provider.h" - -namespace nearby { -namespace presence { - -std::unique_ptr PresenceServiceImpl::CreatePresenceClient() { - return PresenceClientImpl::Factory::Create(lender_.GetBorrowable()); -} - -absl::StatusOr PresenceServiceImpl::StartScan( - ScanRequest scan_request, ScanCallback callback) { - return service_controller_.StartScan(scan_request, std::move(callback)); -} - -void PresenceServiceImpl::StopScan(ScanSessionId id) { - service_controller_.StopScan(id); -} - -absl::StatusOr PresenceServiceImpl::StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) { - return service_controller_.StartBroadcast(broadcast_request, - std::move(callback)); -} - -void PresenceServiceImpl::StopBroadcast(BroadcastSessionId session) { - service_controller_.StopBroadcast(session); -} - -void PresenceServiceImpl::UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) { - provider_.UpdateDeviceIdentityMetaData(device_identity_metadata); - provider_.SetManagerAppId(manager_app_id); - service_controller_.UpdateDeviceIdentityMetaData( - device_identity_metadata, regen_credentials, manager_app_id, - identity_types, credential_life_cycle_days, - contiguous_copy_of_credentials, std::move(credentials_generated_cb)); -} - -void PresenceServiceImpl::GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) { - service_controller_.GetLocalPublicCredentials(credential_selector, - std::move(callback)); -} - -void PresenceServiceImpl::UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) { - service_controller_.UpdateRemotePublicCredentials( - manager_app_id, account_name, remote_public_creds, - std::move(credentials_updated_cb)); -} - -} // namespace presence -} // namespace nearby diff --git a/presence/presence_service_impl.h b/presence/presence_service_impl.h deleted file mode 100644 index a8d5a219..00000000 --- a/presence/presence_service_impl.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 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. -// 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_PRESENCE_PRESENCE_SERVICE_IMPL_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_SERVICE_IMPL_H_ - -#include -#include - -#include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "internal/platform/borrowable.h" -#include "internal/platform/implementation/credential_callbacks.h" -#include "internal/platform/single_thread_executor.h" -#include "internal/proto/metadata.pb.h" -#include "presence/broadcast_request.h" -#include "presence/data_types.h" -#include "presence/implementation/broadcast_manager.h" -#include "presence/implementation/connection_authenticator_impl.h" -#include "presence/implementation/credential_manager_impl.h" -#include "presence/implementation/mediums/mediums.h" -#include "presence/implementation/scan_manager.h" -#include "presence/implementation/service_controller_impl.h" -#include "presence/presence_client.h" -#include "presence/presence_device_provider.h" -#include "presence/presence_service.h" -#include "presence/scan_request.h" -#include "internal/interop/device_provider.h" - -namespace nearby { -namespace presence { - -/* - * PresenceService hosts presence functions by routing invokes to the unique - * {@code ServiceController}. PresenceService should be initialized once and - * only once in the process that hosting presence functions. - */ -class PresenceServiceImpl : public PresenceService { - public: - PresenceServiceImpl() = default; - ~PresenceServiceImpl() override { lender_.Release(); } - - std::unique_ptr CreatePresenceClient() override; - - absl::StatusOr StartScan(ScanRequest scan_request, - ScanCallback callback) override; - void StopScan(ScanSessionId session_id) override; - - absl::StatusOr StartBroadcast( - BroadcastRequest broadcast_request, BroadcastCallback callback) override; - - void StopBroadcast(BroadcastSessionId session_id) override; - - void UpdateDeviceIdentityMetaData( - const ::nearby::internal::DeviceIdentityMetaData& - device_identity_metadata, - bool regen_credentials, absl::string_view manager_app_id, - const std::vector& identity_types, - int credential_life_cycle_days, int contiguous_copy_of_credentials, - GenerateCredentialsResultCallback credentials_generated_cb) override; - - NearbyDeviceProvider* GetLocalDeviceProvider() override { - return &provider_; - } - - ::nearby::internal::DeviceIdentityMetaData GetDeviceIdentityMetaData() - override { - return service_controller_.GetDeviceIdentityMetaData(); - } - - void GetLocalPublicCredentials( - const CredentialSelector& credential_selector, - GetPublicCredentialsResultCallback callback) override; - - void UpdateRemotePublicCredentials( - absl::string_view manager_app_id, absl::string_view account_name, - const std::vector& - remote_public_creds, - UpdateRemotePublicCredentialsCallback credentials_updated_cb) override; - - private: - SingleThreadExecutor executor_; - Mediums mediums_; - CredentialManagerImpl credential_manager_{&executor_}; - ScanManager scan_manager_{mediums_, credential_manager_, executor_}; - BroadcastManager broadcast_manager_{mediums_, credential_manager_, executor_}; - ServiceControllerImpl service_controller_{ - &executor_, &credential_manager_, &scan_manager_, &broadcast_manager_}; - ConnectionAuthenticatorImpl connection_authenticator_; - ::nearby::Lender lender_{this}; - PresenceDeviceProvider provider_{&service_controller_, - &connection_authenticator_}; -}; - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_SERVICE_IMPL_H_ diff --git a/presence/presence_service_test.cc b/presence/presence_service_test.cc deleted file mode 100644 index 1f24275b..00000000 --- a/presence/presence_service_test.cc +++ /dev/null @@ -1,152 +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 "presence/presence_service.h" - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "internal/platform/count_down_latch.h" -#include "internal/platform/medium_environment.h" -#include "presence/presence_client.h" -#include "presence/presence_service_impl.h" - -namespace nearby { -namespace presence { -namespace { -using DeviceIdentityMetaData = ::nearby::internal::DeviceIdentityMetaData; - -constexpr absl::string_view kManagerAppId = "TEST_MANAGER_APP"; -constexpr absl::string_view kAccountName = "dummy account"; - -class PresenceServiceTest : public testing::Test { - protected: - nearby::MediumEnvironment& env_{nearby::MediumEnvironment::Instance()}; -}; - -DeviceIdentityMetaData CreateTestDeviceIdentityMetaData() { - DeviceIdentityMetaData device_identity_metadata; - device_identity_metadata.set_device_type( - internal::DeviceType::DEVICE_TYPE_PHONE); - device_identity_metadata.set_device_name("NP test device"); - device_identity_metadata.set_bluetooth_mac_address( - "\xFF\xFF\xFF\xFF\xFF\xFF"); - device_identity_metadata.set_device_id("\x12\xab\xcd"); - return device_identity_metadata; -} - -CredentialSelector BuildDefaultCredentialSelector() { - CredentialSelector credential_selector; - credential_selector.manager_app_id = std::string(kManagerAppId); - credential_selector.account_name = std::string(kAccountName); - credential_selector.identity_type = internal::IDENTITY_TYPE_PRIVATE_GROUP; - return credential_selector; -} - -TEST_F(PresenceServiceTest, DefaultConstructorWorks) { - PresenceServiceImpl presence_service; -} - -TEST_F(PresenceServiceTest, StartThenStopScan) { - env_.Start(); - absl::Status scan_result; - ScanCallback scan_callback = { - .start_scan_cb = [&](absl::Status status) { scan_result = status; }, - }; - PresenceServiceImpl presence_service; - std::unique_ptr client = - presence_service.CreatePresenceClient(); - - absl::StatusOr scan_session = client->StartScan( - {}, - { - .start_scan_cb = [&](absl::Status status) { scan_result = status; }, - }); - absl::StatusOr scan_session_with_default_params = - client->StartScan(ScanRequest(), ScanCallback()); - - ASSERT_OK(scan_session); - ASSERT_OK(scan_session_with_default_params); - EXPECT_NE(*scan_session, *scan_session_with_default_params); - - client->StopScan(*scan_session); - client->StopScan(*scan_session_with_default_params); - env_.Stop(); -} - -TEST_F(PresenceServiceTest, UpdatingDeviceIdentityMetaDataWorks) { - PresenceServiceImpl presence_service; - presence_service.UpdateDeviceIdentityMetaData( - CreateTestDeviceIdentityMetaData(), false, "Test app", {}, 3, 1, {}); - EXPECT_EQ(presence_service.GetDeviceIdentityMetaData().SerializeAsString(), - CreateTestDeviceIdentityMetaData().SerializeAsString()); -} - -TEST_F(PresenceServiceTest, TestGetDeviceProvider) { - PresenceServiceImpl presence_service; - EXPECT_NE(presence_service.GetLocalDeviceProvider(), nullptr); -} - -TEST_F(PresenceServiceTest, TestGetPublicCredentials) { - PresenceServiceImpl presence_service; - CredentialSelector selector = BuildDefaultCredentialSelector(); - absl::Status status; - nearby::CountDownLatch fetched_latch(1); - presence_service.GetLocalPublicCredentials( - selector, - {.credentials_fetched_cb = - [&status, &fetched_latch]( - absl::StatusOr> - result) { - status = result.status(); - fetched_latch.CountDown(); - }}); - EXPECT_TRUE(fetched_latch.Await().Ok()); - EXPECT_THAT(status, testing::status::StatusIs(absl::StatusCode::kNotFound)); -} - -TEST_F(PresenceServiceTest, TestUpdateRemotePublicCredentials) { - PresenceServiceImpl presence_service; - internal::SharedCredential public_credential_for_test; - public_credential_for_test.set_identity_type( - internal::IdentityType::IDENTITY_TYPE_CONTACTS_GROUP); - std::vector public_credentials{ - {public_credential_for_test}}; - - nearby::CountDownLatch updated_latch(1); - UpdateRemotePublicCredentialsCallback update_credentials_cb{ - .credentials_updated_cb = - [&updated_latch](absl::Status status) { - if (status.ok()) { - updated_latch.CountDown(); - } - }, - }; - - presence_service.UpdateRemotePublicCredentials( - kManagerAppId, kAccountName, public_credentials, - std::move(update_credentials_cb)); - - EXPECT_TRUE(updated_latch.Await().Ok()); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/presence_zone.cc b/presence/presence_zone.cc deleted file mode 100644 index 2fcdad45..00000000 --- a/presence/presence_zone.cc +++ /dev/null @@ -1,82 +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 "presence/presence_zone.h" - -namespace nearby { -namespace presence { - -PresenceZone::DistanceBoundary::DistanceBoundary(float min_distance_meters, - float max_distance_meters, - RangeType range_type) noexcept - : min_distance_meters_(min_distance_meters), - max_distance_meters_(max_distance_meters), - range_type_(range_type) {} - -float PresenceZone::DistanceBoundary::GetMinDistanceMeters() const { - return min_distance_meters_; -} - -float PresenceZone::DistanceBoundary::GetMaxDistanceMeters() const { - return max_distance_meters_; -} - -PresenceZone::DistanceBoundary::RangeType -PresenceZone::DistanceBoundary::GetRangeType() const { - return range_type_; -} - -PresenceZone::AngleOfArrivalBoundary::AngleOfArrivalBoundary( - float min_angle_degrees, float max_angle_degrees) noexcept - : min_angle_degrees_(min_angle_degrees), - max_angle_degrees_(max_angle_degrees) {} - -float PresenceZone::AngleOfArrivalBoundary::GetMinAngleDegrees() const { - return min_angle_degrees_; -} - -float PresenceZone::AngleOfArrivalBoundary::GetMaxAngleDegrees() const { - return max_angle_degrees_; -} - -PresenceZone::PresenceZone( - const DistanceBoundary& distance_boundary, - const AngleOfArrivalBoundary& azimuth_angle_boundary, - const AngleOfArrivalBoundary& elevation_angle_boundary, - const std::vector& device_motions) - : distance_boundary_(distance_boundary), - azimuth_angle_boundary_(azimuth_angle_boundary), - elevation_angle_boundary_(elevation_angle_boundary), - device_motions_(device_motions) {} - -PresenceZone::DistanceBoundary PresenceZone::GetDistanceBoundary() const { - return distance_boundary_; -} - -PresenceZone::AngleOfArrivalBoundary PresenceZone::GetAzimuthAngleBoundary() - const { - return azimuth_angle_boundary_; -} - -PresenceZone::AngleOfArrivalBoundary PresenceZone::GetElevationAngleBoundary() - const { - return elevation_angle_boundary_; -} - -std::vector PresenceZone::GetLocalDeviceMotions() const { - return device_motions_; -} - -} // namespace presence -} // namespace nearby diff --git a/presence/presence_zone.h b/presence/presence_zone.h deleted file mode 100644 index c2883100..00000000 --- a/presence/presence_zone.h +++ /dev/null @@ -1,108 +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 THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_ZONE_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_ZONE_H_ - -#include - -#include "presence/device_motion.h" -namespace nearby { -namespace presence { -class PresenceZone { - public: - class DistanceBoundary { - public: - enum class RangeType { - kRangeUnknown = 0, - kFar, // Distance is very far away from the peer device. - kWithinReach, // Distance is very close to the peer device, typically - // within one meter or less. - kWithinTap, // Distance is within tap range to the peer device, typically - // within ~0.127 meters. - }; - DistanceBoundary(float min_distance_meters = 0, - float max_distance_meters = 0, - RangeType range_type = RangeType::kRangeUnknown) noexcept; - float GetMinDistanceMeters() const; - float GetMaxDistanceMeters() const; - RangeType GetRangeType() const; - - private: - const float min_distance_meters_; - const float max_distance_meters_; - const RangeType range_type_; - }; - - class AngleOfArrivalBoundary { - public: - AngleOfArrivalBoundary(float min_angle_degrees = 0, - float max_angle_degrees = 0) noexcept; - float GetMinAngleDegrees() const; - float GetMaxAngleDegrees() const; - - private: - const float min_angle_degrees_; - const float max_angle_degrees_; - }; - - PresenceZone(const DistanceBoundary& = {}, const AngleOfArrivalBoundary& = {}, - const AngleOfArrivalBoundary& = {}, - const std::vector& = {}); - DistanceBoundary GetDistanceBoundary() const; - AngleOfArrivalBoundary GetAzimuthAngleBoundary() const; - AngleOfArrivalBoundary GetElevationAngleBoundary() const; - std::vector GetLocalDeviceMotions() const; - - private: - const DistanceBoundary distance_boundary_; - const AngleOfArrivalBoundary azimuth_angle_boundary_; - const AngleOfArrivalBoundary elevation_angle_boundary_; - const std::vector device_motions_; -}; - -inline bool operator==(const PresenceZone::DistanceBoundary& d1, - const PresenceZone::DistanceBoundary& d2) { - return d1.GetMinDistanceMeters() == d2.GetMinDistanceMeters() && - d1.GetMaxDistanceMeters() == d2.GetMaxDistanceMeters() && - d1.GetRangeType() == d2.GetRangeType(); -} -inline bool operator!=(const PresenceZone::DistanceBoundary& d1, - const PresenceZone::DistanceBoundary& d2) { - return !(d1 == d2); -} -inline bool operator==(const PresenceZone::AngleOfArrivalBoundary& a1, - const PresenceZone::AngleOfArrivalBoundary& a2) { - return a1.GetMinAngleDegrees() == a2.GetMinAngleDegrees() && - a1.GetMaxAngleDegrees() == a2.GetMaxAngleDegrees(); -} -inline bool operator!=(const PresenceZone::AngleOfArrivalBoundary& a1, - const PresenceZone::AngleOfArrivalBoundary& a2) { - return !(a1 == a2); -} - -inline bool operator==(const PresenceZone& z1, const PresenceZone& z2) { - return z1.GetDistanceBoundary() == z2.GetDistanceBoundary() && - z1.GetAzimuthAngleBoundary() == z2.GetAzimuthAngleBoundary() && - z1.GetElevationAngleBoundary() == z2.GetElevationAngleBoundary() && - z1.GetLocalDeviceMotions() == z2.GetLocalDeviceMotions(); -} -inline bool operator!=(const PresenceZone& z1, const PresenceZone& z2) { - return !(z1 == z2); -} - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_ZONE_H_ diff --git a/presence/presence_zone_test.cc b/presence/presence_zone_test.cc deleted file mode 100644 index e813bf48..00000000 --- a/presence/presence_zone_test.cc +++ /dev/null @@ -1,221 +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 "presence/presence_zone.h" - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "presence/device_motion.h" - -namespace nearby { -namespace presence { -namespace { - -using DistanceBoundary = nearby::presence::PresenceZone::DistanceBoundary; -using RangeType = nearby::presence::PresenceZone::DistanceBoundary::RangeType; -using AngleOfArrivalBoundary = - nearby::presence::PresenceZone::AngleOfArrivalBoundary; - -static const float kDefaultDistanceMeters = 0; -static const float kTestMinDistanceMeters = 1; -static const float kTestMaxDistanceMeters = 2; - -static const float kDefaultDegrees = 0; -static const float kTestMinAngleDegrees = 10; -static const float kTestMaxAngleDegrees = 20; - -static const float kTestConfidence = 0.1; - -static const RangeType kDefaultRangeType = RangeType::kRangeUnknown; -static const RangeType kTestRangeType = RangeType::kFar; - -static const DistanceBoundary kDefaultDistanceBoundary; -static const DistanceBoundary kTestDistanceBoundary = { - kTestMinDistanceMeters, kTestMaxDistanceMeters, kTestRangeType}; -static const AngleOfArrivalBoundary kDefaultAngleBoundary; -static const AngleOfArrivalBoundary kTestAzimuthAngleBoundary = { - kTestMinAngleDegrees, kTestMaxAngleDegrees}; -static const AngleOfArrivalBoundary kTestElevationAngleBoundary = { - kTestMinAngleDegrees, kTestMaxAngleDegrees}; -static const DeviceMotion kTestDeviceMotion = { - DeviceMotion::MotionType::kPointAndHold, kTestConfidence}; - -TEST(DistanceBoundaryTest, DefaultConstructorWorks) { - DistanceBoundary boundary; - EXPECT_EQ(boundary.GetMinDistanceMeters(), kDefaultDistanceMeters); - EXPECT_EQ(boundary.GetMaxDistanceMeters(), kDefaultDistanceMeters); - EXPECT_EQ(boundary.GetRangeType(), kDefaultRangeType); -} - -TEST(DistanceBoundaryTest, DefaultEquals) { - DistanceBoundary boundary1; - DistanceBoundary boundary2; - EXPECT_EQ(boundary1, boundary2); -} - -TEST(DistanceBoundaryTest, PartiallyInitializationWorks) { - DistanceBoundary boundary1 = {kTestMinDistanceMeters, kTestMaxDistanceMeters}; - DistanceBoundary boundary2 = {kTestMinDistanceMeters}; - EXPECT_EQ(boundary1.GetMinDistanceMeters(), kTestMinDistanceMeters); - EXPECT_EQ(boundary1.GetMaxDistanceMeters(), kTestMaxDistanceMeters); - EXPECT_EQ(boundary1.GetRangeType(), kDefaultRangeType); - EXPECT_EQ(boundary2.GetMinDistanceMeters(), kTestMinDistanceMeters); - EXPECT_EQ(boundary2.GetMaxDistanceMeters(), kDefaultDistanceMeters); - EXPECT_EQ(boundary2.GetRangeType(), kDefaultRangeType); -} - -TEST(DistanceBoundaryTest, ExplicitInitEquals) { - DistanceBoundary boundary1 = {kTestMinDistanceMeters, kTestMaxDistanceMeters, - kTestRangeType}; - DistanceBoundary boundary2 = {kTestMinDistanceMeters, kTestMaxDistanceMeters, - kTestRangeType}; - EXPECT_EQ(boundary1.GetMinDistanceMeters(), kTestMinDistanceMeters); - EXPECT_EQ(boundary1.GetMaxDistanceMeters(), kTestMaxDistanceMeters); - EXPECT_EQ(boundary1.GetRangeType(), kTestRangeType); - EXPECT_EQ(boundary1, boundary2); -} - -TEST(DistanceBoundaryTest, ExplicitInitNotEquals) { - DistanceBoundary boundary1 = {kTestMinDistanceMeters, kTestMaxDistanceMeters, - kTestRangeType}; - DistanceBoundary boundary2 = {kTestMinDistanceMeters + 0.1f, - kTestMaxDistanceMeters, kTestRangeType}; - EXPECT_NE(boundary1, boundary2); -} - -TEST(DistanceBoundaryTest, CopyInitEquals) { - DistanceBoundary boundary1 = {kTestMinDistanceMeters, kTestMaxDistanceMeters, - kTestRangeType}; - DistanceBoundary boundary2 = {boundary1}; - EXPECT_EQ(boundary1, boundary2); -} - -TEST(AngleOfArrivalBoundaryTest, DefaultConstructorWorks) { - AngleOfArrivalBoundary aoa_boundary; - EXPECT_EQ(aoa_boundary.GetMinAngleDegrees(), kDefaultDegrees); - EXPECT_EQ(aoa_boundary.GetMaxAngleDegrees(), kDefaultDegrees); -} - -TEST(AngleOfArrivalBoundaryTest, DefaultEquals) { - AngleOfArrivalBoundary aoa_boundary1; - AngleOfArrivalBoundary aoa_boundary2; - EXPECT_EQ(aoa_boundary1, aoa_boundary2); -} - -TEST(AngleOfArrivalBoundaryTest, PartiallyInitializationWorks) { - AngleOfArrivalBoundary aoa_boundary = {kTestMinAngleDegrees}; - EXPECT_EQ(aoa_boundary.GetMinAngleDegrees(), kTestMinAngleDegrees); - EXPECT_EQ(aoa_boundary.GetMaxAngleDegrees(), kDefaultDegrees); -} - -TEST(AngleOfArrivalBoundaryTest, ExplicitInitEquals) { - AngleOfArrivalBoundary aoa_boundary1 = {kTestMinAngleDegrees, - kTestMaxAngleDegrees}; - AngleOfArrivalBoundary aoa_boundary2 = {kTestMinAngleDegrees, - kTestMaxAngleDegrees}; - EXPECT_EQ(aoa_boundary1.GetMinAngleDegrees(), kTestMinAngleDegrees); - EXPECT_EQ(aoa_boundary1.GetMaxAngleDegrees(), kTestMaxAngleDegrees); - EXPECT_EQ(aoa_boundary1, aoa_boundary2); -} - -TEST(AngleOfArrivalBoundaryTest, ExplicitInitNotEquals) { - AngleOfArrivalBoundary aoa_boundary1 = {kTestMinAngleDegrees, - kTestMaxAngleDegrees}; - AngleOfArrivalBoundary aoa_boundary2 = {kTestMinAngleDegrees, - kTestMaxAngleDegrees + 0.1f}; - EXPECT_NE(aoa_boundary1, aoa_boundary2); -} - -TEST(AngleOfArrivalBoundaryTest, CopyInitEquals) { - AngleOfArrivalBoundary aoa_boundary1 = {kTestMinAngleDegrees, - kTestMaxAngleDegrees}; - AngleOfArrivalBoundary aoa_boundary2 = {aoa_boundary1}; - EXPECT_EQ(aoa_boundary1, aoa_boundary2); -} - -TEST(PresenceZoneTest, DefaultConstructorWorks) { - PresenceZone zone; - EXPECT_EQ(zone.GetDistanceBoundary(), kDefaultDistanceBoundary); - EXPECT_EQ(zone.GetAzimuthAngleBoundary(), kDefaultAngleBoundary); - EXPECT_EQ(zone.GetElevationAngleBoundary(), kDefaultAngleBoundary); - EXPECT_EQ(zone.GetLocalDeviceMotions().capacity(), 0); -} - -TEST(PresenceZoneTest, DefaultEquals) { - PresenceZone zone1; - PresenceZone zone2; - EXPECT_EQ(zone1, zone2); -} - -TEST(PresenceZoneTest, PartiallyInitializationWorks) { - PresenceZone zone1 = {kTestDistanceBoundary, kTestAzimuthAngleBoundary, - kTestElevationAngleBoundary}; - PresenceZone zone2 = {kTestDistanceBoundary, kTestAzimuthAngleBoundary}; - PresenceZone zone3 = {kTestDistanceBoundary}; - EXPECT_EQ(zone1.GetDistanceBoundary(), kTestDistanceBoundary); - EXPECT_EQ(zone1.GetAzimuthAngleBoundary(), kTestAzimuthAngleBoundary); - EXPECT_EQ(zone1.GetElevationAngleBoundary(), kTestElevationAngleBoundary); - EXPECT_EQ(zone1.GetLocalDeviceMotions().capacity(), 0); - EXPECT_EQ(zone2.GetDistanceBoundary(), kTestDistanceBoundary); - EXPECT_EQ(zone2.GetAzimuthAngleBoundary(), kTestAzimuthAngleBoundary); - EXPECT_EQ(zone2.GetElevationAngleBoundary(), kDefaultAngleBoundary); - EXPECT_EQ(zone2.GetLocalDeviceMotions().capacity(), 0); - EXPECT_EQ(zone3.GetDistanceBoundary(), kTestDistanceBoundary); - EXPECT_EQ(zone3.GetAzimuthAngleBoundary(), kDefaultAngleBoundary); - EXPECT_EQ(zone3.GetElevationAngleBoundary(), kDefaultAngleBoundary); - EXPECT_EQ(zone3.GetLocalDeviceMotions().capacity(), 0); -} - -TEST(PresenceZoneTest, ExplicitInitEquals) { - PresenceZone zone1 = {kTestDistanceBoundary, - kTestAzimuthAngleBoundary, - kTestElevationAngleBoundary, - {kTestDeviceMotion}}; - PresenceZone zone2 = {kTestDistanceBoundary, - kTestAzimuthAngleBoundary, - kTestElevationAngleBoundary, - {kTestDeviceMotion}}; - EXPECT_EQ(zone1.GetDistanceBoundary(), kTestDistanceBoundary); - EXPECT_EQ(zone1.GetAzimuthAngleBoundary(), kTestAzimuthAngleBoundary); - EXPECT_EQ(zone1.GetElevationAngleBoundary(), kTestElevationAngleBoundary); - EXPECT_EQ(zone1.GetLocalDeviceMotions().size(), 1); - EXPECT_EQ(zone1.GetLocalDeviceMotions()[0], kTestDeviceMotion); - EXPECT_EQ(zone1, zone2); -} - -TEST(PresenceZoneTest, ExplicitInitNotEquals) { - PresenceZone zone1 = {kTestDistanceBoundary, - kTestAzimuthAngleBoundary, - kTestElevationAngleBoundary, - {kTestDeviceMotion}}; - PresenceZone zone2 = {kTestDistanceBoundary, - kTestAzimuthAngleBoundary, - kTestElevationAngleBoundary, - {}}; - EXPECT_NE(zone1, zone2); -} - -TEST(PresenceZoneTest, CopyInitEquals) { - PresenceZone zone1 = {kTestDistanceBoundary, - kTestAzimuthAngleBoundary, - kTestElevationAngleBoundary, - {kTestDeviceMotion}}; - PresenceZone zone2 = {zone1}; - EXPECT_EQ(zone1, zone2); -} - -} // namespace -} // namespace presence -} // namespace nearby diff --git a/presence/proto/BUILD b/presence/proto/BUILD deleted file mode 100644 index 6351491c..00000000 --- a/presence/proto/BUILD +++ /dev/null @@ -1,29 +0,0 @@ -# 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. - -load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") -load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") - -proto_library( - name = "presence_frame_proto", - srcs = ["presence_frame.proto"], -) - -cc_proto_library( - name = "presence_frame_cc_proto", - visibility = [ - "//presence:__subpackages__", - ], - deps = [":presence_frame_proto"], -) diff --git a/presence/proto/presence_frame.proto b/presence/proto/presence_frame.proto deleted file mode 100644 index 1f18cbcd..00000000 --- a/presence/proto/presence_frame.proto +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 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. -// 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. - -syntax = "proto2"; - -package nearby.presence; - -// import "storage/datapol/annotations/proto/semantic_annotations.proto"; - -option optimize_for = LITE_RUNTIME; -option java_package = "com.google.android.gms.nearby.presence"; -option java_outer_classname = "PresenceFrameProtocol"; - -/** - * Nearby Presence’s wire frame format - */ -message PresenceFrame { - /** The version of the frame. */ - enum Version { - UNKNOWN_VERSION = 0; - VERSION_1 = 1; - } - - /** The version 1 frame for Nearby Presence. */ - optional V1Frame v1_frame = 1; -} - -/** - * Nearby Presence’s v1 wire frame format - */ -message V1Frame { - oneof Message { - // Control messages for connection status update. - ControlFrame control_frame = 1; - - // This frame will be shared by public and provisioned identities - DeviceIdentityFrame device_identity_frame = 2; - - // First message from discovery device to broadcaster. - ConnectionInitFrame connection_init_frame = 3; - - // Sent by broadcaster to notify discoverer its UWB capability. - UwbControleeCapabilities uwb_controlee_capabilities_frame = 4; - - // Sent by discoverer to notify broadcaster the UWB ranging parameters. - UwbConnectionInfo uwb_connection_info = 5; - - // Used for identity authentication. - PresenceAuthenticationFrame authentication_frame = 6; - } -} - -/** - * A frame contains the local device’s information, shared by public and - * provisioned identities. - */ -message DeviceIdentityFrame { - optional string device_name = 1; - - // Without this field, the device will not be connectable. - optional bytes bluetooth_mac_address = 2; // deprecated - - optional string device_image_url = 3; - - optional string model_id = 4; - - repeated int32 action = 5 [packed = true]; // deprecated - - optional string device_model_name = 6; - - optional int32 device_type = 7; -} - -/** - * A frame sent from discovery device to broadcast device when connection - * initialized, or when UWB needs to be restarted, or when dedup hint rotates. - */ -message ConnectionInitFrame { - // Discovery-side action list - repeated int32 actions = 1 [packed = true]; - - // Discovery-side identity type - optional int32 identity_type = 2; - - // Should the broadcaster (re)-start UWB OOB process or not. - optional bool uwb_enable = 3; - - // Used for device de-duplicate. Same device ID means the same physical - // device. When dedup hint rotates, this will be updated and send again. - optional int64 device_unique_id = 4; -} - -/** - * A frame that describes the controlee's UWB capabilities. - */ -message UwbControleeCapabilities { - optional bytes controlee_address = 1; - - repeated int32 supported_config_ids = 2 [packed = true]; - - repeated int32 supported_channels = 3 [packed = true]; - - optional int32 min_ranging_interval_ms = 4; - - optional bytes sub_session_id = 5 /* type = ST_SESSION_ID */; - - optional bytes sub_session_key = 6 - /* type = ST_SECURITY_MATERIAL */; - - optional bool ranging_disabled = 7; - - // Used for device de-duplicate. Same device ID means the same physical - // device. - optional int64 device_unique_id = 8; - - optional bool is_distance_supported = 9 [default = true]; - optional bool is_azimuth_supported = 10 [default = true]; - optional bool is_elevation_supported = 11 [default = false]; - optional float min_slot_duration_ms = 12 [default = 2.0]; - repeated int32 supported_ntf_configs = 13 [packed = true]; - optional bool is_ranging_interval_reconfigure_supported = 14 - [default = false]; - repeated int32 supported_slot_durations = 15 [packed = true]; - repeated int32 supported_ranging_update_rates = 16 [packed = true]; - optional int32 chip_count = 17 [default = 1]; - repeated UwbMultiChipInfo multi_chip_info = 18; - optional bool is_background_ranging_supported = 19 [default = false]; -} - -/* A frame containing info needed per chip in a multi-chip environment. */ -message UwbMultiChipInfo { - optional bytes controlee_address = 1; - optional string chip_id = 2; -} - -/** - * A frame that describes the connection info of the UWB ranging session. - */ -message UwbConnectionInfo { - optional bytes controller_address = 1; - - optional int32 channel = 2; - - optional int32 preamble_index = 3; - - optional int32 config_id = 4; - - optional int32 ranging_interval_ms = 5; - - optional int32 session_id = 6 /* type = ST_SESSION_ID */; - - optional bytes vendor_id = 7; - - optional bytes static_sts_iv = 8; - - optional bytes session_key = 9 - /* type = ST_SECURITY_MATERIAL */; - - optional bool ranging_disabled = 10; -} - -/** - * Control frames that used for connection status update. - */ -message ControlFrame { - /** The defined Control type of the frame. */ - enum ControlType { - UNKNOWN_TYPE = 0; - - // Keeps the connection alive. - KEEP_ALIVE = 1; - - // Notifies the peer that the connection will be closed immediately. - DISCONNECT = 2; - } - - optional ControlType type = 1; -} - -message PresenceAuthenticationFrame { - // The version of this frame and protocol. - optional int32 version = 1; - - // A signature signed by the private key in the LocalCredential. - optional bytes private_key_signature = 2; - - // A hash of a shared credential's id. Used to prove ownership of shared - // credentials used in discovery. - optional bytes shared_credential_id_hash = 3; - - // A hash of a local credential's id. Used to expedite local credential - // verification. - optional bytes credential_id_hash = 4 [deprecated = true]; -} diff --git a/presence/rust/README b/presence/rust/README deleted file mode 100644 index 9ca03064..00000000 --- a/presence/rust/README +++ /dev/null @@ -1 +0,0 @@ -This directory contains Rust implementation of Nearby Presence. diff --git a/presence/scan_request.h b/presence/scan_request.h deleted file mode 100644 index 69aaad01..00000000 --- a/presence/scan_request.h +++ /dev/null @@ -1,151 +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 THIRD_PARTY_NEARBY_PRESENCE_SCAN_REQUEST_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_SCAN_REQUEST_H_ - -#include -#include - -#include "absl/types/variant.h" -#include "internal/proto/credential.pb.h" -#include "presence/data_element.h" -#include "presence/power_mode.h" - -namespace nearby { -namespace presence { - -constexpr char kPresenceScanFilterName[] = "PresenceScanFilter"; -constexpr char kLegacyPresenceScanFilterName[] = "LegacyPresenceScanFilter"; - -enum class ScanType { - kUnspecifiedScan = 0, - kFastPairScan = 1, - kPresenceScan = 2, -}; - -/** - * Filter for scanning a nearby presence device. - * Supports Android U and above. - */ -struct PresenceScanFilter { - ScanType scan_type; - // A bundle of extended properties for matching. - std::vector extended_properties; -}; - -/** - * Used to support legacy Android T. Filter for scanning a nearby presence - * device. - */ -struct LegacyPresenceScanFilter { - ScanType scan_type; - // Minimum path loss threshold of the received scan result. - int path_loss_threshold; - - // Android T needs clients to provide remote public credentials in scan - // requests. - std::vector remote_public_credentials; - - // A list of presence actions for matching. Matching condition is met as - // long as there’s one or more equal actions between Scan actions and - // Broadcast actions. - // Considered to use enum, and team agreed to use int to support potential - // un-reserved values. Already existing reserved interger values are defined - // in {@code ActionFactory}. - std::vector actions; - - // A bundle of extended properties for matching. - std::vector extended_properties; -}; - -inline bool operator==(const PresenceScanFilter& a, - const PresenceScanFilter& b) { - return a.scan_type == b.scan_type && - a.extended_properties == b.extended_properties; -} - -inline bool operator!=(const PresenceScanFilter& a, - const PresenceScanFilter& b) { - return !(a == b); -} - -inline bool operator==(const LegacyPresenceScanFilter& a, - const LegacyPresenceScanFilter& b) { - if (a.scan_type != b.scan_type || - a.path_loss_threshold != b.path_loss_threshold || - a.actions != b.actions || - a.remote_public_credentials.size() != - b.remote_public_credentials.size() || - a.extended_properties != b.extended_properties) - return false; - for (size_t i = 0; i < a.remote_public_credentials.size(); ++i) { - if (a.remote_public_credentials[i].SerializeAsString() != - b.remote_public_credentials[i].SerializeAsString()) - return false; - } - return true; -} - -inline bool operator!=(const LegacyPresenceScanFilter& a, - const LegacyPresenceScanFilter& b) { - return !(a == b); -} - -/** - * An encapsulation of various parameters for requesting nearby scans. - */ -struct ScanRequest { - // Same as Metadata.account_name, to fetch private credential - // to broadcast. - std::string account_name; - - // Specifies which manager app to use to get credendentials for scan. - std::string manager_app_id; - - // Used to specify which types of remote SharedCredential to use during the - // scan. If empty, use all available types of remote SharedCredential. - std::vector identity_types; - - // For new Nearby SDK client (like chromeOs and Android U), use - // PresenceScanFilter; for Android T, use LegacyPresenceScanFilter. - std::vector > - scan_filters; - - // Whether to use BLE in the scan. - bool use_ble = false; - - ScanType scan_type = ScanType::kUnspecifiedScan; - PowerMode power_mode = PowerMode::kNoPower; - bool scan_only_when_screen_on = false; -}; - -inline bool operator==(const ScanRequest& a, const ScanRequest& b) { - if (a.identity_types != b.identity_types) return false; - if (a.scan_filters != b.scan_filters) return false; - return a.scan_only_when_screen_on == b.scan_only_when_screen_on && - a.power_mode == b.power_mode && a.scan_type == b.scan_type && - a.use_ble == b.use_ble && a.account_name == b.account_name && - a.identity_types == b.identity_types && - a.manager_app_id == b.manager_app_id; -} - -inline bool operator!=(const ScanRequest& a, const ScanRequest& b) { - return !(a == b); -} - -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_SCAN_REQUEST_H_ diff --git a/presence/scan_request_builder.cc b/presence/scan_request_builder.cc deleted file mode 100644 index 2d9b5740..00000000 --- a/presence/scan_request_builder.cc +++ /dev/null @@ -1,89 +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 "presence/scan_request_builder.h" - -#include -#include - -#include "absl/strings/string_view.h" -#include "absl/types/variant.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { - -using ::nearby::internal::IdentityType; - -ScanRequestBuilder& ScanRequestBuilder::SetAccountName( - absl::string_view account_name) { - request_.account_name = std::string(account_name); - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetPowerMode(PowerMode power_mode) { - request_.power_mode = power_mode; - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetScanType(ScanType scan_type) { - request_.scan_type = scan_type; - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::AddIdentityType( - IdentityType identity_type) { - request_.identity_types.push_back(identity_type); - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetIdentityTypes( - std::vector types) { - request_.identity_types = types; - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::AddScanFilter( - absl::variant scan_filter) { - request_.scan_filters.push_back(scan_filter); - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetScanFilters( - std::vector> - filters) { - request_.scan_filters = filters; - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetUseBle(bool use_ble) { - request_.use_ble = use_ble; - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetOnlyScreenOnScan( - bool screen_on_only_scan) { - request_.scan_only_when_screen_on = screen_on_only_scan; - return *this; -} - -ScanRequestBuilder& ScanRequestBuilder::SetManagerAppId( - absl::string_view manager_app_id) { - request_.manager_app_id = std::string(manager_app_id); - return *this; -} - -ScanRequest ScanRequestBuilder::Build() { return this->request_; } - -} // namespace presence -} // namespace nearby diff --git a/presence/scan_request_builder.h b/presence/scan_request_builder.h deleted file mode 100644 index 80bf770d..00000000 --- a/presence/scan_request_builder.h +++ /dev/null @@ -1,56 +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 THIRD_PARTY_NEARBY_PRESENCE_SCAN_REQUEST_BUILDER_H_ -#define THIRD_PARTY_NEARBY_PRESENCE_SCAN_REQUEST_BUILDER_H_ - -#include - -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "presence/power_mode.h" -#include "presence/presence_zone.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { -class ScanRequestBuilder { - private: - ScanRequest request_; - - public: - ScanRequestBuilder& SetAccountName(absl::string_view account_name); - ScanRequestBuilder& SetPowerMode(PowerMode power_mode); - ScanRequestBuilder& SetScanType(ScanType scan_type); - ScanRequestBuilder& AddIdentityType( - nearby::internal::IdentityType identity_type); - ScanRequestBuilder& SetIdentityTypes( - std::vector types); - ScanRequestBuilder& AddScanFilter( - absl::variant scan_filter); - ScanRequestBuilder& SetScanFilters( - std::vector> - scan_filters); - ScanRequestBuilder& SetUseBle(bool use_ble); - ScanRequestBuilder& SetOnlyScreenOnScan(bool screen_on_only_scan); - ScanRequestBuilder& SetManagerAppId(absl::string_view manager_app_id); - ScanRequest Build(); - inline bool operator==(const ScanRequestBuilder& other) const { - return request_ == other.request_; - } -}; -} // namespace presence -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_PRESENCE_SCAN_REQUEST_BUILDER_H_ diff --git a/presence/scan_request_builder_test.cc b/presence/scan_request_builder_test.cc deleted file mode 100644 index 1d0fd6be..00000000 --- a/presence/scan_request_builder_test.cc +++ /dev/null @@ -1,194 +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 "presence/scan_request_builder.h" - -#include - -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "internal/proto/credential.pb.h" -#include "presence/power_mode.h" -#include "presence/scan_request.h" - -namespace nearby { -namespace presence { -namespace { - -using ::nearby::internal::IdentityType; - -constexpr absl::string_view kAccountName = "Google User"; -constexpr bool kUseBle = true; -constexpr bool kOnlyScreenOnScan = true; -const IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PRIVATE_GROUP; -const ScanType kScanType = ScanType::kPresenceScan; -const PowerMode powerMode = PowerMode::kLowLatency; -constexpr absl::string_view kManagerAppId = "Google App Manager"; -DataElement CreateTestDataElement() { - return {DataElement::kTxPowerFieldType, "1"}; -} -PresenceScanFilter CreateTestPresenceScanFilter() { - return {.scan_type = kScanType, - .extended_properties = {CreateTestDataElement()}}; -} -LegacyPresenceScanFilter CreateTestLegacyPresenceScanFilter() { - return {.scan_type = kScanType}; -} - -TEST(ScanRequestBuilderTest, TestConstructor) { - EXPECT_FALSE(std::is_trivially_constructible::value); -} - -TEST(ScanRequestBuilderTest, TestSetAccountName) { - ScanRequestBuilder builder; - builder.SetAccountName(kAccountName); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.account_name, kAccountName); -} - -TEST(ScanRequestBuilderTest, TestSetPowerMode) { - ScanRequestBuilder builder; - builder.SetPowerMode(powerMode); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.power_mode, powerMode); -} - -TEST(ScanRequestBuilderTest, TestSetScanType) { - ScanRequestBuilder builder; - builder.SetScanType(kScanType); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.scan_type, kScanType); -} - -TEST(ScanRequestBuilderTest, TestAddIdentityType) { - ScanRequestBuilder builder; - builder.AddIdentityType(kIdentity); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.identity_types.size(), 1); - EXPECT_EQ(sr.identity_types[0], kIdentity); -} - -TEST(ScanRequestBuilderTest, TestSetIdentityTypes) { - ScanRequestBuilder builder; - std::vector types = {kIdentity}; - builder.SetIdentityTypes(types); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.identity_types.size(), 1); - EXPECT_EQ(sr.identity_types, types); -} - -TEST(ScanRequestBuilderTest, TestAddScanFilter) { - ScanRequestBuilder builder; - PresenceScanFilter presenceScanFilter = CreateTestPresenceScanFilter(); - LegacyPresenceScanFilter legacyPresenceScanFilter = - CreateTestLegacyPresenceScanFilter(); - builder.AddScanFilter(presenceScanFilter); - builder.AddScanFilter(legacyPresenceScanFilter); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.scan_filters.size(), 2); - EXPECT_TRUE(absl::holds_alternative(sr.scan_filters[0])); - EXPECT_NE(&absl::get(sr.scan_filters[0]), - &presenceScanFilter); - EXPECT_EQ(absl::get(sr.scan_filters[0]), - presenceScanFilter); - EXPECT_TRUE( - absl::holds_alternative(sr.scan_filters[1])); - EXPECT_NE(&absl::get(sr.scan_filters[1]), - &legacyPresenceScanFilter); - EXPECT_EQ(absl::get(sr.scan_filters[1]), - legacyPresenceScanFilter); -} - -TEST(ScanRequestBuilderTest, TestSetScanFilters) { - PresenceScanFilter presenceScanFilter = CreateTestPresenceScanFilter(); - LegacyPresenceScanFilter legacyPresenceScanFilter = - CreateTestLegacyPresenceScanFilter(); - std::vector> - filterList = {presenceScanFilter, legacyPresenceScanFilter}; - ScanRequestBuilder builder; - builder.SetScanFilters(filterList); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.scan_filters.size(), 2); - EXPECT_TRUE(absl::holds_alternative(sr.scan_filters[0])); - EXPECT_NE(&absl::get(sr.scan_filters[0]), - &presenceScanFilter); - EXPECT_EQ(absl::get(sr.scan_filters[0]), - presenceScanFilter); - EXPECT_TRUE( - absl::holds_alternative(sr.scan_filters[1])); - EXPECT_NE(&absl::get(sr.scan_filters[1]), - &legacyPresenceScanFilter); - EXPECT_EQ(absl::get(sr.scan_filters[1]), - legacyPresenceScanFilter); -} - -TEST(ScanRequestBuilderTest, TestNotEqualScanFilter) { - ScanRequestBuilder builderLegacy, builderModern; - ScanRequest legacy = - builderLegacy.AddScanFilter(LegacyPresenceScanFilter{}).Build(); - ScanRequest modern = - builderModern.AddScanFilter(PresenceScanFilter{}).Build(); - EXPECT_NE(legacy, modern); -} - -TEST(ScanRequestBuilderTest, TestSetUseBle) { - ScanRequestBuilder builder; - builder.SetUseBle(kUseBle); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.use_ble, kUseBle); -} - -TEST(ScanRequestBuilderTest, TestSetManagerAppId) { - ScanRequestBuilder builder; - builder.SetManagerAppId(kManagerAppId); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.manager_app_id, kManagerAppId); -} - -TEST(ScanRequestBuilderTest, TestSetOnlyScreenOnScan) { - ScanRequestBuilder builder; - builder.SetOnlyScreenOnScan(kOnlyScreenOnScan); - ScanRequest sr = builder.Build(); - EXPECT_EQ(sr.scan_only_when_screen_on, kOnlyScreenOnScan); -} - -TEST(ScanRequestBuilderTest, TestChainCalls) { - ScanRequestBuilder builder; - ScanRequest sr = builder.SetAccountName(kAccountName) - .SetPowerMode(powerMode) - .SetOnlyScreenOnScan(kOnlyScreenOnScan) - .SetUseBle(kUseBle) - .SetManagerAppId(kManagerAppId) - .Build(); - EXPECT_EQ(sr.account_name, kAccountName); - EXPECT_EQ(sr.scan_only_when_screen_on, kOnlyScreenOnScan); - EXPECT_EQ(sr.power_mode, powerMode); - EXPECT_EQ(sr.use_ble, kUseBle); - EXPECT_EQ(sr.manager_app_id, kManagerAppId); -} - -TEST(ScanRequestBuilderTest, TestCopy) { - ScanRequestBuilder builder1; - builder1.SetOnlyScreenOnScan(kOnlyScreenOnScan).SetUseBle(kUseBle); - ScanRequestBuilder builder2 = {builder1}; - EXPECT_EQ(builder1, builder2); - ScanRequest s1 = builder1.Build(); - ScanRequest s2 = builder2.Build(); - EXPECT_EQ(s1, s2); -} -} // namespace -} // namespace presence -} // namespace nearby diff --git a/proto/connections_enums.proto b/proto/connections_enums.proto index db519643..4c46ce5b 100644 --- a/proto/connections_enums.proto +++ b/proto/connections_enums.proto @@ -1447,6 +1447,11 @@ enum OperationResultCode { DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_HOST_NETWORK_NOT_AVAILABLE = 5058; // Failed to upgrade to high speed medium because no incoming HTTP connection DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_NO_INCOMING_HTTP_CONNECTION = 5059; + // Failed to upgrade to high speed medium because there is no USB device + // connected + DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_USB_NO_CONNECTED_DEVICE = 5060; + // Failed to upgrade to high speed medium because the upgrade is interrupted + DCT_ERROR_UPGRADE_HIGH_SPEED_MEDIUM_FAILED_INTERRUPTED = 5061; } enum StopAdvertisingReason { diff --git a/proto/sharing_enums.proto b/proto/sharing_enums.proto index 7adafdd3..d2f0b0bc 100644 --- a/proto/sharing_enums.proto +++ b/proto/sharing_enums.proto @@ -321,6 +321,7 @@ enum EventType { /*[ device_role = DEVICE_ROLE_INITIATOR ]*/; CLOUD_REGISTER_RECEIVER = 75 /*[ device_role = DEVICE_ROLE_REMOTE ]*/; + // Cloud upload events (routing updated in nearby_event_codes.proto). CLOUD_UPLOAD_START = 76 /*[ device_role = DEVICE_ROLE_INITIATOR ]*/; CLOUD_UPLOAD_END = 77 /*[ device_role = DEVICE_ROLE_INITIATOR ]*/; @@ -845,6 +846,15 @@ enum SharingUseCase { USE_CASE_NEARBY_SHARE_WITH_QR_CODE = 7 [deprecated = true]; // The user was redirected from Bluetooth sharing UI to Nearby Share USE_CASE_REDIRECTED_FROM_BLUETOOTH_SHARE = 8; + USE_CASE_TAP_TO_SHARE = 9; +} + +enum SharingSurface { + SURFACE_UNKNOWN = 0; + + SURFACE_QUICK_SHARE = 1; + SURFACE_APP = 2; + SURFACE_SYSTEM_SHARE_SHEET = 3; } // Used only for Windows App now. diff --git a/sharing/analytics/BUILD b/sharing/analytics/BUILD index b1ff308b..8294c9f9 100644 --- a/sharing/analytics/BUILD +++ b/sharing/analytics/BUILD @@ -13,15 +13,11 @@ # limitations under the License. load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") licenses(["notice"]) cc_library( name = "analytics", - srcs = [ - "analytics_recorder.cc", - ], hdrs = [ "analytics_device_settings.h", "analytics_information.h", @@ -29,38 +25,12 @@ cc_library( ], visibility = ["//visibility:public"], deps = [ - "//internal/analytics:event_logger", "//proto:sharing_enums_cc_proto", "//sharing:attachments", "//sharing:types", "//sharing/common:enum", "//sharing/proto:enums_cc_proto", - "//sharing/proto/analytics:sharing_log_cc_proto", - "@com_google_absl//absl/random", "@com_google_absl//absl/strings:string_view", "@com_google_absl//absl/time", - "@com_google_protobuf//:protobuf", - ], -) - -cc_test( - name = "analytics_test", - srcs = ["analytics_recorder_test.cc"], - deps = [ - ":analytics", - "//internal/analytics:mock_event_logger", - "//internal/platform/implementation:platform_impl", - "//proto:sharing_enums_cc_proto", - "//sharing:attachments", - "//sharing:types", - "//sharing/common:enum", - "//sharing/proto:enums_cc_proto", - "//sharing/proto:wire_format_cc_proto", - "//sharing/proto/analytics:sharing_log_cc_proto", - "@com_github_protobuf_matchers//protobuf-matchers", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/time", - "@com_google_googletest//:gtest_main", - "@com_google_protobuf//:protobuf", ], ) diff --git a/sharing/analytics/analytics_recorder.cc b/sharing/analytics/analytics_recorder.cc deleted file mode 100644 index 3a37df92..00000000 --- a/sharing/analytics/analytics_recorder.cc +++ /dev/null @@ -1,838 +0,0 @@ -// Copyright 2022-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. -// 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 "sharing/analytics/analytics_recorder.h" - -#include -#include -#include -#include - -#include "google/protobuf/duration.pb.h" -#include "absl/random/random.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "proto/sharing_enums.pb.h" -#include "sharing/analytics/analytics_device_settings.h" -#include "sharing/analytics/analytics_information.h" -#include "sharing/attachment_container.h" -#include "sharing/common/nearby_share_enums.h" -#include "sharing/file_attachment.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" -#include "sharing/proto/enums.pb.h" -#include "sharing/share_target.h" -#include "sharing/wifi_credentials_attachment.h" - -namespace nearby { -namespace sharing { -namespace analytics { -namespace { - -using ::location::nearby::proto::sharing::DeviceRelationship; -using ::location::nearby::proto::sharing::DeviceType; -using ::location::nearby::proto::sharing::EstablishConnectionStatus; -using ::location::nearby::proto::sharing::EventCategory; -using ::location::nearby::proto::sharing::EventType; -using ::location::nearby::proto::sharing::OSType; -using ::location::nearby::proto::sharing::ProcessReceivedAttachmentsStatus; -using ::location::nearby::proto::sharing::ShowNotificationStatus; -using ::location::nearby::proto::sharing::Visibility; - -using ::nearby::sharing::analytics::proto::SharingLog; -using ::nearby::sharing::proto::DataUsage; -using ::nearby::sharing::proto::DeviceVisibility; - -DeviceRelationship GetLoggerDeviceRelationship( - const ShareTarget& share_target) { - if (share_target.for_self_share) { - return DeviceRelationship::IS_SELF; - } else if (share_target.is_known) { - return DeviceRelationship::IS_CONTACT; - } else { - return DeviceRelationship::IS_STRANGER; - } -} - -DeviceType GetLoggerDeviceType(ShareTargetType type) { - switch (type) { - case ShareTargetType::kLaptop: - return DeviceType::LAPTOP; - case ShareTargetType::kPhone: - return DeviceType::PHONE; - case ShareTargetType::kTablet: - return DeviceType::TABLET; - default: - return DeviceType::UNKNOWN_DEVICE_TYPE; - } -} - -Visibility GetLoggerVisibility(DeviceVisibility visibility) { - switch (visibility) { - case DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS: - return Visibility::CONTACTS_ONLY; - case DeviceVisibility::DEVICE_VISIBILITY_SELECTED_CONTACTS: - return Visibility::SELECTED_CONTACTS_ONLY; - case DeviceVisibility::DEVICE_VISIBILITY_EVERYONE: - return Visibility::EVERYONE; - case DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE: - return Visibility::SELF_SHARE; - case DeviceVisibility::DEVICE_VISIBILITY_HIDDEN: - return Visibility::HIDDEN; - case DeviceVisibility::DEVICE_VISIBILITY_UNSPECIFIED: - default: - return Visibility::UNKNOWN_VISIBILITY; - } -} - -location::nearby::proto::sharing::DataUsage GetLoggerDataUsage( - DataUsage data_usage) { - switch (data_usage) { - case DataUsage::OFFLINE_DATA_USAGE: - return location::nearby::proto::sharing::DataUsage::OFFLINE; - case DataUsage::ONLINE_DATA_USAGE: - return location::nearby::proto::sharing::DataUsage::ONLINE; - case DataUsage::WIFI_ONLY_DATA_USAGE: - return location::nearby::proto::sharing::DataUsage::WIFI_ONLY; - default: - return location::nearby::proto::sharing::DataUsage::UNKNOWN_DATA_USAGE; - } -} - -void SetShareTargetInfo(SharingLog::ShareTargetInfo* share_target_info, - ShareTargetType device_type, - DeviceRelationship relationship, - OSType os_type = OSType::UNKNOWN_OS_TYPE) { - share_target_info->set_device_relationship(relationship); - share_target_info->set_device_type(GetLoggerDeviceType(device_type)); - if (os_type == OSType::UNKNOWN_OS_TYPE && - device_type == ShareTargetType::kPhone) { - // If the device type is phone, just set the OS type to android because - // no other phone OS for now. - share_target_info->set_os_type(OSType::ANDROID); - } else { - share_target_info->set_os_type(os_type); - } -} - -void SetShareTargetInfo(SharingLog::ShareTargetInfo* share_target_info, - const ShareTarget& share_target, - OSType os_type = OSType::UNKNOWN_OS_TYPE) { - share_target_info->set_device_relationship( - GetLoggerDeviceRelationship(share_target)); - share_target_info->set_device_type(GetLoggerDeviceType(share_target.type)); - if (os_type == OSType::UNKNOWN_OS_TYPE && - share_target.type == ShareTargetType::kPhone) { - // If the device type is phone, just set the OS type to android because - // no other phone OS for now. - share_target_info->set_os_type(OSType::ANDROID); - } else { - share_target_info->set_os_type(os_type); - } -} - -void SetAttachmentInfo(SharingLog::AttachmentsInfo* attachments_info, - const AttachmentContainer& attachments) { - for (const auto& attachment : attachments.GetTextAttachments()) { - SharingLog::TextAttachment::Type type = - SharingLog::TextAttachment::UNKNOWN_TEXT_TYPE; - switch (attachment.GetShareType()) { - case ShareType::kPhone: - type = SharingLog::TextAttachment::PHONE_NUMBER; - break; - case ShareType::kUrl: - type = SharingLog::TextAttachment::URL; - break; - case ShareType::kAddress: - type = SharingLog::TextAttachment::ADDRESS; - break; - case ShareType::kText: - // Apply UNKNOWN_TEXT_TYPE for it based on analytics design. - break; - default: - break; - } - SharingLog::TextAttachment* text_attachment = - attachments_info->mutable_text_attachment()->Add(); - text_attachment->set_type(type); - text_attachment->set_size_bytes(attachment.size()); - text_attachment->set_source_type(attachment.source_type()); - text_attachment->set_batch_id(attachment.batch_id()); - } - - for (const auto& attachment : attachments.GetFileAttachments()) { - SharingLog::FileAttachment::Type type = - SharingLog::FileAttachment::UNKNOWN_FILE_TYPE; - switch (attachment.GetShareType()) { - case ShareType::kImageFile: - type = SharingLog::FileAttachment::IMAGE; - break; - case ShareType::kVideoFile: - type = SharingLog::FileAttachment::VIDEO; - break; - case ShareType::kAudioFile: - type = SharingLog::FileAttachment::AUDIO; - break; - case ShareType::kPdfFile: - case ShareType::kTextFile: - case ShareType::kGoogleDocsFile: - case ShareType::kGoogleSheetsFile: - case ShareType::kGoogleSlidesFile: - type = SharingLog::FileAttachment::DOCUMENT; - break; - case ShareType::kUnknownFile: - // The default type is set to type. - break; - default: - break; - } - SharingLog::FileAttachment* file_attachment = - attachments_info->mutable_file_attachment()->Add(); - file_attachment->set_type(type); - file_attachment->set_size_bytes(attachment.size()); - file_attachment->set_offset_bytes(0); - file_attachment->set_source_type(attachment.source_type()); - file_attachment->set_batch_id(attachment.batch_id()); - } - - for (const auto& attachment : attachments.GetWifiCredentialsAttachments()) { - SharingLog::WifiCredentialsAttachment* wifi_credentials_attachment = - attachments_info->mutable_wifi_credentials_attachment()->Add(); - wifi_credentials_attachment->set_source_type(attachment.source_type()); - wifi_credentials_attachment->set_batch_id(attachment.batch_id()); - } -} - -} // namespace - -void AnalyticsRecorder::NewEstablishConnection( - int64_t session_id, EstablishConnectionStatus connection_status, - const ShareTarget& share_target, int transfer_position, - int concurrent_connections, int64_t duration_millis, - std::optional referrer_package) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::ESTABLISH_CONNECTION); - - auto* establish_connection = sharing_log->mutable_establish_connection(); - - establish_connection->set_session_id(session_id); - establish_connection->set_status(connection_status); - SetShareTargetInfo(establish_connection->mutable_share_target_info(), - share_target); - establish_connection->set_transfer_position(transfer_position); - establish_connection->set_concurrent_connections(concurrent_connections); - establish_connection->set_duration_millis(duration_millis); - if (referrer_package.has_value()) { - establish_connection->set_referrer_name(*referrer_package); - } - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewAcceptAgreements() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::ACCEPT_AGREEMENTS); - - sharing_log->mutable_accept_agreements(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewDeclineAgreements() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::DECLINE_AGREEMENTS); - - sharing_log->mutable_decline_agreements(); - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewAddContact() { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::SETTINGS_EVENT, EventType::ADD_CONTACT); - - sharing_log->mutable_add_contact(); - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewRemoveContact() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::REMOVE_CONTACT); - - sharing_log->mutable_remove_contact(); - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewTapFeedback() { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::SETTINGS_EVENT, EventType::TAP_FEEDBACK); - - sharing_log->mutable_tap_feedback(); - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewTapHelp() { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::SETTINGS_EVENT, EventType::TAP_HELP); - - sharing_log->mutable_tap_help(); - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewLaunchDeviceContactConsent( - ::location::nearby::proto::sharing::ConsentAcceptanceStatus status) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::LAUNCH_CONSENT); - - auto* launch_consent = sharing_log->mutable_launch_consent(); - launch_consent->set_status(status); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewAdvertiseDevicePresenceEnd(int64_t session_id) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::ADVERTISE_DEVICE_PRESENCE_END); - - auto* advertise_device_presence_end = - sharing_log->mutable_advertise_device_presence_end(); - advertise_device_presence_end->set_session_id(session_id); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewAdvertiseDevicePresenceStart( - int64_t session_id, DeviceVisibility visibility, - ::location::nearby::proto::sharing::SessionStatus status, - DataUsage data_usage, std::optional referrer_package) { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::RECEIVING_EVENT, - EventType::ADVERTISE_DEVICE_PRESENCE_START); - - auto* advertise_device_presence_start = - sharing_log->mutable_advertise_device_presence_start(); - advertise_device_presence_start->set_session_id(session_id); - advertise_device_presence_start->set_visibility( - GetLoggerVisibility(visibility)); - advertise_device_presence_start->set_status(status); - advertise_device_presence_start->set_data_usage( - GetLoggerDataUsage(data_usage)); - if (referrer_package.has_value()) { - advertise_device_presence_start->set_referrer_name(*referrer_package); - } - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewDescribeAttachments( - const AttachmentContainer& attachments) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::DESCRIBE_ATTACHMENTS); - - auto* describe_attachments = sharing_log->mutable_describe_attachments(); - SetAttachmentInfo(describe_attachments->mutable_attachments_info(), - attachments); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewDiscoverShareTarget( - const ShareTarget& share_target, int64_t session_id, - int64_t latency_since_scanning_start_millis, int64_t flow_id, - std::optional referrer_package, - int64_t latency_since_send_surface_registered_millis) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::DISCOVER_SHARE_TARGET); - - auto* discover_share_target = sharing_log->mutable_discover_share_target(); - discover_share_target->set_session_id(session_id); - auto* duration = discover_share_target->mutable_duration_since_scanning(); - duration->set_seconds(latency_since_scanning_start_millis / 1000); - duration->set_nanos((latency_since_scanning_start_millis % 1000) * 1000000); - SetShareTargetInfo(discover_share_target->mutable_share_target_info(), - share_target); - discover_share_target->set_session_id(session_id); - discover_share_target->set_flow_id(flow_id); - - discover_share_target->set_latency_since_activity_start_millis( - latency_since_send_surface_registered_millis > 0 - ? latency_since_send_surface_registered_millis - : -1); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewEnableNearbySharing( - ::location::nearby::proto::sharing::NearbySharingStatus status) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::ENABLE_NEARBY_SHARING); - - auto* enable_nearby_sharing = sharing_log->mutable_enable_nearby_sharing(); - enable_nearby_sharing->set_status(status); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewOpenReceivedAttachments( - const AttachmentContainer& attachments, int64_t session_id) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::OPEN_RECEIVED_ATTACHMENTS); - - auto* open_received_attachments = - sharing_log->mutable_open_received_attachments(); - SetAttachmentInfo(open_received_attachments->mutable_attachments_info(), - attachments); - open_received_attachments->set_session_id(session_id); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewProcessReceivedAttachmentsEnd( - int64_t session_id, ProcessReceivedAttachmentsStatus status) { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::RECEIVING_EVENT, - EventType::PROCESS_RECEIVED_ATTACHMENTS_END); - - auto* process_received_attachments_end = - sharing_log->mutable_process_received_attachments_end(); - process_received_attachments_end->set_status(status); - process_received_attachments_end->set_session_id(session_id); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewReceiveAttachmentsEnd( - int64_t session_id, int64_t received_bytes, - ::location::nearby::proto::sharing::AttachmentTransmissionStatus status, - std::optional referrer_package) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::RECEIVE_ATTACHMENTS_END); - - auto* receive_attachments_end = - sharing_log->mutable_receive_attachments_end(); - receive_attachments_end->set_session_id(session_id); - receive_attachments_end->set_received_bytes(received_bytes); - receive_attachments_end->set_status(status); - if (referrer_package.has_value()) { - receive_attachments_end->set_referrer_name(*referrer_package); - } - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewReceiveAttachmentsStart( - int64_t session_id, const AttachmentContainer& attachments) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::RECEIVE_ATTACHMENTS_START); - - auto* receive_attachments_start = - sharing_log->mutable_receive_attachments_start(); - SetAttachmentInfo(receive_attachments_start->mutable_attachments_info(), - attachments); - receive_attachments_start->set_session_id(session_id); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewReceiveFastInitialization( - int64_t timeElapseSinceScreenUnlockMillis) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::RECEIVE_FAST_INITIALIZATION); - - auto* receive_fast_initialization = - sharing_log->mutable_receive_initialization(); - - receive_fast_initialization->set_time_elapse_since_screen_unlock_millis( - timeElapseSinceScreenUnlockMillis); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewAcceptFastInitialization() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::ACCEPT_FAST_INITIALIZATION); - - sharing_log->mutable_accept_fast_initialization(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewDismissFastInitialization() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::DISMISS_FAST_INITIALIZATION); - - sharing_log->mutable_dismiss_fast_initialization(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewReceiveIntroduction( - int64_t session_id, const ShareTarget& share_target, - std::optional referrer_package, - ::location::nearby::proto::sharing::OSType share_target_os_type) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::RECEIVE_INTRODUCTION); - - auto* receive_introduction = sharing_log->mutable_receive_introduction(); - receive_introduction->set_session_id(session_id); - SetShareTargetInfo(receive_introduction->mutable_share_target_info(), - share_target, share_target_os_type); - if (referrer_package.has_value()) { - receive_introduction->set_referrer_name(*referrer_package); - } - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewRespondToIntroduction( - ::location::nearby::proto::sharing::ResponseToIntroduction action, - int64_t session_id) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::RESPOND_TO_INTRODUCTION); - - auto* respond_to_introduction = sharing_log->mutable_respond_introduction(); - respond_to_introduction->set_session_id(session_id); - respond_to_introduction->set_action(action); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewTapPrivacyNotification() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::TAP_PRIVACY_NOTIFICATION); - - sharing_log->mutable_tap_privacy_notification(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewDismissPrivacyNotification() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::RECEIVING_EVENT, EventType::DISMISS_PRIVACY_NOTIFICATION); - - sharing_log->mutable_dismiss_privacy_notification(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewScanForShareTargetsEnd(int64_t session_id) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SCAN_FOR_SHARE_TARGETS_END); - - auto* scan_for_share_targets_end = - sharing_log->mutable_scan_for_share_targets_end(); - scan_for_share_targets_end->set_session_id(session_id); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewScanForShareTargetsStart( - int64_t session_id, - ::location::nearby::proto::sharing::SessionStatus status, - AnalyticsInformation analytics_information, int64_t flow_id, - std::optional referrer_package) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SCAN_FOR_SHARE_TARGETS_START); - - auto* scan_for_share_targets_start = - sharing_log->mutable_scan_for_share_targets_start(); - scan_for_share_targets_start->set_session_id(session_id); - scan_for_share_targets_start->set_status(status); - scan_for_share_targets_start->set_scan_type( - static_cast<::location::nearby::proto::sharing::ScanType>( - analytics_information.send_surface_state)); - scan_for_share_targets_start->set_flow_id(flow_id); - if (referrer_package.has_value()) { - scan_for_share_targets_start->set_referrer_name(*referrer_package); - } - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSendAttachmentsEnd( - int64_t session_id, int64_t sent_bytes, const ShareTarget& share_target, - ::location::nearby::proto::sharing::AttachmentTransmissionStatus status, - int transfer_position, int concurrent_connections, int64_t duration_millis, - std::optional referrer_package, - ::location::nearby::proto::sharing::ConnectionLayerStatus - connection_layer_status, - ::location::nearby::proto::sharing::OSType share_target_os_type) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SEND_ATTACHMENTS_END); - - auto* send_attachments_end = sharing_log->mutable_send_attachments_end(); - send_attachments_end->set_session_id(session_id); - send_attachments_end->set_sent_bytes(sent_bytes); - SetShareTargetInfo(send_attachments_end->mutable_share_target_info(), - share_target, share_target_os_type); - send_attachments_end->set_status(status); - send_attachments_end->set_transfer_position(transfer_position); - send_attachments_end->set_concurrent_connections(concurrent_connections); - send_attachments_end->set_duration_millis(duration_millis); - if (referrer_package.has_value()) { - send_attachments_end->set_referrer_name(*referrer_package); - } - send_attachments_end->set_connection_layer_status(connection_layer_status); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSendAttachmentsStart( - int64_t session_id, const AttachmentContainer& attachments, - int transfer_position, int concurrent_connections, - bool advanced_protection_enabled, bool advanced_protection_mismatch) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SEND_ATTACHMENTS_START); - - auto* send_attachments_start = sharing_log->mutable_send_attachments_start(); - send_attachments_start->set_session_id(session_id); - SetAttachmentInfo(send_attachments_start->mutable_attachments_info(), - attachments); - send_attachments_start->set_transfer_position(transfer_position); - send_attachments_start->set_concurrent_connections(concurrent_connections); - send_attachments_start->set_advanced_protection_enabled( - advanced_protection_enabled); - send_attachments_start->set_advanced_protection_mismatch( - advanced_protection_mismatch); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSendFastInitialization() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SEND_FAST_INITIALIZATION); - - sharing_log->mutable_send_initialization(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSendStart(int64_t session_id, int transfer_position, - int concurrent_connections, - const ShareTarget& share_target) { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::SENDING_EVENT, EventType::SEND_START); - - auto* send_start = sharing_log->mutable_send_start(); - send_start->set_session_id(session_id); - send_start->set_transfer_position(transfer_position); - send_start->set_concurrent_connections(concurrent_connections); - SetShareTargetInfo(send_start->mutable_share_target_info(), share_target); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSendIntroduction( - ShareTargetType target_type, int64_t session_id, - DeviceRelationship relationship, - ::location::nearby::proto::sharing::OSType share_target_os_type) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SEND_INTRODUCTION); - auto* send_introduction = sharing_log->mutable_send_introduction(); - SetShareTargetInfo(send_introduction->mutable_share_target_info(), - target_type, relationship, share_target_os_type); - send_introduction->set_session_id(session_id); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSendIntroduction( - int64_t session_id, const ShareTarget& share_target, int transfer_position, - int concurrent_connections, - ::location::nearby::proto::sharing::OSType share_target_os_type) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SENDING_EVENT, EventType::SEND_INTRODUCTION); - - auto* send_introduction = sharing_log->mutable_send_introduction(); - SetShareTargetInfo(send_introduction->mutable_share_target_info(), - share_target, share_target_os_type); - send_introduction->set_session_id(session_id); - send_introduction->set_transfer_position(transfer_position); - send_introduction->set_concurrent_connections(concurrent_connections); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSetVisibility(DeviceVisibility src_visibility, - DeviceVisibility dst_visibility, - int64_t duration_millis) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::SET_VISIBILITY); - - auto* set_visibility = sharing_log->mutable_set_visibility(); - set_visibility->set_visibility(GetLoggerVisibility(dst_visibility)); - set_visibility->set_source_visibility(GetLoggerVisibility(src_visibility)); - set_visibility->set_duration_millis(duration_millis); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewDeviceSettings(AnalyticsDeviceSettings settings) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::DEVICE_SETTINGS); - - auto* device_settings = sharing_log->mutable_device_settings(); - device_settings->set_data_usage(GetLoggerDataUsage(settings.data_usage)); - device_settings->set_device_name_size(settings.device_name_size); - device_settings->set_is_show_notification_enabled( - settings.is_fast_init_notification_enabled); - device_settings->set_visibility(GetLoggerVisibility(settings.visibility)); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSetDataUsage(DataUsage original_preference, - DataUsage preference) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::SET_DATA_USAGE); - - auto* set_data_usage = sharing_log->mutable_set_data_usage(); - set_data_usage->set_original_preference( - GetLoggerDataUsage(original_preference)); - set_data_usage->set_preference(GetLoggerDataUsage(preference)); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewAddQuickSettingsTile() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::ADD_QUICK_SETTINGS_TILE); - - sharing_log->mutable_add_quick_settings_tile(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewRemoveQuickSettingsTile() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::REMOVE_QUICK_SETTINGS_TILE); - - sharing_log->mutable_remove_quick_settings_tile(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewTapQuickSettingsTile() { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::TAP_QUICK_SETTINGS_TILE); - - sharing_log->mutable_tap_quick_settings_tile(); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewToggleShowNotification( - ShowNotificationStatus prev_status, ShowNotificationStatus current_status) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::TOGGLE_SHOW_NOTIFICATION); - - auto* toggle_show_notification = - sharing_log->mutable_toggle_show_notification(); - toggle_show_notification->set_current_status(current_status); - toggle_show_notification->set_previous_status(prev_status); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewSetDeviceName(int device_name_size) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::SET_DEVICE_NAME); - - auto* set_device_name = sharing_log->mutable_set_device_name(); - set_device_name->set_device_name_size(device_name_size); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewRequestSettingPermissions( - ::location::nearby::proto::sharing::PermissionRequestType type, - ::location::nearby::proto::sharing::PermissionRequestResult result) { - std::unique_ptr sharing_log = CreateSharingLog( - EventCategory::SETTINGS_EVENT, EventType::REQUEST_SETTING_PERMISSIONS); - - auto* request_setting_permissions = - sharing_log->mutable_request_setting_permissions(); - request_setting_permissions->set_permission_type(type); - request_setting_permissions->set_permission_request_result(result); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewInstallAPKStatus( - ::location::nearby::proto::sharing::InstallAPKStatus status, - ::location::nearby::proto::sharing::ApkSource source) { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::RECEIVING_EVENT, EventType::INSTALL_APK); - - auto* install_apk_status = sharing_log->mutable_install_apk_status(); - install_apk_status->add_status(status); - install_apk_status->add_source(source); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewVerifyAPKStatus( - ::location::nearby::proto::sharing::VerifyAPKStatus status, - ::location::nearby::proto::sharing::ApkSource source) { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::RECEIVING_EVENT, EventType::VERIFY_APK); - - auto* verify_apk_status = sharing_log->mutable_verify_apk_status(); - verify_apk_status->add_status(status); - verify_apk_status->add_source(source); - - LogEvent(*sharing_log); -} - -void AnalyticsRecorder::NewRpcCallStatus( - absl::string_view rpc_name, - SharingLog::RpcCallStatus::RpcDirection direction, - int error_code, absl::Duration latency) { - std::unique_ptr sharing_log = - CreateSharingLog(EventCategory::RPC_EVENT, EventType::RPC_CALL_STATUS); - - auto* rpc_call_status = sharing_log->mutable_rpc_call_status(); - rpc_call_status->set_rpc_name(std::string(rpc_name)); - rpc_call_status->set_direction(direction); - rpc_call_status->set_error_code(error_code); - rpc_call_status->set_latency_millis(absl::ToInt64Milliseconds(latency)); - - LogEvent(*sharing_log); -} - -// Start private methods. - -std::unique_ptr AnalyticsRecorder::CreateSharingLog( - EventCategory event_category, EventType event_type) { - auto sharing_log = std::make_unique(); - sharing_log->set_event_category(event_category); - sharing_log->set_event_type(event_type); - sharing_log->mutable_event_metadata()->set_vendor_id(vendor_id_); - return sharing_log; -} - -void AnalyticsRecorder::LogEvent(const SharingLog& message) { - if (event_logger_ == nullptr) { - return; - } - - event_logger_->Log(message); -} - -int64_t AnalyticsRecorder::GenerateNextId() { - absl::BitGen bit_gen; - return absl::Uniform(bit_gen, 0, INT64_MAX - 1) + 1; -} - -} // namespace analytics -} // namespace sharing -} // namespace nearby diff --git a/sharing/analytics/analytics_recorder.h b/sharing/analytics/analytics_recorder.h index e3b776b9..d1bbba4e 100644 --- a/sharing/analytics/analytics_recorder.h +++ b/sharing/analytics/analytics_recorder.h @@ -16,205 +16,195 @@ #define THIRD_PARTY_NEARBY_SHARING_ANALYTICS_ANALYTICS_RECORDER_H_ #include -#include #include #include #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "internal/analytics/event_logger.h" #include "proto/sharing_enums.pb.h" #include "sharing/analytics/analytics_device_settings.h" #include "sharing/analytics/analytics_information.h" #include "sharing/attachment_container.h" #include "sharing/common/nearby_share_enums.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" #include "sharing/proto/enums.pb.h" #include "sharing/share_target.h" -namespace nearby { -namespace sharing { -namespace analytics { +namespace nearby::sharing::analytics { class AnalyticsRecorder { public: - explicit AnalyticsRecorder(int32_t vendor_id, - nearby::analytics::EventLogger* event_logger) - : vendor_id_(vendor_id), event_logger_(event_logger) {} - ~AnalyticsRecorder() = default; + enum class RpcDirection { + kUnknown = 0, + kIncoming = 1, + kOutgoing = 2, + }; - void NewEstablishConnection( + AnalyticsRecorder() = default; + virtual ~AnalyticsRecorder() = default; + + virtual void NewEstablishConnection( int64_t session_id, location::nearby::proto::sharing::EstablishConnectionStatus connection_status, const ShareTarget& share_target, int transfer_position, int concurrent_connections, int64_t duration_millis, - std::optional referrer_package); + std::optional referrer_package) = 0; - void NewAcceptAgreements(); + virtual void NewAcceptAgreements() = 0; - void NewDeclineAgreements(); + virtual void NewDeclineAgreements() = 0; - void NewAddContact(); + virtual void NewAddContact() = 0; - void NewRemoveContact(); + virtual void NewRemoveContact() = 0; - void NewTapFeedback(); + virtual void NewTapFeedback() = 0; - void NewTapHelp(); + virtual void NewTapHelp() = 0; - void NewLaunchDeviceContactConsent( - location::nearby::proto::sharing::ConsentAcceptanceStatus status); + virtual void NewLaunchDeviceContactConsent( + location::nearby::proto::sharing::ConsentAcceptanceStatus status) = 0; - void NewAdvertiseDevicePresenceEnd(int64_t session_id); + virtual void NewAdvertiseDevicePresenceEnd(int64_t session_id) = 0; - void NewAdvertiseDevicePresenceStart( + virtual void NewAdvertiseDevicePresenceStart( int64_t session_id, nearby::sharing::proto::DeviceVisibility visibility, location::nearby::proto::sharing::SessionStatus status, nearby::sharing::proto::DataUsage data_usage, - std::optional referrer_package); + std::optional referrer_package) = 0; - void NewDescribeAttachments(const AttachmentContainer& attachments); + virtual void NewDescribeAttachments( + const AttachmentContainer& attachments) = 0; - void NewDiscoverShareTarget( + virtual void NewDiscoverShareTarget( const ShareTarget& share_target, int64_t session_id, int64_t latency_since_scanning_start_millis, int64_t flow_id, std::optional referrer_package, - int64_t latency_since_send_surface_registered_millis); + int64_t latency_since_send_surface_registered_millis) = 0; - void NewEnableNearbySharing( - location::nearby::proto::sharing::NearbySharingStatus status); + virtual void NewEnableNearbySharing( + location::nearby::proto::sharing::NearbySharingStatus status) = 0; - void NewOpenReceivedAttachments(const AttachmentContainer& attachments, - int64_t session_id); + virtual void NewOpenReceivedAttachments( + const AttachmentContainer& attachments, int64_t session_id) = 0; - void NewProcessReceivedAttachmentsEnd( + virtual void NewProcessReceivedAttachmentsEnd( int64_t session_id, location::nearby::proto::sharing::ProcessReceivedAttachmentsStatus - status); + status) = 0; - void NewReceiveAttachmentsEnd( + virtual void NewReceiveAttachmentsEnd( int64_t session_id, int64_t received_bytes, location::nearby::proto::sharing::AttachmentTransmissionStatus status, - std::optional referrer_package); + std::optional referrer_package) = 0; - void NewReceiveAttachmentsStart(int64_t session_id, - const AttachmentContainer& attachments); + virtual void NewReceiveAttachmentsStart( + int64_t session_id, const AttachmentContainer& attachments) = 0; - void NewReceiveFastInitialization(int64_t timeElapseSinceScreenUnlockMillis); + virtual void NewReceiveFastInitialization( + int64_t timeElapseSinceScreenUnlockMillis) = 0; - void NewAcceptFastInitialization(); + virtual void NewAcceptFastInitialization() = 0; - void NewDismissFastInitialization(); + virtual void NewDismissFastInitialization() = 0; - void NewReceiveIntroduction( + virtual void NewReceiveIntroduction( int64_t session_id, const ShareTarget& share_target, std::optional referrer_package, - location::nearby::proto::sharing::OSType share_target_os_type); + location::nearby::proto::sharing::OSType share_target_os_type) = 0; - void NewRespondToIntroduction( + virtual void NewRespondToIntroduction( location::nearby::proto::sharing::ResponseToIntroduction action, - int64_t session_id); + int64_t session_id) = 0; - void NewTapPrivacyNotification(); + virtual void NewTapPrivacyNotification() = 0; - void NewDismissPrivacyNotification(); + virtual void NewDismissPrivacyNotification() = 0; - void NewScanForShareTargetsEnd(int64_t session_id); + virtual void NewScanForShareTargetsEnd(int64_t session_id) = 0; - void NewScanForShareTargetsStart( + virtual void NewScanForShareTargetsStart( int64_t session_id, location::nearby::proto::sharing::SessionStatus status, AnalyticsInformation analytics_information, int64_t flow_id, - std::optional referrer_package); + std::optional referrer_package) = 0; - void NewSendAttachmentsEnd( + virtual void NewSendAttachmentsEnd( int64_t session_id, int64_t sent_bytes, const ShareTarget& share_target, location::nearby::proto::sharing::AttachmentTransmissionStatus status, int transfer_position, int concurrent_connections, int64_t duration_millis, std::optional referrer_package, location::nearby::proto::sharing::ConnectionLayerStatus connection_layer_status, - location::nearby::proto::sharing::OSType share_target_os_type); + location::nearby::proto::sharing::OSType share_target_os_type) = 0; - void NewSendAttachmentsStart(int64_t session_id, - const AttachmentContainer& attachments, - int transfer_position, - int concurrent_connections, - bool advanced_protection_enabled, - bool advanced_protection_mismatch); + virtual void NewSendAttachmentsStart(int64_t session_id, + const AttachmentContainer& attachments, + int transfer_position, + int concurrent_connections, + bool advanced_protection_enabled, + bool advanced_protection_mismatch) = 0; - void NewSendFastInitialization(); + virtual void NewSendFastInitialization() = 0; - void NewSendStart(int64_t session_id, int transfer_position, - int concurrent_connections, - const ShareTarget& share_target); + virtual void NewSendStart(int64_t session_id, int transfer_position, + int concurrent_connections, + const ShareTarget& share_target) = 0; - void NewSendIntroduction( + virtual void NewSendIntroduction( ShareTargetType target_type, int64_t session_id, location::nearby::proto::sharing::DeviceRelationship relationship, - location::nearby::proto::sharing::OSType share_target_os_type); + location::nearby::proto::sharing::OSType share_target_os_type) = 0; - void NewSendIntroduction( + virtual void NewSendIntroduction( int64_t session_id, const ShareTarget& share_target, int transfer_position, int concurrent_connections, - location::nearby::proto::sharing::OSType share_target_os_type); + location::nearby::proto::sharing::OSType share_target_os_type) = 0; - void NewSetVisibility(nearby::sharing::proto::DeviceVisibility src_visibility, - nearby::sharing::proto::DeviceVisibility dst_visibility, - int64_t duration_millis); + virtual void NewSetVisibility( + nearby::sharing::proto::DeviceVisibility src_visibility, + nearby::sharing::proto::DeviceVisibility dst_visibility, + int64_t duration_millis) = 0; - void NewDeviceSettings(AnalyticsDeviceSettings settings); + virtual void NewDeviceSettings(AnalyticsDeviceSettings settings) = 0; - void NewSetDataUsage(nearby::sharing::proto::DataUsage original_preference, - nearby::sharing::proto::DataUsage preference); + virtual void NewSetDataUsage( + nearby::sharing::proto::DataUsage original_preference, + nearby::sharing::proto::DataUsage preference) = 0; - void NewAddQuickSettingsTile(); + virtual void NewAddQuickSettingsTile() = 0; - void NewRemoveQuickSettingsTile(); + virtual void NewRemoveQuickSettingsTile() = 0; - void NewTapQuickSettingsTile(); + virtual void NewTapQuickSettingsTile() = 0; - void NewToggleShowNotification( + virtual void NewToggleShowNotification( location::nearby::proto::sharing::ShowNotificationStatus prev_status, - location::nearby::proto::sharing::ShowNotificationStatus current_status); + location::nearby::proto::sharing::ShowNotificationStatus + current_status) = 0; - void NewSetDeviceName(int device_name_size); + virtual void NewSetDeviceName(int device_name_size) = 0; - void NewRequestSettingPermissions( + virtual void NewRequestSettingPermissions( location::nearby::proto::sharing::PermissionRequestType type, - location::nearby::proto::sharing::PermissionRequestResult result); + location::nearby::proto::sharing::PermissionRequestResult result) = 0; - void NewInstallAPKStatus( + virtual void NewInstallAPKStatus( location::nearby::proto::sharing::InstallAPKStatus status, - location::nearby::proto::sharing::ApkSource source); + location::nearby::proto::sharing::ApkSource source) = 0; - void NewVerifyAPKStatus( + virtual void NewVerifyAPKStatus( location::nearby::proto::sharing::VerifyAPKStatus status, - location::nearby::proto::sharing::ApkSource source); + location::nearby::proto::sharing::ApkSource source) = 0; - void NewRpcCallStatus( - absl::string_view rpc_name, - nearby::sharing::analytics::proto::SharingLog::RpcCallStatus::RpcDirection - direction, - int error_code, absl::Duration latency); + virtual void NewRpcCallStatus(absl::string_view rpc_name, + RpcDirection direction, int error_code, + absl::Duration latency) = 0; // Generates a random number for session ID or flow ID. - int64_t GenerateNextId(); - - private: - std::unique_ptr - CreateSharingLog( - location::nearby::proto::sharing::EventCategory event_category, - location::nearby::proto::sharing::EventType event_type); - void LogEvent(const nearby::sharing::analytics::proto::SharingLog& message); - - const int32_t vendor_id_; - nearby::analytics::EventLogger* event_logger_ = nullptr; + virtual int64_t GenerateNextId() = 0; }; -} // namespace analytics -} // namespace sharing -} // namespace nearby +} // namespace nearby::sharing::analytics #endif // THIRD_PARTY_NEARBY_SHARING_ANALYTICS_ANALYTICS_RECORDER_H_ diff --git a/sharing/analytics/analytics_recorder_test.cc b/sharing/analytics/analytics_recorder_test.cc deleted file mode 100644 index 1686947d..00000000 --- a/sharing/analytics/analytics_recorder_test.cc +++ /dev/null @@ -1,901 +0,0 @@ -// Copyright 2022-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. -// 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 "sharing/analytics/analytics_recorder.h" - -#include - -#include -#include -#include - -#include "google/protobuf/duration.pb.h" -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" -#include "gtest/gtest.h" -#include "absl/strings/string_view.h" -#include "absl/time/time.h" -#include "internal/analytics/mock_event_logger.h" -#include "proto/sharing_enums.pb.h" -#include "sharing/analytics/analytics_device_settings.h" -#include "sharing/analytics/analytics_information.h" -#include "sharing/attachment_container.h" -#include "sharing/common/nearby_share_enums.h" -#include "sharing/file_attachment.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" -#include "sharing/proto/enums.pb.h" -#include "sharing/proto/wire_format.pb.h" -#include "sharing/share_target.h" -#include "sharing/text_attachment.h" - -namespace nearby::sharing::analytics { -namespace { - -using ::location::nearby::proto::sharing::EventCategory; -using ::location::nearby::proto::sharing::EventType; -using ::location::nearby::proto::sharing::OSType; -using ::nearby::analytics::MockEventLogger; -using ::nearby::sharing::analytics::proto::SharingLog; -using ::nearby::sharing::proto::DataUsage; -using ::nearby::sharing::proto::DeviceVisibility; -using ::testing::An; - -constexpr absl::string_view kFileName = "fileName"; -constexpr absl::string_view kTextBody = "textBody"; -constexpr absl::string_view kFileDocumentName = "abc.pdf"; -constexpr absl::string_view kFileMimeType = "application/pdf"; -constexpr absl::string_view kTextMimeType = "text/plain"; -constexpr absl::string_view kAppPackageName = "com.google.android.youtube"; - -class AnalyticsRecorderTest : public ::testing::Test { - public: - AnalyticsRecorderTest() = default; - ~AnalyticsRecorderTest() override = default; - - MockEventLogger& event_logger() { return event_logger_; } - - AnalyticsRecorder analytics_recoder() { return analytics_recorder_; } - - private: - MockEventLogger event_logger_; - AnalyticsRecorder analytics_recorder_{/*vendor_id=*/0, &event_logger_}; -}; - -TEST_F(AnalyticsRecorderTest, NewEstablishConnection) { - ShareTarget share_target; - share_target.device_name = "share_target"; - share_target.type = ShareTargetType::kPhone; - - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ESTABLISH_CONNECTION); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.establish_connection().status(), - location::nearby::proto::sharing::EstablishConnectionStatus:: - CONNECTION_STATUS_SUCCESS); - EXPECT_EQ(log.establish_connection().session_id(), 1); - EXPECT_EQ(log.establish_connection().transfer_position(), 1); - EXPECT_EQ(log.establish_connection().concurrent_connections(), 1); - EXPECT_EQ(log.establish_connection().duration_millis(), 100); - EXPECT_EQ(log.establish_connection().share_target_info().os_type(), - location::nearby::proto::sharing::OSType::ANDROID); - EXPECT_EQ(log.establish_connection().referrer_name(), kAppPackageName); - }); - - analytics_recoder().NewEstablishConnection( - 1, - location::nearby::proto::sharing::EstablishConnectionStatus:: - CONNECTION_STATUS_SUCCESS, - share_target, 1, 1, 100, std::string(kAppPackageName)); -} - -TEST_F(AnalyticsRecorderTest, NewAcceptAgreements) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ACCEPT_AGREEMENTS); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewAcceptAgreements(); -} - -TEST_F(AnalyticsRecorderTest, NewDeclineAgreements) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DECLINE_AGREEMENTS); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewDeclineAgreements(); -} - -TEST_F(AnalyticsRecorderTest, NewAddContact) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ADD_CONTACT); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewAddContact(); -} - -TEST_F(AnalyticsRecorderTest, NewRemoveContact) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::REMOVE_CONTACT); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewRemoveContact(); -} - -TEST_F(AnalyticsRecorderTest, NewTapFeedback) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::TAP_FEEDBACK); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewTapFeedback(); -} - -TEST_F(AnalyticsRecorderTest, NewTapHelp) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::TAP_HELP); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewTapHelp(); -} - -TEST_F(AnalyticsRecorderTest, NewLaunchDeviceContactConsent) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::LAUNCH_CONSENT); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.launch_consent().status(), - location::nearby::proto::sharing::ConsentAcceptanceStatus:: - CONSENT_ACCEPTED); - }); - - analytics_recoder().NewLaunchDeviceContactConsent( - ::location::nearby::proto::sharing::ConsentAcceptanceStatus:: - CONSENT_ACCEPTED); -} - -TEST_F(AnalyticsRecorderTest, NewAdvertiseDevicePresenceEnd) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ADVERTISE_DEVICE_PRESENCE_END); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.advertise_device_presence_end().session_id(), 100); - }); - - analytics_recoder().NewAdvertiseDevicePresenceEnd(100); -} - -TEST_F(AnalyticsRecorderTest, NewAdvertiseDevicePresenceStart) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ADVERTISE_DEVICE_PRESENCE_START); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.advertise_device_presence_start().visibility(), - location::nearby::proto::sharing::Visibility::CONTACTS_ONLY); - EXPECT_EQ(log.advertise_device_presence_start().status(), - location::nearby::proto::sharing::SessionStatus:: - SUCCEEDED_SESSION_STATUS); - EXPECT_EQ(log.advertise_device_presence_start().data_usage(), - location::nearby::proto::sharing::DataUsage::OFFLINE); - EXPECT_EQ(log.advertise_device_presence_start().referrer_name(), - kAppPackageName); - EXPECT_EQ(log.advertise_device_presence_start().session_id(), 100); - }); - - analytics_recoder().NewAdvertiseDevicePresenceStart( - 100, DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, - location::nearby::proto::sharing::SessionStatus::SUCCEEDED_SESSION_STATUS, - DataUsage::OFFLINE_DATA_USAGE, std::string(kAppPackageName)); -} - -TEST_F(AnalyticsRecorderTest, NewDescribeAttachments) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DESCRIBE_ATTACHMENTS); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment_size(), - 5); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment(0) - .size_bytes(), - kTextBody.size()); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment(0) - .type(), - SharingLog::TextAttachment::UNKNOWN_TEXT_TYPE); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment(1) - .type(), - SharingLog::TextAttachment::PHONE_NUMBER); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment(2) - .type(), - SharingLog::TextAttachment::URL); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment(3) - .type(), - SharingLog::TextAttachment::ADDRESS); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment(4) - .type(), - SharingLog::TextAttachment::UNKNOWN_TEXT_TYPE); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment_size(), - 4); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment(0) - .size_bytes(), - 2); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment(0) - .type(), - SharingLog::FileAttachment::IMAGE); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment(1) - .type(), - SharingLog::FileAttachment::DOCUMENT); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment(2) - .type(), - SharingLog::FileAttachment::AUDIO); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment(3) - .type(), - SharingLog::FileAttachment::DOCUMENT); - }); - - std::unique_ptr attachments = - AttachmentContainer::Builder( - {TextAttachment(5, service::proto::TextMetadata::TEXT, - std::string(kTextBody), kTextBody.size()), - TextAttachment(6, service::proto::TextMetadata::PHONE_NUMBER, - std::string(kTextBody), kTextBody.size()), - TextAttachment(7, service::proto::TextMetadata::URL, - std::string(kTextBody), kTextBody.size()), - TextAttachment(8, service::proto::TextMetadata::ADDRESS, - std::string(kTextBody), kTextBody.size()), - TextAttachment(9, service::proto::TextMetadata::UNKNOWN, - std::string(kTextBody), kTextBody.size())}, - {FileAttachment(1, 2, std::string(kFileName), "", - service::proto::FileMetadata::IMAGE), - FileAttachment(2, 3, std::string(kFileDocumentName), - std::string(kFileMimeType), - service::proto::FileMetadata::DOCUMENT), - FileAttachment(3, 4, std::string(kFileName), "", - service::proto::FileMetadata::AUDIO), - FileAttachment(4, 5, std::string(kFileName), - std::string(kTextMimeType), - service::proto::FileMetadata::DOCUMENT)}, - {}) - .Build(); - - analytics_recoder().NewDescribeAttachments(*attachments); -} - -TEST_F(AnalyticsRecorderTest, EmptyDescribeAttachments) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DESCRIBE_ATTACHMENTS); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .text_attachment_size(), - 0); - EXPECT_EQ(log.describe_attachments() - .attachments_info() - .file_attachment_size(), - 0); - }); - - analytics_recoder().NewDescribeAttachments(AttachmentContainer()); -} - -TEST_F(AnalyticsRecorderTest, NewDiscoverShareTarget) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DISCOVER_SHARE_TARGET); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.discover_share_target().duration_since_scanning().nanos(), - (2100 % 1000) * 1000000); - EXPECT_EQ( - log.discover_share_target().duration_since_scanning().seconds(), - 2100 / 1000); - EXPECT_EQ( - log.discover_share_target() - .share_target_info() - .device_relationship(), - ::location::nearby::proto::sharing::DeviceRelationship::IS_CONTACT); - EXPECT_EQ(log.discover_share_target().share_target_info().device_type(), - ::location::nearby::proto::sharing::DeviceType::LAPTOP); - EXPECT_EQ(log.discover_share_target().share_target_info().os_type(), - ::location::nearby::proto::sharing::OSType::UNKNOWN_OS_TYPE); - EXPECT_EQ(log.discover_share_target().session_id(), 1); - EXPECT_EQ(log.discover_share_target().flow_id(), 100); - EXPECT_FALSE(log.discover_share_target().has_referrer_name()); - EXPECT_EQ( - log.discover_share_target().latency_since_activity_start_millis(), - 2); - }); - - ShareTarget share_target; - share_target.device_name = "share_target"; - share_target.type = ShareTargetType::kLaptop; - share_target.is_incoming = true; - share_target.is_known = true; - - analytics_recoder().NewDiscoverShareTarget(share_target, 1, 2100, 100, - std::nullopt, 2); -} - -TEST_F(AnalyticsRecorderTest, NewEnableNearbySharing) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ENABLE_NEARBY_SHARING); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.enable_nearby_sharing().status(), - location::nearby::proto::sharing::NearbySharingStatus::ON); - }); - - analytics_recoder().NewEnableNearbySharing( - ::location::nearby::proto::sharing::NearbySharingStatus::ON); -} - -TEST_F(AnalyticsRecorderTest, NewOpenReceivedAttachments) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::OPEN_RECEIVED_ATTACHMENTS); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.open_received_attachments() - .attachments_info() - .text_attachment_size(), - 0); - EXPECT_EQ(log.open_received_attachments() - .attachments_info() - .file_attachment_size(), - 0); - EXPECT_EQ(log.open_received_attachments().session_id(), 1); - }); - - analytics_recoder().NewOpenReceivedAttachments(AttachmentContainer(), 1); -} - -TEST_F(AnalyticsRecorderTest, NewProcessReceivedAttachmentsEnd) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), - EventType::PROCESS_RECEIVED_ATTACHMENTS_END); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.process_received_attachments_end().session_id(), 1); - EXPECT_EQ( - log.process_received_attachments_end().status(), - location::nearby::proto::sharing::ProcessReceivedAttachmentsStatus:: - PROCESSING_STATUS_COMPLETE_PROCESSING_ATTACHMENTS); - }); - - analytics_recoder().NewProcessReceivedAttachmentsEnd( - 1, location::nearby::proto::sharing::ProcessReceivedAttachmentsStatus:: - PROCESSING_STATUS_COMPLETE_PROCESSING_ATTACHMENTS); -} - -TEST_F(AnalyticsRecorderTest, NewReceiveAttachmentsEnd) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::RECEIVE_ATTACHMENTS_END); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.receive_attachments_end().session_id(), 1); - EXPECT_EQ(log.receive_attachments_end().received_bytes(), 2); - EXPECT_EQ( - log.receive_attachments_end().status(), - ::location::nearby::proto::sharing::AttachmentTransmissionStatus:: - COMPLETE_ATTACHMENT_TRANSMISSION_STATUS); - EXPECT_EQ(log.receive_attachments_end().referrer_name(), - kAppPackageName); - }); - - analytics_recoder().NewReceiveAttachmentsEnd( - 1, 2, - ::location::nearby::proto::sharing::AttachmentTransmissionStatus:: - COMPLETE_ATTACHMENT_TRANSMISSION_STATUS, - std::string(kAppPackageName)); -} - -TEST_F(AnalyticsRecorderTest, NewReceiveAttachmentsStart) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::RECEIVE_ATTACHMENTS_START); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.receive_attachments_start().session_id(), 1); - EXPECT_EQ(log.receive_attachments_start() - .attachments_info() - .file_attachment_size(), - 0); - }); - - analytics_recoder().NewReceiveAttachmentsStart(1, AttachmentContainer()); -} - -TEST_F(AnalyticsRecorderTest, NewReceiveFastInitialization) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::RECEIVE_FAST_INITIALIZATION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.receive_initialization() - .time_elapse_since_screen_unlock_millis(), - 1); - }); - - analytics_recoder().NewReceiveFastInitialization(1); -} - -TEST_F(AnalyticsRecorderTest, NewAcceptFastInitialization) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ACCEPT_FAST_INITIALIZATION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - }); - - analytics_recoder().NewAcceptFastInitialization(); -} - -TEST_F(AnalyticsRecorderTest, NewDismissFastInitialization) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DISMISS_FAST_INITIALIZATION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - }); - - analytics_recoder().NewDismissFastInitialization(); -} - -TEST_F(AnalyticsRecorderTest, NewReceiveIntroduction) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::RECEIVE_INTRODUCTION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.receive_introduction().session_id(), 1); - EXPECT_EQ(log.receive_introduction().share_target_info().os_type(), - ::location::nearby::proto::sharing::OSType::WINDOWS); - EXPECT_EQ(log.receive_introduction().share_target_info().device_type(), - ::location::nearby::proto::sharing::DeviceType::PHONE); - EXPECT_EQ(log.receive_introduction().referrer_name(), kAppPackageName); - }); - - ShareTarget share_target; - share_target.device_name = "share_target"; - share_target.type = ShareTargetType::kPhone; - analytics_recoder().NewReceiveIntroduction( - 1, share_target, std::string(kAppPackageName), OSType::WINDOWS); -} - -TEST_F(AnalyticsRecorderTest, NewRespondToIntroduction) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::RESPOND_TO_INTRODUCTION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.respond_introduction().session_id(), 1); - EXPECT_EQ(log.respond_introduction().action(), - ::location::nearby::proto::sharing::ResponseToIntroduction:: - ACCEPT_INTRODUCTION); - }); - - analytics_recoder().NewRespondToIntroduction( - ::location::nearby::proto::sharing::ResponseToIntroduction:: - ACCEPT_INTRODUCTION, - 1); -} - -TEST_F(AnalyticsRecorderTest, NewTapPrivacyNotification) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::TAP_PRIVACY_NOTIFICATION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - }); - - analytics_recoder().NewTapPrivacyNotification(); -} - -TEST_F(AnalyticsRecorderTest, NewDismissPrivacyNotification) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DISMISS_PRIVACY_NOTIFICATION); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - }); - - analytics_recoder().NewDismissPrivacyNotification(); -} - -TEST_F(AnalyticsRecorderTest, NewScanForShareTargetsEnd) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SCAN_FOR_SHARE_TARGETS_END); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.scan_for_share_targets_end().session_id(), 100); - }); - - analytics_recoder().NewScanForShareTargetsEnd(100); -} - -TEST_F(AnalyticsRecorderTest, NewScanForShareTargetsStart) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SCAN_FOR_SHARE_TARGETS_START); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.scan_for_share_targets_start().session_id(), 3); - EXPECT_EQ(log.scan_for_share_targets_start().status(), - ::location::nearby::proto::sharing::SessionStatus:: - FAILED_SESSION_STATUS); - EXPECT_EQ(log.scan_for_share_targets_start().flow_id(), 100); - EXPECT_EQ( - log.scan_for_share_targets_start().scan_type(), - ::location::nearby::proto::sharing::ScanType::FOREGROUND_SCAN); - EXPECT_FALSE(log.scan_for_share_targets_start().has_referrer_name()); - }); - - analytics_recoder().NewScanForShareTargetsStart( - 3, - ::location::nearby::proto::sharing::SessionStatus::FAILED_SESSION_STATUS, - AnalyticsInformation{SendSurfaceState::kForeground}, 100, std::nullopt); -} - -TEST_F(AnalyticsRecorderTest, NewSendAttachmentsEnd) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SEND_ATTACHMENTS_END); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.send_attachments_end().session_id(), 1); - EXPECT_EQ(log.send_attachments_end().sent_bytes(), 2); - EXPECT_EQ(log.send_attachments_end().share_target_info().os_type(), - ::location::nearby::proto::sharing::OSType::ANDROID); - EXPECT_EQ(log.send_attachments_end().share_target_info().device_type(), - ::location::nearby::proto::sharing::DeviceType::PHONE); - EXPECT_EQ(log.send_attachments_end().transfer_position(), 1); - EXPECT_EQ(log.send_attachments_end().concurrent_connections(), 2); - EXPECT_EQ(log.send_attachments_end().duration_millis(), 100); - EXPECT_EQ( - log.send_attachments_end().status(), - ::location::nearby::proto::sharing::AttachmentTransmissionStatus:: - COMPLETE_ATTACHMENT_TRANSMISSION_STATUS); - EXPECT_EQ(log.send_attachments_end().referrer_name(), kAppPackageName); - }); - - ShareTarget share_target; - share_target.device_name = "share_target"; - share_target.type = ShareTargetType::kPhone; - analytics_recoder().NewSendAttachmentsEnd( - 1, 2, share_target, - ::location::nearby::proto::sharing::AttachmentTransmissionStatus:: - COMPLETE_ATTACHMENT_TRANSMISSION_STATUS, - 1, 2, 100, std::string(kAppPackageName), - ::location::nearby::proto::sharing::ConnectionLayerStatus:: - CONNECTION_LAYER_STATUS_UNKNOWN, - OSType::UNKNOWN_OS_TYPE); -} - -TEST_F(AnalyticsRecorderTest, NewSendAttachmentsStart) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SEND_ATTACHMENTS_START); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.send_attachments_start().session_id(), 1); - EXPECT_EQ(log.send_attachments_start() - .attachments_info() - .file_attachment_size(), - 0); - EXPECT_EQ(log.send_attachments_start().transfer_position(), 100); - EXPECT_EQ(log.send_attachments_start().concurrent_connections(), 200); - EXPECT_EQ(log.send_attachments_start().advanced_protection_enabled(), - true); - EXPECT_EQ(log.send_attachments_start().advanced_protection_mismatch(), - true); - }); - - analytics_recoder().NewSendAttachmentsStart(1, AttachmentContainer(), 100, - 200, true, true); -} - -TEST_F(AnalyticsRecorderTest, NewSendFastInitialization) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SEND_FAST_INITIALIZATION); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - }); - - analytics_recoder().NewSendFastInitialization(); -} - -TEST_F(AnalyticsRecorderTest, NewSendStart) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SEND_START); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.send_start().session_id(), 123); - EXPECT_EQ(log.send_start().transfer_position(), 1); - EXPECT_EQ(log.send_start().concurrent_connections(), 2); - EXPECT_EQ(log.send_start().share_target_info().device_type(), - ::location::nearby::proto::sharing::DeviceType::LAPTOP); - EXPECT_EQ(log.send_start().share_target_info().os_type(), - ::location::nearby::proto::sharing::OSType::UNKNOWN_OS_TYPE); - }); - - ShareTarget share_target; - share_target.device_name = "share_target"; - share_target.type = ShareTargetType::kLaptop; - share_target.is_known = true; - share_target.is_incoming = true; - analytics_recoder().NewSendStart(123, 1, 2, share_target); -} - -TEST_F(AnalyticsRecorderTest, NewSendIntroductionWithRelationship) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SEND_INTRODUCTION); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.send_introduction().session_id(), 5); - EXPECT_EQ(log.send_introduction().share_target_info().device_type(), - ::location::nearby::proto::sharing::DeviceType::LAPTOP); - EXPECT_EQ(log.send_introduction().share_target_info().os_type(), - ::location::nearby::proto::sharing::OSType::MACOS); - EXPECT_EQ( - log.send_introduction().share_target_info().device_relationship(), - ::location::nearby::proto::sharing::DeviceRelationship::IS_CONTACT); - }); - - analytics_recoder().NewSendIntroduction( - ShareTargetType::kLaptop, 5, - ::location::nearby::proto::sharing::DeviceRelationship::IS_CONTACT, - OSType::MACOS); -} - -TEST_F(AnalyticsRecorderTest, NewSendIntroduction) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SEND_INTRODUCTION); - EXPECT_EQ(log.event_category(), EventCategory::SENDING_EVENT); - EXPECT_EQ(log.send_introduction().session_id(), 1); - EXPECT_EQ(log.send_introduction().transfer_position(), 2); - EXPECT_EQ(log.send_introduction().concurrent_connections(), 3); - EXPECT_EQ(log.send_introduction().share_target_info().device_type(), - ::location::nearby::proto::sharing::DeviceType::LAPTOP); - EXPECT_EQ(log.send_introduction().share_target_info().os_type(), - ::location::nearby::proto::sharing::OSType::UNKNOWN_OS_TYPE); - }); - - ShareTarget share_target; - share_target.device_name = "share_target"; - share_target.type = ShareTargetType::kLaptop; - analytics_recoder().NewSendIntroduction(1, share_target, 2, 3, - OSType::UNKNOWN_OS_TYPE); -} - -TEST_F(AnalyticsRecorderTest, NewSetVisibility) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SET_VISIBILITY); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.set_visibility().duration_millis(), 100); - EXPECT_EQ(log.set_visibility().source_visibility(), - ::location::nearby::proto::sharing::Visibility::EVERYONE); - EXPECT_EQ( - log.set_visibility().visibility(), - ::location::nearby::proto::sharing::Visibility::CONTACTS_ONLY); - }); - - analytics_recoder().NewSetVisibility( - DeviceVisibility::DEVICE_VISIBILITY_EVERYONE, - DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, 100); -} - -TEST_F(AnalyticsRecorderTest, NewDeviceSettings) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::DEVICE_SETTINGS); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.device_settings().device_name_size(), 10); - EXPECT_EQ(log.device_settings().visibility(), - ::location::nearby::proto::sharing::Visibility::EVERYONE); - EXPECT_EQ(log.device_settings().data_usage(), - ::location::nearby::proto::sharing::DataUsage::WIFI_ONLY); - EXPECT_EQ(log.device_settings().is_show_notification_enabled(), true); - }); - - AnalyticsDeviceSettings device_settings; - device_settings.device_name_size = 10; - device_settings.data_usage = DataUsage::WIFI_ONLY_DATA_USAGE; - device_settings.is_fast_init_notification_enabled = true; - device_settings.visibility = DeviceVisibility::DEVICE_VISIBILITY_EVERYONE; - analytics_recoder().NewDeviceSettings(device_settings); -} - -TEST_F(AnalyticsRecorderTest, NewSetDataUsage) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SET_DATA_USAGE); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.set_data_usage().preference(), - ::location::nearby::proto::sharing::DataUsage::OFFLINE); - EXPECT_EQ(log.set_data_usage().original_preference(), - ::location::nearby::proto::sharing::DataUsage::WIFI_ONLY); - }); - - analytics_recoder().NewSetDataUsage(DataUsage::WIFI_ONLY_DATA_USAGE, - DataUsage::OFFLINE_DATA_USAGE); -} - -TEST_F(AnalyticsRecorderTest, NewAddQuickSettingsTile) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::ADD_QUICK_SETTINGS_TILE); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewAddQuickSettingsTile(); -} - -TEST_F(AnalyticsRecorderTest, NewRemoveQuickSettingsTile) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::REMOVE_QUICK_SETTINGS_TILE); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewRemoveQuickSettingsTile(); -} - -TEST_F(AnalyticsRecorderTest, NewTapQuickSettingsTile) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::TAP_QUICK_SETTINGS_TILE); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - }); - - analytics_recoder().NewTapQuickSettingsTile(); -} - -TEST_F(AnalyticsRecorderTest, NewToggleShowNotification) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::TOGGLE_SHOW_NOTIFICATION); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ( - log.toggle_show_notification().previous_status(), - ::location::nearby::proto::sharing::ShowNotificationStatus::SHOW); - EXPECT_EQ(log.toggle_show_notification().current_status(), - ::location::nearby::proto::sharing::ShowNotificationStatus:: - NOT_SHOW); - }); - - analytics_recoder().NewToggleShowNotification( - ::location::nearby::proto::sharing::ShowNotificationStatus::SHOW, - ::location::nearby::proto::sharing::ShowNotificationStatus::NOT_SHOW); -} - -TEST_F(AnalyticsRecorderTest, NewSetDeviceName) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::SET_DEVICE_NAME); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.set_device_name().device_name_size(), 16); - }); - - analytics_recoder().NewSetDeviceName(16); -} - -TEST_F(AnalyticsRecorderTest, NewRequestSettingPermissions) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::REQUEST_SETTING_PERMISSIONS); - EXPECT_EQ(log.event_category(), EventCategory::SETTINGS_EVENT); - EXPECT_EQ(log.request_setting_permissions().permission_type(), - ::location::nearby::proto::sharing::PermissionRequestType:: - PERMISSION_BLUETOOTH); - EXPECT_EQ( - log.request_setting_permissions().permission_request_result(), - ::location::nearby::proto::sharing::PermissionRequestResult:: - PERMISSION_GRANTED); - }); - - analytics_recoder().NewRequestSettingPermissions( - ::location::nearby::proto::sharing::PermissionRequestType:: - PERMISSION_BLUETOOTH, - ::location::nearby::proto::sharing::PermissionRequestResult:: - PERMISSION_GRANTED); -} - -TEST_F(AnalyticsRecorderTest, NewInstallAPKStatus) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::INSTALL_APK); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ(log.install_apk_status().status(0), - ::location::nearby::proto::sharing::InstallAPKStatus:: - SUCCESS_INSTALLATION); - EXPECT_EQ( - log.install_apk_status().source(0), - ::location::nearby::proto::sharing::ApkSource::APK_FROM_SD_CARD); - }); - - analytics_recoder().NewInstallAPKStatus( - ::location::nearby::proto::sharing::InstallAPKStatus:: - SUCCESS_INSTALLATION, - ::location::nearby::proto::sharing::ApkSource::APK_FROM_SD_CARD); -} - -TEST_F(AnalyticsRecorderTest, NewVerifyAPKStatus) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::VERIFY_APK); - EXPECT_EQ(log.event_category(), EventCategory::RECEIVING_EVENT); - EXPECT_EQ( - log.verify_apk_status().status(0), - ::location::nearby::proto::sharing::VerifyAPKStatus::INSTALLABLE); - EXPECT_EQ( - log.verify_apk_status().source(0), - ::location::nearby::proto::sharing::ApkSource::APK_FROM_SD_CARD); - }); - - analytics_recoder().NewVerifyAPKStatus( - ::location::nearby::proto::sharing::VerifyAPKStatus::INSTALLABLE, - ::location::nearby::proto::sharing::ApkSource::APK_FROM_SD_CARD); -} - -TEST_F(AnalyticsRecorderTest, NewRpcCallStatus) { - EXPECT_CALL(event_logger(), Log(An())) - .WillOnce([](const SharingLog& log) { - EXPECT_EQ(log.event_type(), EventType::RPC_CALL_STATUS); - EXPECT_EQ(log.event_category(), EventCategory::RPC_EVENT); - EXPECT_EQ(log.rpc_call_status().rpc_name(), "service.rpc_name"); - EXPECT_EQ(log.rpc_call_status().direction(), - SharingLog::RpcCallStatus::OUTGOING); - EXPECT_EQ(log.rpc_call_status().error_code(), 123); - EXPECT_EQ(log.rpc_call_status().latency_millis(), 456); - }); - - analytics_recoder().NewRpcCallStatus( - "service.rpc_name", SharingLog::RpcCallStatus::OUTGOING, 123, - absl::Milliseconds(456)); -} - -TEST_F(AnalyticsRecorderTest, GenerateID) { - int64_t id = analytics_recoder().GenerateNextId(); - EXPECT_GT(id, 0); - int64_t id2 = analytics_recoder().GenerateNextId(); - EXPECT_NE(id2, id); -} - -} // namespace -} // namespace nearby::sharing::analytics diff --git a/sharing/certificates/nearby_share_certificate_manager_impl_test.cc b/sharing/certificates/nearby_share_certificate_manager_impl_test.cc index 796c91e0..ebd994a6 100644 --- a/sharing/certificates/nearby_share_certificate_manager_impl_test.cc +++ b/sharing/certificates/nearby_share_certificate_manager_impl_test.cc @@ -27,6 +27,8 @@ #include "google/nearby/identity/v1/resources.pb.h" #include "google/nearby/identity/v1/rpcs.pb.h" +#include "location/nearby/sharing/lib/account/account_manager.h" +#include "location/nearby/sharing/lib/account/fake_account_manager.h" #include "location/nearby/sharing/lib/rpc/fake_nearby_share_client.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" @@ -37,9 +39,8 @@ #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/span.h" -#include "internal/platform/implementation/account_manager.h" +#include "internal/flags/nearby_flags.h" #include "internal/platform/mac_address.h" -#include "internal/test/fake_account_manager.h" #include "sharing/certificates/constants.h" #include "sharing/certificates/fake_nearby_share_certificate_storage.h" #include "sharing/certificates/nearby_share_certificate_manager.h" @@ -48,6 +49,7 @@ #include "sharing/certificates/nearby_share_encrypted_metadata_key.h" #include "sharing/certificates/nearby_share_private_certificate.h" #include "sharing/certificates/test_util.h" +#include "sharing/flags/generated/nearby_sharing_feature_flags.h" #include "sharing/internal/api/mock_sharing_platform.h" #include "sharing/internal/public/pref_names.h" #include "sharing/internal/test/fake_bluetooth_adapter.h" @@ -62,16 +64,18 @@ #include "sharing/scheduling/fake_nearby_share_scheduler_factory.h" #include "sharing/scheduling/nearby_share_scheduler_factory.h" -namespace nearby { -namespace sharing { +namespace nearby::sharing { namespace { -using ::google::nearby::identity::v1::AccountInfo; using ::google::nearby::identity::v1::Device; using ::google::nearby::identity::v1::GetAccountInfoResponse; using ::google::nearby::identity::v1::PublishDeviceRequest; using ::google::nearby::identity::v1::PublishDeviceResponse; using ::google::nearby::identity::v1::QuerySharedCredentialsRequest; using ::google::nearby::identity::v1::QuerySharedCredentialsResponse; +using ::google::nearby::identity::v1:: + QuerySharedCredentialsWithBindingIdsRequest; +using ::google::nearby::identity::v1:: + QuerySharedCredentialsWithBindingIdsResponse; using ::nearby::sharing::proto::DeviceVisibility; using ::nearby::sharing::proto::PublicCertificate; using ::testing::Not; @@ -102,6 +106,7 @@ class NearbyShareCertificateManagerImplTest ~NearbyShareCertificateManagerImplTest() override = default; void SetUp() override { + NearbyFlags::GetInstance().ResetOverridedValues(); ON_CALL(mock_sharing_platform_, GetPreferenceManager) .WillByDefault(ReturnRef(preference_manager_)); ON_CALL(mock_sharing_platform_, GetAccountManager) @@ -306,7 +311,7 @@ class NearbyShareCertificateManagerImplTest std::max(max_not_after_self_share, cert.not_after()); break; default: - DCHECK(false); + FAIL() << "Unexpected visibility: " << cert.visibility(); break; } @@ -425,6 +430,78 @@ class NearbyShareCertificateManagerImplTest return response; } + void QuerySharedCredentialsWithBindingIdsFlow( + size_t num_pages, DownloadPublicCertificatesResult result) { + size_t prev_num_results = download_scheduler_->handled_results().size(); + cert_store_->SetPublicCertificateIds(kPublicCertificateIds); + + size_t initial_num_notifications = + num_public_certs_downloaded_notifications_; + size_t initial_num_public_cert_exp_reschedules = + public_cert_exp_scheduler_->num_reschedule_calls(); + + std::vector> + responses; + std::string page_token; + for (size_t page_number = 0; page_number < num_pages; ++page_number) { + bool last_page = page_number == num_pages - 1; + if (last_page && result == DownloadPublicCertificatesResult::kHttpError) { + responses.push_back(absl::InternalError("")); + break; + } + page_token = last_page ? std::string() + : absl::StrCat(kPageTokenPrefix, page_number); + responses.push_back(BuildQuerySharedCredentialsWithBindingIdsResponse( + page_number, page_token)); + } + + identity_client_.SetQuerySharedCredentialsWithBindingIdsResponses( + responses); + cert_store_->SetAddPublicCertificatesResult( + result != DownloadPublicCertificatesResult::kStorageError); + download_scheduler_->InvokeRequestCallback(); + Sync(); + + std::vector requests = + identity_client_.query_shared_credentials_with_binding_ids_requests(); + EXPECT_EQ(requests.size(), num_pages); + EXPECT_EQ(requests.back().name(), absl::StrCat("devices/", kDeviceId)); + ASSERT_EQ(download_scheduler_->handled_results().size(), + prev_num_results + 1); + + bool success = result == DownloadPublicCertificatesResult::kSuccess; + EXPECT_EQ(download_scheduler_->handled_results().back(), success); + EXPECT_EQ(num_public_certs_downloaded_notifications_, + initial_num_notifications + (success ? 1u : 0u)); + EXPECT_EQ(public_cert_exp_scheduler_->num_reschedule_calls(), + initial_num_public_cert_exp_reschedules + (success ? 1u : 0u)); + } + + QuerySharedCredentialsWithBindingIdsResponse + BuildQuerySharedCredentialsWithBindingIdsResponse( + size_t page_number, absl::string_view page_token) { + QuerySharedCredentialsWithBindingIdsResponse response; + int i = 0; + for (auto public_certificate : public_certificates_) { + auto* shared_credential = response.add_shared_credentials(); + shared_credential->set_id(page_number * 100 + i); + if (i % 2 == 0) { + shared_credential->set_data_type( + google::nearby::identity::v1::SharedCredential:: + DATA_TYPE_PUBLIC_CERTIFICATE); + } else { + shared_credential->set_data_type( + google::nearby::identity::v1::SharedCredential:: + DATA_TYPE_SHARED_CREDENTIAL); + } + *shared_credential->mutable_data() = + public_certificate.SerializeAsString(); + i++; + } + response.set_next_page_token(page_token); + return response; + } + void CheckStorageAddCertificates( const FakeNearbyShareCertificateStorage::AddPublicCertificatesCall& add_cert_call) { @@ -702,6 +779,24 @@ TEST_F(NearbyShareCertificateManagerImplTest, /*num_pages=*/2, DownloadPublicCertificatesResult::kHttpError)); } +TEST_F(NearbyShareCertificateManagerImplTest, + QuerySharedCredentialsWithBindingIdsSuccess) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_sharing_feature::kEnableFileSync, true); + Initialize(); + ASSERT_NO_FATAL_FAILURE(QuerySharedCredentialsWithBindingIdsFlow( + /*num_pages=*/2, DownloadPublicCertificatesResult::kSuccess)); +} + +TEST_F(NearbyShareCertificateManagerImplTest, + QuerySharedCredentialsWithBindingIdsRPCFailure) { + NearbyFlags::GetInstance().OverrideBoolFlagValue( + config_package_nearby::nearby_sharing_feature::kEnableFileSync, true); + Initialize(); + ASSERT_NO_FATAL_FAILURE(QuerySharedCredentialsWithBindingIdsFlow( + /*num_pages=*/2, DownloadPublicCertificatesResult::kHttpError)); +} + TEST_F(NearbyShareCertificateManagerImplTest, ClearPublicCertificates) { Initialize(); cert_manager_->ClearPublicCertificates([&](bool result) {}); @@ -958,7 +1053,7 @@ TEST_F(NearbyShareCertificateManagerImplTest, Initialize(); GetAccountInfoResponse response; response.mutable_account_info()->mutable_capabilities()->Add( - AccountInfo::CAPABILITY_TITANIUM); + google::nearby::identity::v1::AccountInfo::CAPABILITY_TITANIUM); identity_client_.SetGetAccountInfoResponse(response); account_info_update_scheduler_->InvokeRequestCallback(); @@ -990,7 +1085,7 @@ TEST_F(NearbyShareCertificateManagerImplTest, preference_manager_.SetBoolean(PrefNames::kAdvancedProtectionEnabled, true); GetAccountInfoResponse response; response.mutable_account_info()->mutable_capabilities()->Add( - AccountInfo::CAPABILITY_UNSPECIFIED); + google::nearby::identity::v1::AccountInfo::CAPABILITY_UNSPECIFIED); identity_client_.SetGetAccountInfoResponse(response); account_info_update_scheduler_->InvokeRequestCallback(); @@ -1015,5 +1110,4 @@ TEST_F(NearbyShareCertificateManagerImplTest, PrefNames::kAdvancedProtectionEnabled, /*default_value=*/false)); } -} // namespace sharing -} // namespace nearby +} // namespace nearby::sharing diff --git a/sharing/common/nearby_share_prefs.cc b/sharing/common/nearby_share_prefs.cc index 279b352b..9d988ba5 100644 --- a/sharing/common/nearby_share_prefs.cc +++ b/sharing/common/nearby_share_prefs.cc @@ -67,7 +67,6 @@ void RegisterNearbySharingPrefs(PreferenceManager& preference_manager, preference_manager.Remove(PrefNames::kUsers); preference_manager.SetBoolean(PrefNames::kAdvancedProtectionEnabled, false); - preference_manager.RemoveAllSyncConfigs(); preference_manager.RemoveAllBindingConfigs(); } diff --git a/sharing/contacts/fake_nearby_share_contact_manager.h b/sharing/contacts/fake_nearby_share_contact_manager.h deleted file mode 100644 index d52d0820..00000000 --- a/sharing/contacts/fake_nearby_share_contact_manager.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2021-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. -// 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_SHARING_CONTACTS_FAKE_NEARBY_SHARE_CONTACT_MANAGER_H_ -#define THIRD_PARTY_NEARBY_SHARING_CONTACTS_FAKE_NEARBY_SHARE_CONTACT_MANAGER_H_ - -#include "sharing/contacts/nearby_share_contact_manager.h" - -namespace nearby { -namespace sharing { - -// A fake implementation of NearbyShareContactManager. -class FakeNearbyShareContactManager : public NearbyShareContactManager { - public: - FakeNearbyShareContactManager() = default; - ~FakeNearbyShareContactManager() override = default; - - private: - void GetContacts(ContactsCallback callback) override {}; -}; - -} // namespace sharing -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_SHARING_CONTACTS_FAKE_NEARBY_SHARE_CONTACT_MANAGER_H_ diff --git a/sharing/contacts/nearby_share_contact_manager.h b/sharing/contacts/nearby_share_contact_manager.h deleted file mode 100644 index 81bf5f17..00000000 --- a/sharing/contacts/nearby_share_contact_manager.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2021-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. -// 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_SHARING_CONTACTS_NEARBY_SHARE_CONTACT_MANAGER_H_ -#define THIRD_PARTY_NEARBY_SHARING_CONTACTS_NEARBY_SHARE_CONTACT_MANAGER_H_ - -#include - -#include - -#include "absl/functional/any_invocable.h" -#include "absl/status/statusor.h" -#include "sharing/proto/rpc_resources.pb.h" - -namespace nearby { -namespace sharing { - -// The Nearby Share contacts manager retrieves the user's contact list from the -// server. -class NearbyShareContactManager { - public: - using ContactsCallback = absl::AnyInvocable< - void(absl::StatusOr>, - uint32_t num_unreachable_contacts_filtered_out) &&>; - - virtual ~NearbyShareContactManager() = default; - - // Retrieves the user's contact list from the server. - virtual void GetContacts(ContactsCallback callback) = 0; -}; - -} // namespace sharing -} // namespace nearby - -#endif // THIRD_PARTY_NEARBY_SHARING_CONTACTS_NEARBY_SHARE_CONTACT_MANAGER_H_ diff --git a/sharing/contacts/nearby_share_contact_manager_impl_test.cc b/sharing/contacts/nearby_share_contact_manager_impl_test.cc deleted file mode 100644 index b2c7da8f..00000000 --- a/sharing/contacts/nearby_share_contact_manager_impl_test.cc +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 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. -// 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 "sharing/contacts/nearby_share_contact_manager_impl.h" - -#include -#include - -#include -#include -#include - -#include "location/nearby/sharing/lib/rpc/fake_nearby_share_client.h" -#include "gtest/gtest.h" -#include "absl/time/time.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/test/fake_account_manager.h" -#include "sharing/internal/test/fake_context.h" -#include "sharing/local_device_data/fake_nearby_share_local_device_data_manager.h" -#include "sharing/proto/contact_rpc.pb.h" -#include "sharing/proto/rpc_resources.pb.h" - -namespace nearby::sharing { -namespace { - -using ::nearby::sharing::proto::ContactRecord; - -constexpr char kTestDefaultDeviceName[] = "Josh's Chromebook"; -constexpr char kTestProfileUserName[] = "test@google.com"; -constexpr char kTestAccountId[] = "test_account_id"; - -class NearbyShareContactManagerImplTest - : public ::testing::Test { - protected: - struct ContactsDownloadedNotification { - std::vector contacts; - uint32_t num_unreachable_contacts_filtered_out; - }; - struct ContactsUploadedNotification { - bool did_contacts_change_since_last_upload; - }; - - NearbyShareContactManagerImplTest() - : local_device_data_manager_(kTestDefaultDeviceName) {} - - ~NearbyShareContactManagerImplTest() override = default; - - void SetUp() override { - AccountManager::Account account; - account.id = kTestAccountId; - account.email = kTestProfileUserName; - fake_account_manager_.SetAccount(account); - - manager_ = std::make_unique( - &fake_context_, fake_account_manager_, &nearby_client_); - } - - void TearDown() override { - manager_.reset(); - } - - void Sync() { - EXPECT_TRUE(fake_context_.last_sequenced_task_runner()->SyncWithTimeout( - absl::Milliseconds(1000))); - } - - std::vector& - contacts_downloaded_notifications() { - return contacts_downloaded_notifications_; - } - - FakeContext& fake_context() { return fake_context_; } - - private: - FakeAccountManager fake_account_manager_; - FakeContext fake_context_; - std::vector - contacts_downloaded_notifications_; - std::vector contacts_uploaded_notifications_; - FakeNearbyShareClient nearby_client_; - FakeNearbyShareLocalDeviceDataManager local_device_data_manager_; - std::unique_ptr account_manager_; - std::unique_ptr manager_; -}; - -} // namespace -} // namespace nearby::sharing diff --git a/sharing/fake_nearby_sharing_service.cc b/sharing/fake_nearby_sharing_service.cc index 2fcb7932..e3c90021 100644 --- a/sharing/fake_nearby_sharing_service.cc +++ b/sharing/fake_nearby_sharing_service.cc @@ -18,13 +18,22 @@ #include #include #include +#include +#include "location/nearby/sharing/lib/sync/sync_manager.h" +#include "absl/functional/any_invocable.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "internal/base/file_path.h" #include "internal/base/observer_list.h" +#include "internal/platform/clock.h" #include "sharing/advertisement.h" #include "sharing/attachment_container.h" -#include "sharing/local_device_data/nearby_share_local_device_data_manager.h" +#include "sharing/certificates/nearby_share_certificate_manager.h" #include "sharing/nearby_sharing_service.h" #include "sharing/nearby_sharing_settings.h" +#include "sharing/outgoing_share_session.h" +#include "sharing/outgoing_targets_manager.h" #include "sharing/share_target.h" #include "sharing/share_target_discovered_callback.h" #include "sharing/transfer_metadata.h" @@ -34,6 +43,22 @@ namespace nearby { namespace sharing { +FakeNearbySharingService::FakeNearbySharingService() + : service_thread_(&clock_, /*count=*/1), + analytics_recorder_(/*vendor_id=*/0, /*event_logger=*/nullptr), + sync_manager_(std::make_unique(&identity_rpc_client_, + &preference_manager_)), + outgoing_targets_manager_(std::make_unique( + &clock_, &service_thread_, &connections_manager_, + &analytics_recorder_, + [this](const ShareTarget& target) { + FireShareTargetDiscovered(target); + }, + [this](const ShareTarget& target) { FireShareTargetUpdated(target); }, + [this](const ShareTarget& target) { FireShareTargetLost(target); }, + /*transfer_update_callback=*/ + [](OutgoingShareSession&, const TransferMetadata&) {})) {} + void FakeNearbySharingService::AddObserver(Observer* observer) { observers_.AddObserver(observer); } @@ -54,7 +79,7 @@ void FakeNearbySharingService::RegisterSendSurface( TransferUpdateCallback* transfer_callback, ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state, Advertisement::BlockedVendorId blocked_vendor_id, bool disable_wifi_hotspot, - std::function status_codes_callback) { + absl::AnyInvocable status_codes_callback) { if (state == SendSurfaceState::kForeground) { foreground_send_surface_map_.insert( {transfer_callback, @@ -73,7 +98,7 @@ void FakeNearbySharingService::RegisterSendSurface( // Unregisters the current send surface. void FakeNearbySharingService::UnregisterSendSurface( TransferUpdateCallback* transfer_callback, - std::function status_codes_callback) { + absl::AnyInvocable status_codes_callback) { foreground_send_surface_map_.erase(transfer_callback); background_send_surface_map_.erase(transfer_callback); @@ -84,7 +109,7 @@ void FakeNearbySharingService::UnregisterSendSurface( void FakeNearbySharingService::RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, Advertisement::BlockedVendorId vendor_id, - std::function status_codes_callback) { + absl::AnyInvocable status_codes_callback) { if (state == ReceiveSurfaceState::kForeground) { foreground_receive_transfer_callbacks_.AddObserver(transfer_callback); } else { @@ -97,7 +122,7 @@ void FakeNearbySharingService::RegisterReceiveSurface( // Unregisters the current receive surface. void FakeNearbySharingService::UnregisterReceiveSurface( TransferUpdateCallback* transfer_callback, - std::function status_codes_callback) { + absl::AnyInvocable status_codes_callback) { foreground_receive_transfer_callbacks_.RemoveObserver(transfer_callback); background_receive_transfer_callbacks_.RemoveObserver(transfer_callback); status_codes_callback(StatusCodes::kOk); @@ -105,7 +130,7 @@ void FakeNearbySharingService::UnregisterReceiveSurface( // Unregisters all foreground receive surfaces. void FakeNearbySharingService::ClearForegroundReceiveSurfaces( - std::function status_codes_callback) { + absl::AnyInvocable status_codes_callback) { status_codes_callback(StatusCodes::kOk); } @@ -144,19 +169,18 @@ void FakeNearbySharingService::Cancel( status_codes_callback(StatusCodes::kOk); } +void FakeNearbySharingService::InitiatePairing( + int64_t share_target_id, service::proto::BindingRequest::Type binding_type, + absl::AnyInvocable + status_codes_callback) { + initiate_pairing_callbacks_[share_target_id] = + std::move(status_codes_callback); +} + std::string FakeNearbySharingService::Dump() const { return ""; } NearbyShareSettings* FakeNearbySharingService::GetSettings() { return nullptr; } -NearbyShareLocalDeviceDataManager* -FakeNearbySharingService::GetLocalDeviceDataManager() { - return nullptr; -} - -NearbyShareContactManager* FakeNearbySharingService::GetContactManager() { - return nullptr; -} - NearbyShareCertificateManager* FakeNearbySharingService::GetCertificateManager() { return nullptr; @@ -166,6 +190,14 @@ AccountManager* FakeNearbySharingService::GetAccountManager() { return nullptr; } +Clock& FakeNearbySharingService::GetClock() { return clock_; } + +SyncManager& FakeNearbySharingService::sync_manager() { return *sync_manager_; } + +OutgoingTargetsManager& FakeNearbySharingService::outgoing_targets_manager() { + return *outgoing_targets_manager_; +} + void FakeNearbySharingService::FireHighVisibilityChangeRequested() { for (auto& observer : observers_.GetObservers()) { observer->OnHighVisibilityChangeRequested(); @@ -229,29 +261,53 @@ void FakeNearbySharingService::FireReceiveTransferUpdate( // Fire discovery events. void FakeNearbySharingService::FireShareTargetDiscovered( - SendSurfaceState state, ShareTarget share_target) { - if (state == SendSurfaceState::kForeground) { - for (auto& entry : foreground_send_surface_map_) { - entry.second.OnShareTargetDiscovered(share_target); - } - } else { - for (auto& entry : background_send_surface_map_) { - entry.second.OnShareTargetDiscovered(share_target); - } + ShareTarget share_target) { + for (auto& entry : foreground_send_surface_map_) { + entry.second.OnShareTargetDiscovered(share_target); + } + for (auto& entry : background_send_surface_map_) { + entry.second.OnShareTargetDiscovered(share_target); } } -void FakeNearbySharingService::FireShareTargetLost(SendSurfaceState state, - ShareTarget share_target) { - if (state == SendSurfaceState::kForeground) { - for (auto& entry : foreground_send_surface_map_) { - entry.second.OnShareTargetLost(share_target); - } - } else { - for (auto& entry : background_send_surface_map_) { - entry.second.OnShareTargetLost(share_target); - } +void FakeNearbySharingService::FireShareTargetUpdated( + ShareTarget share_target) { + for (auto& entry : foreground_send_surface_map_) { + entry.second.OnShareTargetUpdated(share_target); } + for (auto& entry : background_send_surface_map_) { + entry.second.OnShareTargetUpdated(share_target); + } +} + +void FakeNearbySharingService::FireShareTargetLost(ShareTarget share_target) { + for (auto& entry : foreground_send_surface_map_) { + entry.second.OnShareTargetLost(share_target); + } + for (auto& entry : background_send_surface_map_) { + entry.second.OnShareTargetLost(share_target); + } +} + +void FakeNearbySharingService::FireInitiatePairingResult( + int64_t share_target_id, StatusCodes status) { + auto it = initiate_pairing_callbacks_.find(share_target_id); + if (it == initiate_pairing_callbacks_.end()) { + return; + } + auto callback = std::move(it->second); + initiate_pairing_callbacks_.erase(it); + std::move(callback)(status); +} + +void FakeNearbySharingService::UpdateBackupSavePath( + absl::string_view binding_id, absl::string_view save_path, + absl::AnyInvocable + status_codes_callback) { + absl::StatusOr status = + sync_manager_->UpdateSyncBindingDestinationDirectory(binding_id, + FilePath(save_path)); + status_codes_callback(status.ok() ? StatusCodes::kOk : StatusCodes::kError); } } // namespace sharing diff --git a/sharing/fake_nearby_sharing_service.h b/sharing/fake_nearby_sharing_service.h index 9aaf0376..e68644af 100644 --- a/sharing/fake_nearby_sharing_service.h +++ b/sharing/fake_nearby_sharing_service.h @@ -20,13 +20,27 @@ #include #include +#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h" +#include "location/nearby/sharing/lib/rpc/fake_nearby_share_client.h" +#include "location/nearby/sharing/lib/rpc/sharing_rpc_client.h" +#include "location/nearby/sharing/lib/sync/sync_manager.h" #include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "internal/base/observer_list.h" +#include "internal/platform/clock.h" +#include "internal/test/fake_clock.h" +#include "internal/test/fake_task_runner.h" #include "sharing/advertisement.h" #include "sharing/attachment_container.h" -#include "sharing/local_device_data/nearby_share_local_device_data_manager.h" +#include "sharing/certificates/nearby_share_certificate_manager.h" +#include "sharing/fake_nearby_connections_manager.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/test/fake_preference_manager.h" #include "sharing/nearby_sharing_service.h" #include "sharing/nearby_sharing_settings.h" +#include "sharing/outgoing_targets_manager.h" #include "sharing/share_target.h" #include "sharing/share_target_discovered_callback.h" #include "sharing/transfer_metadata.h" @@ -38,6 +52,7 @@ namespace sharing { class FakeNearbySharingService : public NearbySharingService { public: + FakeNearbySharingService(); ~FakeNearbySharingService() override = default; void AddObserver(Observer* observer) override; @@ -54,27 +69,27 @@ class FakeNearbySharingService : public NearbySharingService { ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state, Advertisement::BlockedVendorId blocked_vendor_id, bool disable_wifi_hotspot, - std::function status_codes_callback) override; + absl::AnyInvocable status_codes_callback) override; // Unregisters the current send surface. void UnregisterSendSurface( TransferUpdateCallback* transfer_callback, - std::function status_codes_callback) override; + absl::AnyInvocable status_codes_callback) override; // Registers a receiver surface for handling payload transfer status. void RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, Advertisement::BlockedVendorId vendor_id, - std::function status_codes_callback) override; + absl::AnyInvocable status_codes_callback) override; // Unregisters the current receive surface. void UnregisterReceiveSurface( TransferUpdateCallback* transfer_callback, - std::function status_codes_callback) override; + absl::AnyInvocable status_codes_callback) override; // Unregisters all foreground receive surfaces. void ClearForegroundReceiveSurfaces( - std::function status_codes_callback) override; + absl::AnyInvocable status_codes_callback) override; // Returns true if there is an ongoing file transfer. bool IsTransferring() const override; @@ -103,13 +118,49 @@ class FakeNearbySharingService : public NearbySharingService { std::function status_codes_callback) override; + void InitiatePairing( + int64_t share_target_id, + service::proto::BindingRequest::Type binding_type, + absl::AnyInvocable + status_codes_callback) override; + std::string Dump() const override; + bool IsBluetoothPresent() const override { return true; } + bool IsBluetoothPowered() const override { return true; } + bool IsExtendedAdvertisingSupported() const override { return true; } + bool IsLanConnected() const override { return true; } + std::string GetQrCodeUrl() const override { return ""; } + void SetVisibility( + proto::DeviceVisibility visibility, absl::Duration expiration, + absl::AnyInvocable callback) override {} + void UpdateFilePathsInProgress(bool update_file_paths) override {} NearbyShareSettings* GetSettings() override; - NearbyShareLocalDeviceDataManager* GetLocalDeviceDataManager() override; - NearbyShareContactManager* GetContactManager() override; NearbyShareCertificateManager* GetCertificateManager() override; AccountManager* GetAccountManager() override; + Clock& GetClock() override; + void SetAlternateServiceUuidForDiscovery( + uint16_t alternate_service_uuid) override {} + SyncManager& sync_manager() override; + OutgoingTargetsManager& outgoing_targets_manager() override; + void UpdateBackupSavePath( + absl::string_view binding_id, absl::string_view save_path, + absl::AnyInvocable + status_codes_callback) override; + + nearby::sharing::api::IdentityRpcClient& fake_identity_rpc_client() { + return identity_rpc_client_; + } + nearby::sharing::api::PreferenceManager& fake_preference_manager() { + return preference_manager_; + } + FakeNearbyConnectionsManager& fake_nearby_connections_manager() { + return connections_manager_; + } + FakeTaskRunner& fake_task_runner() { return service_thread_; } + analytics::AnalyticsRecorderImpl& analytics_recorder() { + return analytics_recorder_; + } // Fake methods to support test scenarios. @@ -130,9 +181,10 @@ class FakeNearbySharingService : public NearbySharingService { TransferMetadata transfer_metadata); // Fire discovery events. - void FireShareTargetDiscovered(SendSurfaceState state, - ShareTarget share_target); - void FireShareTargetLost(SendSurfaceState state, ShareTarget share_target); + void FireShareTargetDiscovered(ShareTarget share_target); + void FireShareTargetUpdated(ShareTarget share_target); + void FireShareTargetLost(ShareTarget share_target); + void FireInitiatePairingResult(int64_t share_target_id, StatusCodes status); private: ObserverList observers_; @@ -147,6 +199,17 @@ class FakeNearbySharingService : public NearbySharingService { background_send_surface_map_; ObserverList foreground_receive_transfer_callbacks_; ObserverList background_receive_transfer_callbacks_; + FakeClock clock_; + FakeTaskRunner service_thread_; + FakeNearbyConnectionsManager connections_manager_; + analytics::AnalyticsRecorderImpl analytics_recorder_; + FakePreferenceManager preference_manager_; + FakeNearbyIdentityClient identity_rpc_client_; + std::unique_ptr sync_manager_; + std::unique_ptr outgoing_targets_manager_; + absl::flat_hash_map> + initiate_pairing_callbacks_; }; } // namespace sharing diff --git a/sharing/flags/generated/README.md b/sharing/flags/generated/README.md deleted file mode 100644 index a7682807..00000000 --- a/sharing/flags/generated/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Feature flags generation - -This directory contains the generated Nearby Share feature flags definition -file. - -## Adding flags - -New flags need to be added to google3/googledata/experiments/mobile/nearby/features/nearby_sharing_feature.gcl. - -To generate code for the new flags, run: - -``` -blaze build //third_party/nearby/sharing/flags:nearby_sharing_feature_flags_cpp_consts -``` - -The creates the generated file in *blaze-genfiles/third_party/nearby/sharing/flags/nearby_sharing_feature_flags.h*. Copy this file to google3/third_party/nearby/sharing/flags/generated/nearby_sharing_feature_flags.h -and include in your CL for submission. diff --git a/sharing/flags/generated/nearby_sharing_feature_flags.h b/sharing/flags/generated/nearby_sharing_feature_flags.h index 71b1295a..25beaeb5 100755 --- a/sharing/flags/generated/nearby_sharing_feature_flags.h +++ b/sharing/flags/generated/nearby_sharing_feature_flags.h @@ -47,9 +47,6 @@ constexpr auto kEnableMediumWifiLan = // Enable/disable retry/resume transfer for partial files. constexpr auto kEnableRetryResumeTransfer = flags::Flag(kConfigPackage, "45411589", false); -// Enable/disable self share UI in Nearby Share -constexpr auto kEnableSelfShareUi = - flags::Flag(kConfigPackage, "45418908", false); // Enable/disable sending desktop events constexpr auto kEnableSendingDesktopEvents = flags::Flag(kConfigPackage, "45459748", false); @@ -83,6 +80,9 @@ constexpr auto kUpdateTrack = // Timeout between displays of the conflict banner. constexpr auto kConflictBannerTimeout = flags::Flag(kConfigPackage, "45668886", 604800); +// When true, enables the backup feature. +constexpr auto kEnableBackup = + flags::Flag(kConfigPackage, "45776229", false); // Enable a persistent BETA label. constexpr auto kEnableBetaLabel = flags::Flag(kConfigPackage, "45662570", true); @@ -100,7 +100,7 @@ constexpr auto kEnableNativeNotifications = flags::Flag(kConfigPackage, "45743135", false); // When true, enables responsive UI. constexpr auto kEnableResponsiveUi = - flags::Flag(kConfigPackage, "45727212", false); + flags::Flag(kConfigPackage, "45727212", true); inline absl::btree_map&> GetBoolFlags() { return { @@ -109,12 +109,12 @@ inline absl::btree_map&> GetBoolFlags() { {45418905, kEnableMediumWebRtc}, {45418906, kEnableMediumWifiLan}, {45411589, kEnableRetryResumeTransfer}, - {45418908, kEnableSelfShareUi}, {45459748, kEnableSendingDesktopEvents}, {45409033, kShowAutoUpdateSetting}, {45762616, kEnableFileSync}, {45673628, kEnableWifiHotspotForHpRealtekDevices}, {45683539, kUseAlternateServiceUuidForDiscovery}, + {45776229, kEnableBackup}, {45662570, kEnableBetaLabel}, {45661130, kEnableConflictBanner}, {45720206, kEnableFlutterHooks}, diff --git a/sharing/incoming_frames_reader.cc b/sharing/incoming_frames_reader.cc index 72be3530..73c3cb43 100644 --- a/sharing/incoming_frames_reader.cc +++ b/sharing/incoming_frames_reader.cc @@ -24,6 +24,7 @@ #include #include +#include "absl/functional/any_invocable.h" #include "absl/memory/memory.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" @@ -66,21 +67,21 @@ IncomingFramesReader::~IncomingFramesReader() { } void IncomingFramesReader::ReadFrame( - std::function)> callback, + absl::AnyInvocable)> callback, absl::Duration timeout) { ProcessReadRequest(std::nullopt, std::move(callback), timeout); } void IncomingFramesReader::ReadFrame( FrameType frame_type, - std::function)> callback, + absl::AnyInvocable)> callback, absl::Duration timeout) { ProcessReadRequest(frame_type, std::move(callback), timeout); } void IncomingFramesReader::ProcessReadRequest( std::optional frame_type, - std::function)> callback, + absl::AnyInvocable)> callback, absl::Duration timeout) { std::unique_ptr cached_frame; { diff --git a/sharing/incoming_frames_reader.h b/sharing/incoming_frames_reader.h index cd3ba339..b03845d4 100644 --- a/sharing/incoming_frames_reader.h +++ b/sharing/incoming_frames_reader.h @@ -25,6 +25,7 @@ #include #include "absl/base/thread_annotations.h" +#include "absl/functional/any_invocable.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "internal/platform/task_runner.h" @@ -54,7 +55,7 @@ class IncomingFramesReader // Note: Callers are expected wait for `callback` to be run before scheduling // subsequent calls to ReadFrame(..). virtual void ReadFrame( - std::function< + absl::AnyInvocable< void(bool is_timeout, std::optional)> callback, @@ -70,7 +71,7 @@ class IncomingFramesReader // subsequent calls to ReadFrame(..). virtual void ReadFrame( nearby::sharing::service::proto::V1Frame::FrameType frame_type, - std::function< + absl::AnyInvocable< void(bool is_timeout, std::optional)> callback, @@ -84,8 +85,9 @@ class IncomingFramesReader struct ReadFrameInfo { std::optional frame_type = std::nullopt; - std::function)> + absl::AnyInvocable)> callback = nullptr; absl::Duration timeout = absl::ZeroDuration(); }; @@ -93,7 +95,7 @@ class IncomingFramesReader void ProcessReadRequest( std::optional frame_type, - std::function< + absl::AnyInvocable< void(bool is_timeout, std::optional)> callback, diff --git a/sharing/incoming_share_session.cc b/sharing/incoming_share_session.cc index 669cff8f..5bf80a03 100644 --- a/sharing/incoming_share_session.cc +++ b/sharing/incoming_share_session.cc @@ -46,6 +46,7 @@ #include "sharing/payload_tracker.h" #include "sharing/proto/wire_format.pb.h" #include "sharing/share_session.h" +#include "sharing/share_session_usage.h" #include "sharing/share_target.h" #include "sharing/text_attachment.h" #include "sharing/thread_timer.h" @@ -56,16 +57,12 @@ namespace nearby::sharing { namespace { -using ::location::nearby::proto::sharing::OSType; using ::location::nearby::proto::sharing::ResponseToIntroduction; using ::nearby::sharing::service::proto::AppMetadata; using ::nearby::sharing::service::proto::ConnectionResponseFrame; -using ::nearby::sharing::service::proto::Frame; using ::nearby::sharing::service::proto::IntroductionFrame; -using ::nearby::sharing::service::proto::SyncConfig; using ::nearby::sharing::service::proto::V1Frame; using ::nearby::sharing::service::proto::WifiCredentials; -using ::nearby::sharing::sync::SyncConfigPrefs; } // namespace @@ -78,7 +75,9 @@ IncomingShareSession::IncomingShareSession( transfer_update_callback) : ShareSession(clock, service_thread, connections_manager, analytics_recorder, std::move(endpoint_id), share_target), - transfer_update_callback_(std::move(transfer_update_callback)) {} + transfer_update_callback_(std::move(transfer_update_callback)) { + set_session_usage(ShareSessionUsage::kSharing); +} IncomingShareSession::IncomingShareSession(IncomingShareSession&&) = default; @@ -144,8 +143,20 @@ IncomingShareSession::ProcessIntroduction( "64 bit integer."; return TransferMetadata::Status::kNotEnoughSpace; } + if (apk.file_name_size() != apk.file_size_size() || + apk.file_name_size() != apk.payload_id_size()) { + LOG(WARNING) + << __func__ + << ": Ignore introduction, AppMetadata array length mismatch"; + return TransferMetadata::Status::kUnsupportedAttachmentType; + } // Map each apk file to a file attachment. for (int index = 0; index < apk.file_name_size(); ++index) { + if (apk.file_size(index) <= 0) { + LOG(WARNING) << __func__ + << ": Ignore introduction, due to invalid apk file size"; + return TransferMetadata::Status::kUnsupportedAttachmentType; + } // Locally generate an attachment id for each apk file, and map it to the // payload id. FileAttachment apk_file( @@ -219,6 +230,7 @@ bool IncomingShareSession::ReadyForTransfer( if (!self_share()) { TransferMetadataBuilder transfer_metadata_builder; + transfer_metadata_builder.set_usage(session_usage()); transfer_metadata_builder.set_status( TransferMetadata::Status::kAwaitingLocalConfirmation); transfer_metadata_builder.set_token(token()); @@ -258,6 +270,7 @@ bool IncomingShareSession::AcceptTransfer( UpdateTransferMetadata( TransferMetadataBuilder() + .set_usage(session_usage()) .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance) .set_token(token()) .build()); @@ -443,7 +456,10 @@ void IncomingShareSession::SendFailureResponse( WriteResponseFrame(response_status); DCHECK(TransferMetadata::IsFinalStatus(status)) << "SendFailureResponse should only be called with a final status"; - UpdateTransferMetadata(TransferMetadataBuilder().set_status(status).build()); + UpdateTransferMetadata(TransferMetadataBuilder() + .set_usage(session_usage()) + .set_status(status) + .build()); } std::optional @@ -458,19 +474,21 @@ IncomingShareSession::ProcessPayloadTransferUpdates( // Cancel acceptance timer when payload transfer update is received. // This mean sender has begun sending payload. mutual_acceptance_timeout_ = nullptr; - std::optional metadata; + std::optional metadata_builder; // If there is a batch of updates in the queue, only return the latest // TransferMetadata. for (; !updates.empty(); updates.pop()) { - metadata = + metadata_builder = get_payload_tracker()->ProcessPayloadUpdate(std::move(updates.front())); - if (!metadata.has_value()) { + if (!metadata_builder.has_value()) { continue; } - - if (metadata->status() == TransferMetadata::Status::kComplete) { + TransferMetadata metadata = + metadata_builder->set_usage(session_usage()).build(); + if (metadata.status() == TransferMetadata::Status::kComplete) { if (!FinalizePayloads()) { return TransferMetadataBuilder() + .set_usage(session_usage()) .set_status(TransferMetadata::Status::kIncompletePayloads) .build(); } @@ -483,13 +501,15 @@ IncomingShareSession::ProcessPayloadTransferUpdates( if (update_file_paths_in_progress) { UpdateFilePayloadPaths(); } else { - if (metadata->status() == TransferMetadata::Status::kCancelled) { + if (metadata.status() == TransferMetadata::Status::kCancelled) { VLOG(1) << __func__ << ": Update file paths for cancelled transfer"; UpdateFilePayloadPaths(); } } } - return metadata; + return metadata_builder.has_value() + ? std::make_optional(metadata_builder->build()) + : std::nullopt; } void IncomingShareSession::OnConnected(NearbyConnection* connection) { @@ -502,43 +522,4 @@ void IncomingShareSession::PushPayloadTransferUpdateForTest( payload_updates_queue()->Queue(std::move(update)); } -void IncomingShareSession::ProcessSyncFrame( - SyncManager& sync_manager, - const nearby::sharing::service::proto::SyncFrame& sync_frame) { - if (session_phase_ != SessionPhase::kUninitialized) { - LOG(WARNING) << "Ignore SyncFrame received in unexpected session phase: " - << static_cast(session_phase_); - return; - } - // TODO: b/485304482 - Check that the connected device is authenticated and is - // part of a sync pairing. - if (!certificate().has_value()) { - LOG(WARNING) << "Ignore SyncFrame received from unauthenticated device."; - return; - } - if (false && - !sync_manager.IsFileSyncBinding(certificate()->binding_id())) { - LOG(WARNING) << "Ignore SyncFrame received in unexpected binding id: " - << certificate()->binding_id(); - return; - } - session_phase_ = SessionPhase::kSync; - if (sync_frame.has_handshake()) { - VLOG(1) << __func__ << ": Received FileSync Handshake"; - WriteSyncConfigFrame( - sync_manager.GetSyncConfig(certificate()->binding_id()) - .value_or(SyncConfigPrefs()) - .sync_config()); - } -} - -void IncomingShareSession::WriteSyncConfigFrame(const SyncConfig& config) { - Frame frame; - frame.set_version(Frame::V1); - V1Frame* v1_frame = frame.mutable_v1(); - v1_frame->set_type(V1Frame::FILE_SYNC); - *v1_frame->mutable_file_sync()->mutable_config() = config; - WriteFrame(frame); -} - } // namespace nearby::sharing diff --git a/sharing/incoming_share_session.h b/sharing/incoming_share_session.h index 73a7ce14..ec4a55f4 100644 --- a/sharing/incoming_share_session.h +++ b/sharing/incoming_share_session.h @@ -105,9 +105,6 @@ class IncomingShareSession : public ShareSession { // Called when an incoming connection is established. void OnConnected(NearbyConnection* connection); - void ProcessSyncFrame(nearby::sharing::SyncManager& sync_manager, - const nearby::sharing::service::proto::SyncFrame& sync_frame); - protected: void InvokeTransferUpdateCallback(const TransferMetadata& metadata) override; @@ -129,9 +126,6 @@ class IncomingShareSession : public ShareSession { // Returns true if all payloads were successfully finalized. bool FinalizePayloads(); - void WriteSyncConfigFrame( - const nearby::sharing::service::proto::SyncConfig& config); - std::function transfer_update_callback_; diff --git a/sharing/incoming_share_session_test.cc b/sharing/incoming_share_session_test.cc index b926f65b..1c77ae79 100644 --- a/sharing/incoming_share_session_test.cc +++ b/sharing/incoming_share_session_test.cc @@ -24,28 +24,28 @@ #include #include +#include "location/nearby/analytics/cpp/logging/mock_event_logger.h" +#include "location/nearby/analytics/cpp/logging/sharing_log_matchers.h" +#include "location/nearby/analytics/cpp/proto/nearby_sharing_log.pb.h" +#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "internal/analytics/mock_event_logger.h" -#include "internal/analytics/sharing_log_matchers.h" #include "internal/base/file_path.h" #include "internal/test/fake_clock.h" #include "internal/test/fake_device_info.h" #include "internal/test/fake_task_runner.h" #include "proto/sharing_enums.pb.h" -#include "sharing/analytics/analytics_recorder.h" #include "sharing/attachment_compare.h" // IWYU pragma: keep #include "sharing/fake_nearby_connections_manager.h" #include "sharing/file_attachment.h" #include "sharing/internal/public/logging.h" #include "sharing/nearby_connection_impl.h" #include "sharing/nearby_connections_types.h" -#include "sharing/paired_key_verification_runner.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" #include "sharing/proto/wire_format.pb.h" +#include "sharing/share_session_usage.h" #include "sharing/share_target.h" #include "sharing/text_attachment.h" #include "sharing/transfer_metadata.h" @@ -59,7 +59,6 @@ namespace { using ::absl::Seconds; using ::location::nearby::proto::sharing::EventCategory; using ::location::nearby::proto::sharing::EventType; -using ::location::nearby::proto::sharing::OSType; using ::location::nearby::proto::sharing::ResponseToIntroduction; using ::nearby::analytics::HasAction; using ::nearby::analytics::HasCategory; @@ -187,8 +186,8 @@ class IncomingShareSessionTest : public ::testing::Test { FakeClock clock_; FakeTaskRunner task_runner_{&clock_, 1}; nearby::analytics::MockEventLogger mock_event_logger_; - analytics::AnalyticsRecorder analytics_recorder_{/*vendor_id=*/0, - &mock_event_logger_}; + analytics::AnalyticsRecorderImpl analytics_recorder_{/*vendor_id=*/0, + &mock_event_logger_}; ShareTarget share_target_; MockFunction transfer_metadata_callback_; @@ -355,6 +354,51 @@ TEST_F(IncomingShareSessionTest, ProcessIntroductionWithApkSuccess) { UnorderedElementsAre(file1, file2, file3)); } +TEST_F(IncomingShareSessionTest, ProcessIntroductionWithApkLengthMismatch) { + IntroductionFrame introduction_frame; + CHECK( + proto2::TextFormat::ParseFromString(R"pb( + app_metadata { + app_name: "MyApp" + size: 300 + payload_id: 9876 + id: 1234 + file_name: "MyApp.apk" + file_name: "MyApp2.apk" + file_size: 100 + file_size: 100 + file_size: 100 + package_name: "com.example.myapp" + } + )pb", + &introduction_frame)); + session_.OnConnected(&connection_); + + EXPECT_THAT(session_.ProcessIntroduction(introduction_frame), + Eq(TransferMetadata::Status::kUnsupportedAttachmentType)); +} + +TEST_F(IncomingShareSessionTest, ProcessIntroductionWithApkInvalidSize) { + IntroductionFrame introduction_frame; + CHECK( + proto2::TextFormat::ParseFromString(R"pb( + app_metadata { + app_name: "MyApp" + size: 300 + payload_id: 9876 + id: 1234 + file_name: "MyApp.apk" + file_size: 0 + package_name: "com.example.myapp" + } + )pb", + &introduction_frame)); + session_.OnConnected(&connection_); + + EXPECT_THAT(session_.ProcessIntroduction(introduction_frame), + Eq(TransferMetadata::Status::kUnsupportedAttachmentType)); +} + TEST_F(IncomingShareSessionTest, PayloadTransferUpdateCompleteWithWrongPayloadType) { connections_manager_.AcceptConnection( @@ -1085,7 +1129,9 @@ TEST_F(IncomingShareSessionTest, ReadyForTransferNotSelfShare) { session_.OnConnected(&connection_); EXPECT_CALL( transfer_metadata_callback_, - Call(_, HasStatus(TransferMetadata::Status::kAwaitingLocalConfirmation))); + Call(_, AllOf(HasStatus( + TransferMetadata::Status::kAwaitingLocalConfirmation), + HasUsage(ShareSessionUsage::kSharing)))); EXPECT_THAT( session_.ReadyForTransfer( @@ -1104,7 +1150,9 @@ TEST_F(IncomingShareSessionTest, ReadyForTransferSelfShare) { session.OnConnected(&connection_); EXPECT_CALL( transfer_metadata_callback_, - Call(_, HasStatus(TransferMetadata::Status::kAwaitingLocalConfirmation))) + Call(_, AllOf(HasStatus( + TransferMetadata::Status::kAwaitingLocalConfirmation), + HasUsage(ShareSessionUsage::kSharing)))) .Times(0); EXPECT_THAT( @@ -1117,7 +1165,9 @@ TEST_F(IncomingShareSessionTest, ReadyForTransferTimeout) { session_.OnConnected(&connection_); EXPECT_CALL( transfer_metadata_callback_, - Call(_, HasStatus(TransferMetadata::Status::kAwaitingLocalConfirmation))); + Call(_, AllOf(HasStatus( + TransferMetadata::Status::kAwaitingLocalConfirmation), + HasUsage(ShareSessionUsage::kSharing)))); bool accept_timeout_called = false; EXPECT_THAT(session_.ReadyForTransfer( @@ -1195,7 +1245,9 @@ TEST_F(IncomingShareSessionTest, AcceptTransferSuccess) { IsFalse()); EXPECT_CALL( transfer_metadata_callback_, - Call(_, HasStatus(TransferMetadata::Status::kAwaitingRemoteAcceptance))); + Call(_, + AllOf(HasStatus(TransferMetadata::Status::kAwaitingRemoteAcceptance), + HasUsage(ShareSessionUsage::kSharing)))); EXPECT_CALL( mock_event_logger_, Log(Matcher(AllOf( @@ -1274,8 +1326,10 @@ TEST_F(IncomingShareSessionTest, TryUpgradeBandwidthNeeded) { } TEST_F(IncomingShareSessionTest, SendFailureResponseNotConnected) { - EXPECT_CALL(transfer_metadata_callback_, - Call(_, HasStatus(TransferMetadata::Status::kNotEnoughSpace))); + EXPECT_CALL( + transfer_metadata_callback_, + Call(_, AllOf(HasStatus(TransferMetadata::Status::kNotEnoughSpace), + HasUsage(ShareSessionUsage::kSharing)))); session_.SendFailureResponse(TransferMetadata::Status::kNotEnoughSpace); } @@ -1284,8 +1338,10 @@ TEST_F(IncomingShareSessionTest, SendFailureResponseConnected) { connections_manager_.AcceptConnection( /*endpoint_info=*/{}, kEndpointId, &connection_); session_.OnConnected(&connection_); - EXPECT_CALL(transfer_metadata_callback_, - Call(_, HasStatus(TransferMetadata::Status::kNotEnoughSpace))); + EXPECT_CALL( + transfer_metadata_callback_, + Call(_, AllOf(HasStatus(TransferMetadata::Status::kNotEnoughSpace), + HasUsage(ShareSessionUsage::kSharing)))); std::queue> frames_data; connections_manager_.set_send_payload_callback( [&](std::unique_ptr payload, diff --git a/sharing/internal/api/mock_sharing_platform.h b/sharing/internal/api/mock_sharing_platform.h index b5b64e18..c19adcc8 100644 --- a/sharing/internal/api/mock_sharing_platform.h +++ b/sharing/internal/api/mock_sharing_platform.h @@ -19,12 +19,11 @@ #include #include +#include "location/nearby/sharing/lib/account/account_manager.h" #include "gmock/gmock.h" #include "absl/strings/string_view.h" #include "internal/base/file_path.h" -#include "internal/platform/device_info.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/task_runner.h" +#include "internal/platform/implementation/device_info.h" #include "sharing/internal/api/app_info.h" #include "sharing/internal/api/bluetooth_adapter.h" #include "sharing/internal/api/fast_init_ble_beacon.h" @@ -71,8 +70,7 @@ class MockSharingPlatform : public SharingPlatform { MOCK_METHOD(PreferenceManager&, GetPreferenceManager, (), (override)); MOCK_METHOD(AccountManager&, GetAccountManager, (), (override)); - MOCK_METHOD(TaskRunner&, GetDefaultTaskRunner, (), (override)); - MOCK_METHOD(nearby::DeviceInfo&, GetDeviceInfo, (), (override)); + MOCK_METHOD(nearby::api::DeviceInfo&, GetDeviceInfo, (), (override)); MOCK_METHOD(std::unique_ptr, CreatePublicCertificateDatabase, (const FilePath& database_path), (override)); diff --git a/sharing/internal/api/sharing_platform.h b/sharing/internal/api/sharing_platform.h index d5bab76a..9aefd967 100644 --- a/sharing/internal/api/sharing_platform.h +++ b/sharing/internal/api/sharing_platform.h @@ -19,11 +19,10 @@ #include #include +#include "location/nearby/sharing/lib/account/account_manager.h" #include "absl/strings/string_view.h" #include "internal/base/file_path.h" -#include "internal/platform/device_info.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/platform/task_runner.h" +#include "internal/platform/implementation/device_info.h" #include "sharing/internal/api/app_info.h" #include "sharing/internal/api/bluetooth_adapter.h" #include "sharing/internal/api/fast_init_ble_beacon.h" @@ -64,8 +63,7 @@ class SharingPlatform { virtual PreferenceManager& GetPreferenceManager() = 0; virtual AccountManager& GetAccountManager() = 0; - virtual TaskRunner& GetDefaultTaskRunner() = 0; - virtual nearby::DeviceInfo& GetDeviceInfo() = 0; + virtual nearby::api::DeviceInfo& GetDeviceInfo() = 0; virtual std::unique_ptr CreatePublicCertificateDatabase(const FilePath& database_path) = 0; diff --git a/sharing/internal/public/context.h b/sharing/internal/public/context.h index 23c8de03..05b3d25f 100644 --- a/sharing/internal/public/context.h +++ b/sharing/internal/public/context.h @@ -49,9 +49,6 @@ class Context { // count of tasks running at the same time. virtual std::unique_ptr CreateConcurrentTaskRunner( uint32_t concurrent_count) const = 0; - - // Provides the API to retrieve TaskRunner to run a task globally. - virtual TaskRunner* GetTaskRunner() = 0; }; } // namespace nearby diff --git a/sharing/internal/public/context_impl.cc b/sharing/internal/public/context_impl.cc index b439cefa..7aefa05c 100644 --- a/sharing/internal/public/context_impl.cc +++ b/sharing/internal/public/context_impl.cc @@ -70,8 +70,4 @@ std::unique_ptr ContextImpl::CreateConcurrentTaskRunner( return task_runner; } -TaskRunner* ContextImpl::GetTaskRunner() { - return &platform_.GetDefaultTaskRunner(); -} - } // namespace nearby diff --git a/sharing/internal/public/context_impl.h b/sharing/internal/public/context_impl.h index 9775228d..a9078a6a 100644 --- a/sharing/internal/public/context_impl.h +++ b/sharing/internal/public/context_impl.h @@ -43,7 +43,6 @@ class ContextImpl : public Context { std::unique_ptr CreateSequencedTaskRunner() const override; std::unique_ptr CreateConcurrentTaskRunner( uint32_t concurrent_count) const override; - TaskRunner* GetTaskRunner() override; private: nearby::sharing::api::SharingPlatform& platform_; diff --git a/sharing/internal/public/pref_names.h b/sharing/internal/public/pref_names.h index 83ced43c..6daef139 100644 --- a/sharing/internal/public/pref_names.h +++ b/sharing/internal/public/pref_names.h @@ -61,13 +61,6 @@ class PrefNames { // TODO: b/485304482 - define data format for binding configs. static constexpr absl::string_view kBindingConfigPrefix = "nearby_sharing.binding_config."; - - // Sync configs preferences are stored in pref keys: - // kSyncConfigPrefix + - // Example: "nearby_sharing.sync_config.01243347-2343-4324-3423-432432432432" - // Data stored in sync config prefs is a SyncConfig proto. - static constexpr absl::string_view kSyncConfigPrefix = - "nearby_sharing.sync_config."; }; } // namespace nearby::sharing diff --git a/sharing/internal/test/fake_context.cc b/sharing/internal/test/fake_context.cc index 35605bca..37557c15 100644 --- a/sharing/internal/test/fake_context.cc +++ b/sharing/internal/test/fake_context.cc @@ -38,8 +38,7 @@ FakeContext::FakeContext() fake_connectivity_manager_(std::make_unique()), fake_bluetooth_adapter_(std::make_unique()), fake_fast_initiation_manager_( - std::make_unique()), - executor_(std::make_unique(fake_clock_.get(), 5)) {} + std::make_unique()) {} Clock* FakeContext::GetClock() const { return fake_clock_.get(); } @@ -70,6 +69,4 @@ std::unique_ptr FakeContext::CreateConcurrentTaskRunner( return std::make_unique(fake_clock_.get(), concurrent_count); } -TaskRunner* FakeContext::GetTaskRunner() { return executor_.get(); } - } // namespace nearby diff --git a/sharing/internal/test/fake_context.h b/sharing/internal/test/fake_context.h index c637dbf2..5a59879a 100644 --- a/sharing/internal/test/fake_context.h +++ b/sharing/internal/test/fake_context.h @@ -47,7 +47,6 @@ class FakeContext : public Context { std::unique_ptr CreateSequencedTaskRunner() const override; std::unique_ptr CreateConcurrentTaskRunner( uint32_t concurrent_count) const override; - TaskRunner* GetTaskRunner() override; FakeClock* fake_clock() const { return fake_clock_.get(); } FakeConnectivityManager* fake_connectivity_manager() const { @@ -59,9 +58,6 @@ class FakeContext : public Context { FakeFastInitiationManager* fake_fast_initiation_manager() const { return fake_fast_initiation_manager_.get(); } - FakeTaskRunner* fake_task_runner() const { - return executor_.get(); - } FakeTaskRunner* last_sequenced_task_runner() const { return last_sequenced_task_runner_; @@ -72,7 +68,6 @@ class FakeContext : public Context { std::unique_ptr fake_connectivity_manager_; std::unique_ptr fake_bluetooth_adapter_; std::unique_ptr fake_fast_initiation_manager_; - std::unique_ptr executor_; mutable FakeTaskRunner* last_sequenced_task_runner_ = nullptr; }; diff --git a/sharing/internal/test/fake_context_test.cc b/sharing/internal/test/fake_context_test.cc index 0b0c3152..03179926 100644 --- a/sharing/internal/test/fake_context_test.cc +++ b/sharing/internal/test/fake_context_test.cc @@ -15,9 +15,6 @@ #include "sharing/internal/test/fake_context.h" #include "gtest/gtest.h" -#include "absl/synchronization/notification.h" -#include "absl/time/time.h" -#include "internal/platform/task_runner.h" namespace nearby { namespace { @@ -31,18 +28,5 @@ TEST(FakeContext, TestAccessMockContext) { EXPECT_NE(context.CreateConcurrentTaskRunner(5), nullptr); } -TEST(FakeContext, ExecuteTask) { - FakeContext context; - absl::Notification notification; - bool is_called = false; - context.GetTaskRunner()->PostTask([&]() { - is_called = true; - notification.Notify(); - }); - - EXPECT_TRUE(notification.WaitForNotificationWithTimeout(absl::Seconds(1))); - EXPECT_TRUE(is_called); -} - } // namespace } // namespace nearby diff --git a/sharing/local_device_data/BUILD b/sharing/local_device_data/BUILD index 030085b3..22930d93 100644 --- a/sharing/local_device_data/BUILD +++ b/sharing/local_device_data/BUILD @@ -30,9 +30,8 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//internal/base", - "//internal/platform:types", - "//internal/platform/implementation:account_manager", "//internal/platform/implementation:types", + "//location/nearby/sharing/lib/account:account_manager", "//sharing/common:enum", "//sharing/internal/api:platform", "//sharing/internal/base:utf_utils", @@ -68,9 +67,10 @@ cc_test( ], deps = [ ":local_device_data", - "//internal/platform/implementation:account_manager", "//internal/platform/implementation:platform_impl", "//internal/test", + "//location/nearby/sharing/lib/account:account_manager", + "//location/nearby/sharing/lib/account:fake_account_manager", "//sharing/common", "//sharing/common:enum", "//sharing/internal/test:nearby_test", diff --git a/sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc b/sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc index 80f2ffbb..e3ab98b2 100644 --- a/sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc +++ b/sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc @@ -21,11 +21,10 @@ #include #include +#include "location/nearby/sharing/lib/account/account_manager.h" #include "absl/memory/memory.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "absl/strings/substitute.h" -#include "internal/platform/device_info.h" -#include "internal/platform/implementation/account_manager.h" #include "internal/platform/implementation/device_info.h" #include "sharing/common/nearby_share_enums.h" #include "sharing/internal/api/preference_manager.h" @@ -37,14 +36,11 @@ #include "sharing/proto/rpc_resources.pb.h" #include "sharing/proto/timestamp.pb.h" -namespace nearby { -namespace sharing { +namespace nearby::sharing { namespace { using ::nearby::api::DeviceInfo; using ::nearby::sharing::api::PreferenceManager; -constexpr absl::string_view kDefaultDeviceName = "$0\'s $1"; - // Returns a truncated version of |name| that is |max_length| characters long. // For example, name="Reallylongname" with max_length=9 will return "Really...". // name="Reallylongname" with max_length=20 will return "Reallylongname". @@ -72,7 +68,7 @@ NearbyShareLocalDeviceDataManagerImpl::Factory* std::unique_ptr NearbyShareLocalDeviceDataManagerImpl::Factory::Create( PreferenceManager& preference_manager, - AccountManager& account_manager, nearby::DeviceInfo& device_info) { + AccountManager& account_manager, nearby::api::DeviceInfo& device_info) { if (test_factory_) { return test_factory_->CreateInstance(); } @@ -91,7 +87,7 @@ NearbyShareLocalDeviceDataManagerImpl::Factory::~Factory() = default; NearbyShareLocalDeviceDataManagerImpl::NearbyShareLocalDeviceDataManagerImpl( PreferenceManager& preference_manager, AccountManager& account_manager, - nearby::DeviceInfo& device_info) + nearby::api::DeviceInfo& device_info) : preference_manager_(preference_manager), account_manager_(account_manager), device_info_(device_info) {} @@ -148,21 +144,24 @@ std::string NearbyShareLocalDeviceDataManagerImpl::GetDefaultDeviceName() if (os_type == DeviceInfo::OsType::kMacOS || os_type == DeviceInfo::OsType::kIos || !account.has_value() || account->given_name.empty()) { - std::string device_name = device_info_.GetOsDeviceName(); + std::string device_name = + device_info_.GetOsDeviceName().value_or("unknown"); return GetTruncatedName(device_name, kNearbyShareDeviceNameMaxLength); } std::string given_name = account->given_name; - std::string device_type = device_info_.GetDeviceTypeName(); - uint64_t untruncated_length = - absl::Substitute(kDefaultDeviceName, given_name, device_type).length(); + DeviceInfo::DeviceType device_type = device_info_.GetDeviceType(); + std::string device_name = absl::StrCat(given_name, "'s ", device_type); + uint64_t untruncated_length = device_name.length(); + if (untruncated_length <= kNearbyShareDeviceNameMaxLength) { + return device_name; + } uint64_t overflow_length = untruncated_length - kNearbyShareDeviceNameMaxLength; std::string truncated_name = GetTruncatedName(given_name, given_name.length() - overflow_length); - return absl::Substitute(kDefaultDeviceName, truncated_name, device_type); + return absl::StrCat(truncated_name, "'s ", device_type); } -} // namespace sharing -} // namespace nearby +} // namespace nearby::sharing diff --git a/sharing/local_device_data/nearby_share_local_device_data_manager_impl.h b/sharing/local_device_data/nearby_share_local_device_data_manager_impl.h index 176b3b94..7df292b0 100644 --- a/sharing/local_device_data/nearby_share_local_device_data_manager_impl.h +++ b/sharing/local_device_data/nearby_share_local_device_data_manager_impl.h @@ -18,9 +18,9 @@ #include #include +#include "location/nearby/sharing/lib/account/account_manager.h" #include "absl/strings/string_view.h" -#include "internal/platform/device_info.h" -#include "internal/platform/implementation/account_manager.h" +#include "internal/platform/implementation/device_info.h" #include "sharing/common/nearby_share_enums.h" #include "sharing/internal/api/preference_manager.h" #include "sharing/local_device_data/nearby_share_local_device_data_manager.h" @@ -40,7 +40,7 @@ class NearbyShareLocalDeviceDataManagerImpl public: static std::unique_ptr Create( nearby::sharing::api::PreferenceManager& preference_manager, - AccountManager& account_manager, nearby::DeviceInfo& device_info); + AccountManager& account_manager, nearby::api::DeviceInfo& device_info); static void SetFactoryForTesting(Factory* test_factory); protected: @@ -61,7 +61,7 @@ class NearbyShareLocalDeviceDataManagerImpl private: NearbyShareLocalDeviceDataManagerImpl( nearby::sharing::api::PreferenceManager& preference_manager, - AccountManager& account_manager, nearby::DeviceInfo& device_info); + AccountManager& account_manager, nearby::api::DeviceInfo& device_info); DeviceNameValidationResult ValidateDeviceName(absl::string_view name); @@ -73,7 +73,7 @@ class NearbyShareLocalDeviceDataManagerImpl nearby::sharing::api::PreferenceManager& preference_manager_; AccountManager& account_manager_; - nearby::DeviceInfo& device_info_; + nearby::api::DeviceInfo& device_info_; }; } // namespace nearby::sharing diff --git a/sharing/local_device_data/nearby_share_local_device_data_manager_impl_test.cc b/sharing/local_device_data/nearby_share_local_device_data_manager_impl_test.cc index ca3fcdad..d33eb8d6 100644 --- a/sharing/local_device_data/nearby_share_local_device_data_manager_impl_test.cc +++ b/sharing/local_device_data/nearby_share_local_device_data_manager_impl_test.cc @@ -21,11 +21,11 @@ #include #include +#include "location/nearby/sharing/lib/account/account_manager.h" +#include "location/nearby/sharing/lib/account/fake_account_manager.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" -#include "internal/platform/implementation/account_manager.h" -#include "internal/test/fake_account_manager.h" #include "internal/test/fake_device_info.h" #include "sharing/common/nearby_share_enums.h" #include "sharing/common/nearby_share_prefs.h" @@ -109,16 +109,16 @@ class NearbyShareLocalDeviceDataManagerImplTest } std::string GetDeviceName() const { - return fake_device_info_.GetOsDeviceName(); + return fake_device_info_.GetOsDeviceName().value_or("unknown"); } - std::string GetDeviceTypeName() const { - return fake_device_info_.GetDeviceTypeName(); + nearby::FakeDeviceInfo::DeviceType GetDeviceType() const { + return fake_device_info_.GetDeviceType(); } protected: nearby::FakePreferenceManager preference_manager_; - nearby::FakeAccountManager fake_account_manager_; + FakeAccountManager fake_account_manager_; nearby::FakeDeviceInfo fake_device_info_; std::vector notifications_; std::unique_ptr manager_; @@ -138,8 +138,9 @@ TEST_F(NearbyShareLocalDeviceDataManagerImplTest, DefaultDeviceName) { fake_account_manager().SetAccount(account); EXPECT_EQ(absl::Substitute(kDefaultDeviceName, kFakeGivenName, - GetDeviceTypeName()), + GetDeviceType()), manager()->GetDeviceName()); + EXPECT_EQ(manager()->GetDeviceName(), "Barack奥巴马's PC"); // Make sure that when we use a given name that is very long we truncate // correctly. @@ -152,7 +153,7 @@ TEST_F(NearbyShareLocalDeviceDataManagerImplTest, SetDeviceName) { CreateManager(); std::string expected_default_device_name = - absl::Substitute(kDefaultDeviceName, kFakeGivenName, GetDeviceTypeName()); + absl::Substitute(kDefaultDeviceName, kFakeGivenName, GetDeviceType()); EXPECT_EQ(manager()->GetDeviceName(), expected_default_device_name); EXPECT_TRUE(notifications().empty()); diff --git a/sharing/nearby_connection_impl.cc b/sharing/nearby_connection_impl.cc index 42ab97eb..eecca33d 100644 --- a/sharing/nearby_connection_impl.cc +++ b/sharing/nearby_connection_impl.cc @@ -22,12 +22,12 @@ #include #include "absl/synchronization/mutex.h" -#include "internal/platform/device_info.h" +#include "internal/platform/implementation/device_info.h" #include "sharing/internal/public/logging.h" namespace nearby::sharing { -NearbyConnectionImpl::NearbyConnectionImpl(nearby::DeviceInfo& device_info) +NearbyConnectionImpl::NearbyConnectionImpl(nearby::api::DeviceInfo& device_info) : device_info_(device_info) { if (!device_info_.PreventSleep()) { LOG(WARNING) << __func__ << ":Failed to prevent device sleep."; diff --git a/sharing/nearby_connection_impl.h b/sharing/nearby_connection_impl.h index 35725791..090bf9eb 100644 --- a/sharing/nearby_connection_impl.h +++ b/sharing/nearby_connection_impl.h @@ -23,7 +23,7 @@ #include "absl/base/thread_annotations.h" #include "absl/synchronization/mutex.h" -#include "internal/platform/device_info.h" +#include "internal/platform/implementation/device_info.h" #include "sharing/nearby_connection.h" namespace nearby::sharing { @@ -32,7 +32,7 @@ class NearbyConnectionsManager; class NearbyConnectionImpl : public NearbyConnection { public: - explicit NearbyConnectionImpl(nearby::DeviceInfo& device_info); + explicit NearbyConnectionImpl(nearby::api::DeviceInfo& device_info); ~NearbyConnectionImpl() override; // NearbyConnection: @@ -46,7 +46,7 @@ class NearbyConnectionImpl : public NearbyConnection { void WriteMessage(std::vector bytes) ABSL_LOCKS_EXCLUDED(mutex_); private: - nearby::DeviceInfo& device_info_; + nearby::api::DeviceInfo& device_info_; absl::Mutex mutex_; std::function> bytes)> read_callback_ diff --git a/sharing/nearby_connections_manager_factory.cc b/sharing/nearby_connections_manager_factory.cc index 31816390..cba3ccbd 100644 --- a/sharing/nearby_connections_manager_factory.cc +++ b/sharing/nearby_connections_manager_factory.cc @@ -16,8 +16,8 @@ #include -#include "internal/analytics/event_logger.h" -#include "internal/platform/device_info.h" +#include "location/nearby/analytics/cpp/logging/event_logger.h" +#include "internal/platform/implementation/device_info.h" #include "internal/platform/task_runner.h" #include "sharing/internal/public/context.h" #include "sharing/nearby_connections_manager.h" @@ -29,7 +29,7 @@ namespace nearby::sharing { std::unique_ptr NearbyConnectionsManagerFactory::CreateConnectionsManager( nearby::TaskRunner* connections_callback_task_runner, Context* context, - nearby::DeviceInfo& device_info, + nearby::api::DeviceInfo& device_info, nearby::analytics::EventLogger* event_logger) { return std::make_unique( connections_callback_task_runner, context, diff --git a/sharing/nearby_connections_manager_factory.h b/sharing/nearby_connections_manager_factory.h index f22da1ef..f856a140 100644 --- a/sharing/nearby_connections_manager_factory.h +++ b/sharing/nearby_connections_manager_factory.h @@ -17,8 +17,8 @@ #include -#include "internal/analytics/event_logger.h" -#include "internal/platform/device_info.h" +#include "location/nearby/analytics/cpp/logging/event_logger.h" +#include "internal/platform/implementation/device_info.h" #include "internal/platform/task_runner.h" #include "sharing/internal/public/context.h" #include "sharing/nearby_connections_manager.h" @@ -33,7 +33,7 @@ class NearbyConnectionsManagerFactory { // that NearbySharingService is running on. static std::unique_ptr CreateConnectionsManager( nearby::TaskRunner* connections_callback_task_runner, Context* context, - nearby::DeviceInfo& device_info, + nearby::api::DeviceInfo& device_info, nearby::analytics::EventLogger* event_logger = nullptr); private: diff --git a/sharing/nearby_connections_manager_impl.cc b/sharing/nearby_connections_manager_impl.cc index 20b6e1ef..0b57e8c0 100644 --- a/sharing/nearby_connections_manager_impl.cc +++ b/sharing/nearby_connections_manager_impl.cc @@ -32,7 +32,7 @@ #include "absl/types/span.h" #include "internal/base/file_path.h" #include "internal/flags/nearby_flags.h" -#include "internal/platform/device_info.h" +#include "internal/platform/implementation/device_info.h" #include "internal/platform/mutex_lock.h" #include "internal/platform/task_runner.h" #include "sharing/advertisement.h" @@ -150,7 +150,8 @@ std::string PayloadStatusToString(PayloadStatus status) { NearbyConnectionsManagerImpl::NearbyConnectionsManagerImpl( TaskRunner* connections_callback_task_runner, Context* context, - ConnectivityManager& connectivity_manager, nearby::DeviceInfo& device_info, + ConnectivityManager& connectivity_manager, + nearby::api::DeviceInfo& device_info, std::unique_ptr nearby_connections_service) : connections_callback_task_runner_(connections_callback_task_runner), context_(context), @@ -333,6 +334,12 @@ void NearbyConnectionsManagerImpl::StopDiscovery() { }); } +void NearbyConnectionsManagerImpl::RemoveTransferManagerOnCallbackThread( + std::unique_ptr transfer_manager) const { + connections_callback_task_runner_->PostTask( + [transfer_manager = std::move(transfer_manager)]() {}); +} + void NearbyConnectionsManagerImpl::Connect( std::vector endpoint_info, absl::string_view endpoint_id, std::optional> bluetooth_mac_address, @@ -415,15 +422,20 @@ void NearbyConnectionsManagerImpl::Connect( [this, endpoint_id = std::string(endpoint_id)](ConnectionsStatus status) { MutexLock lock(&mutex_); if (status != ConnectionsStatus::kSuccess) { - transfer_managers_.erase(endpoint_id); + auto node = transfer_managers_.extract(endpoint_id); + if (!node.empty()) { + RemoveTransferManagerOnCallbackThread(std::move(node.mapped())); + } } OnConnectionRequested(endpoint_id, status); }); // Setup transfer manager. if (IsTransportTypeFlagsSet(transport_type, TransportType::kHighQuality)) { - transfer_managers_[endpoint_id] = - std::make_unique(context_, endpoint_id); + transfer_managers_[endpoint_id] = std::make_unique( + connections_callback_task_runner_, endpoint_id, + absl::bind_front(&NearbyConnectionsManagerImpl::SendWithoutDelay, + this)); } } @@ -498,23 +510,18 @@ void NearbyConnectionsManagerImpl::Send( RegisterPayloadStatusListener(payload->id, listener); } - if (transfer_managers_.contains(endpoint_id) && payload->content.is_file()) { - VLOG(1) << __func__ << ": Send payload " << payload->id << " to " - << endpoint_id << " to transfer manager. payload is file: " - << payload->content.is_file() << ", is bytes " - << payload->content.is_bytes(); - transfer_managers_.at(endpoint_id) - ->Send([&, endpoint_id = std::string(endpoint_id), - payload_copy = *payload]() { - VLOG(1) << __func__ << ": Send payload " << payload_copy.id << " to " - << endpoint_id; - auto sent_payload = std::make_unique(payload_copy); - SendWithoutDelay(endpoint_id, std::move(sent_payload)); - }); - transfer_managers_.at(endpoint_id)->StartTransfer(); - return; + if (payload->content.is_file()) { + const auto& it = transfer_managers_.find(endpoint_id); + if (it != transfer_managers_.end()) { + VLOG(1) << __func__ << ": Send payload " << payload->id << " to " + << endpoint_id << " to transfer manager. payload is file: " + << payload->content.is_file() << ", is bytes " + << payload->content.is_bytes(); + it->second->Send(std::move(payload)); + it->second->StartTransfer(); + return; + } } - SendWithoutDelay(endpoint_id, std::move(payload)); } @@ -739,9 +746,13 @@ void NearbyConnectionsManagerImpl::OnDisconnected( absl::string_view endpoint_id) { MutexLock lock(&mutex_); // Remove transfer manager. - if (transfer_managers_.contains(endpoint_id)) { - transfer_managers_[endpoint_id]->CancelTransfer(); - transfer_managers_.erase(endpoint_id); + const auto& transfer_manager_it = transfer_managers_.find(endpoint_id); + if (transfer_manager_it != transfer_managers_.end()) { + transfer_manager_it->second->CancelTransfer(); + auto node = transfer_managers_.extract(transfer_manager_it); + if (!node.empty()) { + RemoveTransferManagerOnCallbackThread(std::move(node.mapped())); + } } Status connection_layer_status = Status::kUnknown; @@ -771,8 +782,9 @@ void NearbyConnectionsManagerImpl::OnBandwidthChanged( << ": Bandwidth changed to medium=" << static_cast(medium) << "; endpoint_id=" << endpoint_id; - if (transfer_managers_.contains(endpoint_id)) { - transfer_managers_[endpoint_id]->OnMediumQualityChanged(medium); + const auto& transfer_manager_it = transfer_managers_.find(endpoint_id); + if (transfer_manager_it != transfer_managers_.end()) { + transfer_manager_it->second->OnMediumQualityChanged(medium); } current_upgraded_mediums_.insert_or_assign(endpoint_id, medium); @@ -907,7 +919,11 @@ void NearbyConnectionsManagerImpl::Reset() { for (auto& transfer_manager : transfer_managers_) { transfer_manager.second->CancelTransfer(); } - transfer_managers_.clear(); + absl::flat_hash_map> + transfer_managers; + transfer_managers.swap(transfer_managers_); + connections_callback_task_runner_->PostTask( + [transfer_managers = std::move(transfer_managers)]() {}); for (auto& entry : pending_outgoing_connections_) std::move(entry.second)(entry.first, /*connection=*/nullptr, diff --git a/sharing/nearby_connections_manager_impl.h b/sharing/nearby_connections_manager_impl.h index 0de7d791..174f83f8 100644 --- a/sharing/nearby_connections_manager_impl.h +++ b/sharing/nearby_connections_manager_impl.h @@ -27,7 +27,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/strings/string_view.h" #include "internal/base/file_path.h" -#include "internal/platform/device_info.h" +#include "internal/platform/implementation/device_info.h" #include "internal/platform/mutex.h" #include "internal/platform/task_runner.h" #include "internal/platform/timer.h" @@ -49,7 +49,7 @@ class NearbyConnectionsManagerImpl : public NearbyConnectionsManager { explicit NearbyConnectionsManagerImpl( nearby::TaskRunner* connections_callback_task_runner, Context* context, nearby::ConnectivityManager& connectivity_manager, - nearby::DeviceInfo& device_info, + nearby::api::DeviceInfo& device_info, std::unique_ptr nearby_connections_service); ~NearbyConnectionsManagerImpl() override; NearbyConnectionsManagerImpl(const NearbyConnectionsManagerImpl&) = delete; @@ -143,10 +143,13 @@ class NearbyConnectionsManagerImpl : public NearbyConnectionsManager { void SendWithoutDelay(absl::string_view endpoint_id, std::unique_ptr payload); + void RemoveTransferManagerOnCallbackThread( + std::unique_ptr transfer_manager) const; + nearby::TaskRunner* const connections_callback_task_runner_; Context* const context_; nearby::ConnectivityManager& connectivity_manager_; - nearby::DeviceInfo& device_info_; + nearby::api::DeviceInfo& device_info_; // Nearby Connections Manager is called from different threads and may have // multiple calls to the class from one thread. To avoid deadlock and access diff --git a/sharing/nearby_connections_manager_impl_test.cc b/sharing/nearby_connections_manager_impl_test.cc index 2e46ec1f..f3c32490 100644 --- a/sharing/nearby_connections_manager_impl_test.cc +++ b/sharing/nearby_connections_manager_impl_test.cc @@ -33,7 +33,6 @@ #include "absl/strings/string_view.h" #include "absl/synchronization/notification.h" #include "absl/time/time.h" -#include "absl/types/optional.h" #include "absl/types/span.h" #include "internal/base/file_path.h" #include "internal/base/files.h" @@ -1037,7 +1036,7 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectClosedByRemote) { [&]() { close_notification.Notify(); }); Sync(); absl::Notification read_notification; - nearby_connection->Read([&](absl::optional> bytes) { + nearby_connection->Read([&](std::optional> bytes) { EXPECT_FALSE(bytes); read_notification.Notify(); }); @@ -1071,7 +1070,7 @@ TEST_F(NearbyConnectionsManagerImplTest, ConnectClosedByClient) { [&]() { close_notification.Notify(); }); Sync(); absl::Notification read_notification; - nearby_connection->Read([&](absl::optional> bytes) { + nearby_connection->Read([&](std::optional> bytes) { EXPECT_FALSE(bytes); read_notification.Notify(); }); diff --git a/sharing/nearby_connections_service_impl.cc b/sharing/nearby_connections_service_impl.cc index b0d3a89d..42a8ba75 100644 --- a/sharing/nearby_connections_service_impl.cc +++ b/sharing/nearby_connections_service_impl.cc @@ -23,6 +23,7 @@ #include #include +#include "location/nearby/analytics/cpp/logging/event_logger.h" #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" @@ -31,6 +32,7 @@ #include "connections/connection_options.h" #include "connections/core.h" #include "connections/discovery_options.h" +#include "connections/implementation/analytics/analytics_recorder_impl.h" #include "connections/implementation/service_controller_router.h" #include "connections/listeners.h" #include "connections/medium_selector.h" @@ -39,7 +41,6 @@ #include "connections/payload_type.h" #include "connections/status.h" #include "connections/strategy.h" -#include "internal/analytics/event_logger.h" #include "internal/platform/byte_array.h" #include "internal/platform/logging.h" #include "internal/platform/mac_address.h" @@ -51,6 +52,7 @@ namespace nearby { namespace sharing { namespace { +using ::nearby::analytics::AnalyticsRecorderImpl; using ::nearby::connections::ConnectionRequestInfo; using ::nearby::connections::ConnectionResponseInfo; using ::nearby::connections::Core; @@ -85,7 +87,8 @@ NearbyConnectionsServiceImpl::NearbyConnectionsServiceImpl( // at an invalid instance. return connectivity_manager_.IsHPRealtekDevice(); }); - static Core* core = new Core(event_logger, router); + static Core* core = + new Core(std::make_unique(event_logger), router); service_handle_ = core; } diff --git a/sharing/nearby_connections_service_impl.h b/sharing/nearby_connections_service_impl.h index cdcfcf30..76d34891 100644 --- a/sharing/nearby_connections_service_impl.h +++ b/sharing/nearby_connections_service_impl.h @@ -22,10 +22,10 @@ #include #include +#include "location/nearby/analytics/cpp/logging/event_logger.h" #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" -#include "internal/analytics/event_logger.h" #include "sharing/internal/public/connectivity_manager.h" #include "sharing/nearby_connections_service.h" #include "sharing/nearby_connections_types.h" diff --git a/sharing/nearby_sharing_service.h b/sharing/nearby_sharing_service.h index 8d1f8a1a..317b5a02 100644 --- a/sharing/nearby_sharing_service.h +++ b/sharing/nearby_sharing_service.h @@ -20,25 +20,23 @@ #include #include +#include "location/nearby/sharing/lib/sync/sync_manager.h" #include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "internal/platform/clock.h" #include "sharing/advertisement.h" #include "sharing/attachment_container.h" #include "sharing/certificates/nearby_share_certificate_manager.h" -#include "sharing/local_device_data/nearby_share_local_device_data_manager.h" #include "sharing/nearby_sharing_settings.h" +#include "sharing/outgoing_targets_manager.h" #include "sharing/share_target_discovered_callback.h" #include "sharing/transfer_update_callback.h" -namespace nearby { +namespace nearby::sharing { class AccountManager; - -namespace sharing { - class NearbyNotificationDelegate; -class NearbyShareContactManager; // This service implements Nearby Sharing on top of the Nearby Connections mojo. // Currently, only single profile will be allowed to be bound at a time and only @@ -143,28 +141,28 @@ class NearbySharingService { ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state, Advertisement::BlockedVendorId blocked_vendor_id, bool disable_wifi_hotspot, - std::function status_codes_callback) = 0; + absl::AnyInvocable status_codes_callback) = 0; // Unregisters the current send surface. virtual void UnregisterSendSurface( TransferUpdateCallback* transfer_callback, - std::function status_codes_callback) = 0; + absl::AnyInvocable status_codes_callback) = 0; // Registers a receiver surface for handling payload transfer status, and // advertises the vendor ID specified by |vendor_id|. virtual void RegisterReceiveSurface( TransferUpdateCallback* transfer_callback, ReceiveSurfaceState state, Advertisement::BlockedVendorId vendor_id, - std::function status_codes_callback) = 0; + absl::AnyInvocable status_codes_callback) = 0; // Unregisters the current receive surface. virtual void UnregisterReceiveSurface( TransferUpdateCallback* transfer_callback, - std::function status_codes_callback) = 0; + absl::AnyInvocable status_codes_callback) = 0; // Unregisters all foreground receive surfaces. virtual void ClearForegroundReceiveSurfaces( - std::function status_codes_callback) = 0; + absl::AnyInvocable status_codes_callback) = 0; // Returns true if there is an ongoing file transfer. virtual bool IsTransferring() const = 0; @@ -208,6 +206,12 @@ class NearbySharingService { int64_t share_target_id, std::function status_codes_callback) = 0; + virtual void InitiatePairing( + int64_t share_target_id, + service::proto::BindingRequest::Type binding_type, + absl::AnyInvocable + status_codes_callback) = 0; + // Checks to make sure visibility setting is valid and updates the service's // visibility if so. virtual void SetVisibility( @@ -218,16 +222,19 @@ class NearbySharingService { virtual void UpdateFilePathsInProgress(bool update_file_paths) = 0; virtual NearbyShareSettings* GetSettings() = 0; - virtual NearbyShareLocalDeviceDataManager* GetLocalDeviceDataManager() = 0; - virtual NearbyShareContactManager* GetContactManager() = 0; virtual NearbyShareCertificateManager* GetCertificateManager() = 0; virtual AccountManager* GetAccountManager() = 0; virtual Clock& GetClock() = 0; virtual void SetAlternateServiceUuidForDiscovery( uint16_t alternate_service_uuid) = 0; + virtual SyncManager& sync_manager() = 0; + virtual OutgoingTargetsManager& outgoing_targets_manager() = 0; + virtual void UpdateBackupSavePath( + absl::string_view binding_id, absl::string_view save_path, + absl::AnyInvocable + status_codes_callback) = 0; }; -} // namespace sharing -} // namespace nearby +} // namespace nearby::sharing #endif // THIRD_PARTY_NEARBY_SHARING_NEARBY_SHARING_SERVICE_H_ diff --git a/sharing/nearby_sharing_service_impl_test.cc b/sharing/nearby_sharing_service_impl_test.cc index a009f000..491a56ef 100644 --- a/sharing/nearby_sharing_service_impl_test.cc +++ b/sharing/nearby_sharing_service_impl_test.cc @@ -30,6 +30,11 @@ #include #include +#include "location/nearby/analytics/cpp/logging/mock_event_logger.h" +#include "location/nearby/sharing/lib/account/fake_account_manager.h" +#include "location/nearby/sharing/lib/account/mock_account_observer.h" +#include "location/nearby/sharing/lib/account/signin_attempt.h" +#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h" #include "location/nearby/sharing/lib/rpc/fake_nearby_share_client.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" @@ -44,18 +49,13 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "absl/types/span.h" -#include "internal/analytics/mock_event_logger.h" #include "internal/base/file_path.h" #include "internal/base/files.h" #include "internal/flags/nearby_flags.h" -#include "internal/platform/implementation/signin_attempt.h" -#include "internal/test/fake_account_manager.h" #include "internal/test/fake_device_info.h" #include "internal/test/fake_task_runner.h" -#include "internal/test/mock_account_observer.h" #include "sharing/advertisement.h" #include "sharing/advertisement_capabilities.h" -#include "sharing/analytics/analytics_recorder.h" #include "sharing/attachment_container.h" #include "sharing/certificates/fake_nearby_share_certificate_manager.h" #include "sharing/certificates/nearby_share_certificate_manager_impl.h" @@ -64,7 +64,6 @@ #include "sharing/common/nearby_share_enums.h" #include "sharing/common/nearby_share_prefs.h" #include "sharing/constants.h" -#include "sharing/contacts/fake_nearby_share_contact_manager.h" #include "sharing/fake_nearby_connections_manager.h" #include "sharing/fast_initiation/fake_nearby_fast_initiation.h" #include "sharing/fast_initiation/nearby_fast_initiation_impl.h" @@ -115,6 +114,7 @@ using ::nearby::sharing::service::proto::PairedKeyResultFrame; using ::nearby::sharing::service::proto::TextMetadata; using ::nearby::sharing::service::proto::V1Frame; using ::testing::_; +using ::protobuf_matchers::EqualsProto; using ::testing::InSequence; using ::testing::NiceMock; using ::testing::Return; @@ -429,7 +429,6 @@ class NearbySharingServiceImplTest : public testing::Test { auto fake_task_runner = std::make_unique(fake_context_.fake_clock(), 1); sharing_service_task_runner_ = fake_task_runner.get(); - contact_manager_ = new FakeNearbyShareContactManager(); fake_nearby_connections_manager_ = new FakeNearbyConnectionsManager(); connection_ = std::make_unique(fake_device_info_); fake_nearby_connections_manager_->set_send_payload_callback( @@ -453,7 +452,7 @@ class NearbySharingServiceImplTest : public testing::Test { SetBluetoothIsPowered(true); SetScreenLocked(false); SetLanConnected(true); - analytics_recorder_ = std::make_unique( + analytics_recorder_ = std::make_unique( /*vendor_id=*/0, /*event_logger=*/nullptr); service_ = CreateService(std::move(fake_task_runner)); @@ -484,9 +483,9 @@ class NearbySharingServiceImplTest : public testing::Test { std::unique_ptr task_runner) { return std::make_unique( std::move(task_runner), &fake_context_, mock_sharing_platform_, - &nearby_identity_client_, &nearby_share_client_, + &nearby_identity_client_, absl::WrapUnique(fake_nearby_connections_manager_), - absl::WrapUnique(contact_manager_), analytics_recorder_.get(), + analytics_recorder_.get(), /*supports_file_sync=*/false); } @@ -842,19 +841,22 @@ class NearbySharingServiceImplTest : public testing::Test { int64_t SetUpOutgoingShareTarget( MockTransferUpdateCallback& transfer_callback, - MockShareTargetDiscoveredCallback& discovery_callback) { + MockShareTargetDiscoveredCallback& discovery_callback, + bool for_self_share = false) { SetUpKeyVerification( /*is_incoming=*/false, PairedKeyResultFrame::SUCCESS); fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId, GetToken()); fake_nearby_connections_manager_->set_nearby_connection(connection_.get()); - return DiscoverShareTarget(transfer_callback, discovery_callback); + return DiscoverShareTarget(transfer_callback, discovery_callback, + for_self_share); } int64_t DiscoverShareTarget( MockTransferUpdateCallback& transfer_callback, - MockShareTargetDiscoveredCallback& discovery_callback) { + MockShareTargetDiscoveredCallback& discovery_callback, + bool for_self_share = false) { SetLanConnected(true); // Start discovering, to ensure a discovery listener is registered. @@ -876,7 +878,7 @@ class NearbySharingServiceImplTest : public testing::Test { std::move(endpoint_info)); FlushTesting(); ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1, - /*success=*/true); + /*success=*/true, for_self_share); return discovered_target_id; } @@ -1262,13 +1264,12 @@ class NearbySharingServiceImplTest : public testing::Test { FakeNearbyConnectionsManager* fake_nearby_connections_manager_ = nullptr; FakeNearbyShareLocalDeviceDataManager::Factory local_device_data_manager_factory_; - FakeNearbyShareContactManager* contact_manager_ = nullptr; FakeNearbyShareCertificateManager::Factory certificate_manager_factory_; std::unique_ptr nearby_fast_initiation_factory_; std::unique_ptr connection_; StrictMock* mock_app_info_ = nullptr; - std::unique_ptr analytics_recorder_; + std::unique_ptr analytics_recorder_; std::unique_ptr service_; int expect_transfer_updates_count_ = 0; std::function expect_transfer_updates_callback_; @@ -1280,7 +1281,6 @@ class NearbySharingServiceImplTest : public testing::Test { std::queue written_payloads_ ABSL_GUARDED_BY(connection_output_mutex_); FakeNearbyIdentityClient nearby_identity_client_; - FakeNearbyShareClient nearby_share_client_; }; struct ValidSendSurfaceTestData { @@ -1705,7 +1705,7 @@ TEST_F(NearbySharingServiceImplTest, ForegroundRegisterReceiveSurfaceIsAdvertisingAllContacts) { SetLanConnected(true); SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS); - ::nearby::AccountManager::Account account; + AccountManager::Account account; account.id = kTestAccountId; account_manager().SetAccount(account); local_device_data_manager()->SetDeviceName(kDeviceName); @@ -1759,7 +1759,7 @@ TEST_F(NearbySharingServiceImplTest, BackgroundRegisterReceiveSurfaceIsAdvertisingSelectedContacts) { SetLanConnected(true); SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_SELECTED_CONTACTS); - ::nearby::AccountManager::Account account; + AccountManager::Account account; account.id = kTestAccountId; account_manager().SetAccount(account); SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS); @@ -4852,8 +4852,8 @@ TEST_F(NearbySharingServiceImplTest, RemoveIncomingPayloads) { unknown_file_paths_to_delete, UnorderedElementsAre(FilePath("test1.txt"), FilePath("test2.txt"))); nearby::analytics::MockEventLogger mock_event_logger; - analytics::AnalyticsRecorder analytics_recorder{/*vendor_id=*/0, - &mock_event_logger}; + analytics::AnalyticsRecorderImpl analytics_recorder{/*vendor_id=*/0, + &mock_event_logger}; ShareTarget share_target; share_target.is_incoming = true; IncomingShareSession session( @@ -4883,7 +4883,7 @@ TEST_F(NearbySharingServiceImplTest, RemoveIncomingPayloads) { TEST_F(NearbySharingServiceImplTest, NotifyLogoutSucceededWithCredentialError) { TestObserver observer(service_.get()); - ::nearby::AccountManager::Account account; + AccountManager::Account account; account.id = kTestAccountId; account_manager().SetAccount(account); @@ -4897,5 +4897,205 @@ TEST_F(NearbySharingServiceImplTest, NotifyLogoutSucceededWithCredentialError) { FlushTesting(); } +TEST_F(NearbySharingServiceImplTest, InitiatePairingNotSelfShare) { + MockTransferUpdateCallback transfer_callback; + MockShareTargetDiscoveredCallback discovery_callback; + int64_t target_id = SetUpOutgoingShareTarget( + transfer_callback, discovery_callback, /*for_self_share=*/false); + ScopedSendSurface s(service_.get(), &transfer_callback); + + absl::Notification notification; + ExpectTransferUpdates(transfer_callback, target_id, + {TransferMetadata::Status::kConnecting, + TransferMetadata::Status::kDeviceAuthenticationFailed}, + [&] { notification.Notify(); }); + + absl::Notification pairing_notification; + NearbySharingServiceImpl::StatusCodes pairing_result; + EXPECT_CALL(*mock_app_info_, SetActiveFlag()); + service_->InitiatePairing( + target_id, service::proto::BindingRequest::FILESYNC, + [&](NearbySharingServiceImpl::StatusCodes status_code) { + pairing_result = status_code; + pairing_notification.Notify(); + }); + EXPECT_TRUE( + pairing_notification.WaitForNotificationWithTimeout(kTaskWaitTimeout)); + EXPECT_EQ(pairing_result, NearbySharingServiceImpl::StatusCodes::kOk); + + FlushTesting(); + // Verify data sent to the remote device so far. + EXPECT_TRUE(ExpectPairedKeyEncryptionFrame()); + EXPECT_TRUE(ExpectPairedKeyResultFrame()); + // Wait for the transfer updates. + EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout)); +} + +TEST_F(NearbySharingServiceImplTest, InitiatePairingBindingRpcFailed) { + MockTransferUpdateCallback transfer_callback; + MockShareTargetDiscoveredCallback discovery_callback; + int64_t target_id = SetUpOutgoingShareTarget( + transfer_callback, discovery_callback, /*for_self_share=*/true); + ScopedSendSurface s(service_.get(), &transfer_callback); + + absl::Notification notification; + ExpectTransferUpdates(transfer_callback, target_id, + {TransferMetadata::Status::kConnecting, + TransferMetadata::Status::kFailed}, + [&] { notification.Notify(); }); + + absl::Notification pairing_notification; + NearbySharingServiceImpl::StatusCodes pairing_result; + EXPECT_CALL(*mock_app_info_, SetActiveFlag()); + nearby_identity_client_.SetInitiateBindingResponses( + {absl::InternalError("Binding RPC failed")}); + service_->InitiatePairing( + target_id, service::proto::BindingRequest::FILESYNC, + [&](NearbySharingServiceImpl::StatusCodes status_code) { + pairing_result = status_code; + pairing_notification.Notify(); + }); + EXPECT_TRUE( + pairing_notification.WaitForNotificationWithTimeout(kTaskWaitTimeout)); + EXPECT_EQ(pairing_result, NearbySharingServiceImpl::StatusCodes::kOk); + + FlushTesting(); + // Verify data sent to the remote device so far. + EXPECT_TRUE(ExpectPairedKeyEncryptionFrame()); + EXPECT_TRUE(ExpectPairedKeyResultFrame()); + // Wait for the transfer updates. + EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout)); +} + +TEST_F(NearbySharingServiceImplTest, + InitiatePairingPeerBindingResponseTimeout) { + MockTransferUpdateCallback transfer_callback; + MockShareTargetDiscoveredCallback discovery_callback; + int64_t target_id = SetUpOutgoingShareTarget( + transfer_callback, discovery_callback, /*for_self_share=*/true); + ScopedSendSurface s(service_.get(), &transfer_callback); + absl::Notification notification; + ExpectTransferUpdates(transfer_callback, target_id, + {TransferMetadata::Status::kConnecting, + TransferMetadata::Status::kAwaitingRemoteAcceptance, + TransferMetadata::Status::kFailed}, + [&] { notification.Notify(); }); + + absl::Notification pairing_notification; + NearbySharingServiceImpl::StatusCodes pairing_result; + EXPECT_CALL(*mock_app_info_, SetActiveFlag()); + constexpr absl::string_view kBindingId = "binding_id"; + google::nearby::identity::v1::InitiateBindingResponse response; + response.set_binding_id(kBindingId); + nearby_identity_client_.SetInitiateBindingResponses({response}); + service_->InitiatePairing( + target_id, service::proto::BindingRequest::FILESYNC, + [&](NearbySharingServiceImpl::StatusCodes status_code) { + pairing_result = status_code; + pairing_notification.Notify(); + }); + EXPECT_TRUE( + pairing_notification.WaitForNotificationWithTimeout(kTaskWaitTimeout)); + EXPECT_EQ(pairing_result, NearbySharingServiceImpl::StatusCodes::kOk); + + FlushTesting(); + // Verify data sent to the remote device so far. + if (!ExpectPairedKeyEncryptionFrame()) { + return; + } + + if (!ExpectPairedKeyResultFrame()) { + return; + } + // Check BindingRequest frame sent to the remote device. + std::unique_ptr frame = GetWrittenFrame(); + ASSERT_TRUE(frame->has_v1()); + EXPECT_EQ(frame->v1().type(), service::proto::V1Frame::BINDINGS); + EXPECT_EQ(frame->v1().bindings().binding_request().binding_id(), kBindingId); + EXPECT_EQ(frame->v1().bindings().binding_request().type(), + service::proto::BindingRequest::FILESYNC); + + // BindingResponse frame timeout. + FastForward(absl::Seconds(60)); + // Wait for the transfer updates. + EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout)); +} + +TEST_F(NearbySharingServiceImplTest, InitiatePairingSuccess) { + MockTransferUpdateCallback transfer_callback; + MockShareTargetDiscoveredCallback discovery_callback; + int64_t target_id = SetUpOutgoingShareTarget( + transfer_callback, discovery_callback, /*for_self_share=*/true); + ScopedSendSurface s(service_.get(), &transfer_callback); + absl::Notification notification; + ExpectTransferUpdates(transfer_callback, target_id, + {TransferMetadata::Status::kConnecting, + TransferMetadata::Status::kAwaitingRemoteAcceptance, + TransferMetadata::Status::kComplete}, + [&] { notification.Notify(); }); + + absl::Notification pairing_notification; + NearbySharingServiceImpl::StatusCodes pairing_result; + EXPECT_CALL(*mock_app_info_, SetActiveFlag()); + constexpr absl::string_view kBindingId = "binding_id"; + google::nearby::identity::v1::InitiateBindingResponse response; + response.set_binding_id(kBindingId); + nearby_identity_client_.SetInitiateBindingResponses({response}); + service_->InitiatePairing( + target_id, service::proto::BindingRequest::FILESYNC, + [&](NearbySharingServiceImpl::StatusCodes status_code) { + pairing_result = status_code; + pairing_notification.Notify(); + }); + EXPECT_TRUE( + pairing_notification.WaitForNotificationWithTimeout(kTaskWaitTimeout)); + EXPECT_EQ(pairing_result, NearbySharingServiceImpl::StatusCodes::kOk); + + FlushTesting(); + // Verify data sent to the remote device so far. + EXPECT_TRUE(ExpectPairedKeyEncryptionFrame()); + EXPECT_TRUE(ExpectPairedKeyResultFrame()); + + // Check BindingRequest frame sent to the remote device. + std::unique_ptr frame = GetWrittenFrame(); + ASSERT_TRUE(frame->has_v1()); + EXPECT_EQ(frame->v1().type(), service::proto::V1Frame::BINDINGS); + EXPECT_EQ(frame->v1().bindings().binding_request().binding_id(), kBindingId); + EXPECT_EQ(frame->v1().bindings().binding_request().type(), + service::proto::BindingRequest::FILESYNC); + + preference_manager_.SetString(PrefNames::kCustomSavePath, "Downloads"); + Frame binding_response_frame; + binding_response_frame.set_version(Frame::V1); + binding_response_frame.mutable_v1()->set_type( + service::proto::V1Frame::BINDINGS); + binding_response_frame.mutable_v1() + ->mutable_bindings() + ->mutable_binding_response() + ->set_status(service::proto::BindingResponse::SUCCESS); + std::vector result_bytes(binding_response_frame.ByteSizeLong()); + binding_response_frame.SerializeToArray(result_bytes.data(), + result_bytes.size()); + ReceiveMessageFromConnection(std::move(result_bytes)); + + // Verify that connection is closed. + EXPECT_FALSE( + fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId) + .has_value()); + + std::optional binding = + preference_manager_.GetSyncBindingValue(); + ASSERT_TRUE(binding.has_value()); + EXPECT_EQ(binding->sync_bindings().size(), 1); + sync::SyncBinding expected_binding; + expected_binding.set_binding_id(kBindingId); + expected_binding.set_source_name(kDeviceName); + expected_binding.set_destination_directory( + FilePath("Downloads").append(FilePath(kDeviceName)).ToString()); + expected_binding.set_source_device_type( + sync::SyncBinding::SOURCE_DEVICE_TYPE_PHONE); + EXPECT_THAT(binding->sync_bindings(0), EqualsProto(expected_binding)); +} + } // namespace NearbySharingServiceUnitTests } // namespace nearby::sharing diff --git a/sharing/nearby_sharing_settings.cc b/sharing/nearby_sharing_settings.cc index 9a189aed..8d915aa9 100644 --- a/sharing/nearby_sharing_settings.cc +++ b/sharing/nearby_sharing_settings.cc @@ -22,17 +22,18 @@ #include #include +#include "absl/base/nullability.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "internal/platform/clock.h" -#include "internal/platform/device_info.h" +#include "internal/platform/implementation/device_info.h" +#include "internal/platform/task_runner.h" #include "proto/sharing_enums.pb.h" #include "sharing/analytics/analytics_recorder.h" #include "sharing/common/nearby_share_enums.h" #include "sharing/common/nearby_share_prefs.h" #include "sharing/internal/api/preference_manager.h" -#include "sharing/internal/public/context.h" #include "sharing/internal/public/logging.h" #include "sharing/internal/public/pref_names.h" #include "sharing/local_device_data/nearby_share_local_device_data_manager.h" @@ -48,6 +49,7 @@ using ::nearby::sharing::api::PreferenceManager; using ::nearby::sharing::proto::DataUsage; using ::nearby::sharing::proto::DeviceVisibility; using ::nearby::sharing::proto::FastInitiationNotificationState; +using ::nearby::sharing::sync::SyncBindingPrefs; constexpr absl::string_view kPreferencesObserverName = "nearby-sharing-settings"; @@ -69,12 +71,12 @@ ShowNotificationStatus GetNotificationStatus( } // namespace NearbyShareSettings::NearbyShareSettings( - Context* context, nearby::Clock* clock, nearby::DeviceInfo& device_info, - PreferenceManager& preference_manager, + TaskRunner* absl_nonnull task_runner, nearby::Clock* absl_nonnull clock, + nearby::api::DeviceInfo& device_info, PreferenceManager& preference_manager, NearbyShareLocalDeviceDataManager* local_device_data_manager, analytics::AnalyticsRecorder* analytics_recorder) - : context_(context), - clock_(clock), + : task_runner_(*task_runner), + clock_(*clock), device_info_(device_info), preference_manager_(preference_manager), local_device_data_manager_(local_device_data_manager), @@ -142,7 +144,7 @@ void NearbyShareSettings::StartVisibilityTimer( LOG(INFO) << __func__ << ": start visibility timer. expiration=" << expiration; visibility_expiration_timer_ = std::make_unique( - *context_->GetTaskRunner(), "nearby_share_settings_visibility_timer", + task_runner_, "nearby_share_settings_visibility_timer", expiration, [this]() { LOG(INFO) << __func__ << ": visibility timer expired."; proto::DeviceVisibility visibility; @@ -163,7 +165,7 @@ void NearbyShareSettings::RestoreFallbackVisibility() { static_cast(prefs::kDefaultFallbackVisibility)); fallback_visibility_ = static_cast(fallback_visibility); - int64_t now_seconds = absl::ToUnixSeconds(clock_->Now()); + int64_t now_seconds = absl::ToUnixSeconds(clock_.Now()); int64_t remaining_seconds = expiration_seconds - now_seconds; int64_t diff = kMaxVisibilityExpirationSeconds - remaining_seconds; LOG(INFO) << __func__ << ": diff=" << diff << ", now=" << now_seconds @@ -186,6 +188,16 @@ std::string NearbyShareSettings::GetCustomSavePath() const { PrefNames::kCustomSavePath, device_info_.GetDownloadPath().ToString()); } +SyncBindingPrefs NearbyShareSettings::GetSyncBindingPrefs() const { + return preference_manager_.GetSyncBindingValue().value_or( + SyncBindingPrefs()); +} + +void NearbyShareSettings::SetSyncBindingPrefs( + const SyncBindingPrefs& prefs) { + preference_manager_.SetSyncBindingValue(prefs); +} + bool NearbyShareSettings::IsDisabledByPolicy() const { return false; } void NearbyShareSettings::AddSettingsObserver(Observer* observer) { @@ -265,7 +277,7 @@ void NearbyShareSettings::SetVisibility(DeviceVisibility visibility, visibility_expiration_timer_.reset(); SetFallbackVisibility(last_visibility); - absl::Time now = clock_->Now(); + absl::Time now = clock_.Now(); if (expiration != absl::ZeroDuration()) { VLOG(1) << __func__ << ": temporary visibility timer starts."; absl::Time fallback_visibility_timestamp = now + expiration; diff --git a/sharing/nearby_sharing_settings.h b/sharing/nearby_sharing_settings.h index 09fa7016..8e40847e 100644 --- a/sharing/nearby_sharing_settings.h +++ b/sharing/nearby_sharing_settings.h @@ -22,18 +22,20 @@ #include #include +#include "location/nearby/sharing/lib/sync/sync_binding_prefs.pb.h" +#include "absl/base/nullability.h" #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "internal/base/observer_list.h" #include "internal/platform/clock.h" -#include "internal/platform/device_info.h" +#include "internal/platform/implementation/device_info.h" +#include "internal/platform/task_runner.h" #include "proto/sharing_enums.pb.h" #include "sharing/analytics/analytics_recorder.h" #include "sharing/common/nearby_share_enums.h" #include "sharing/internal/api/preference_manager.h" -#include "sharing/internal/public/context.h" #include "sharing/internal/public/logging.h" #include "sharing/local_device_data/nearby_share_local_device_data_manager.h" #include "sharing/proto/settings_observer_data.pb.h" @@ -138,7 +140,8 @@ class NearbyShareSettings }; NearbyShareSettings( - Context* context, nearby::Clock* clock, nearby::DeviceInfo& device_info, + TaskRunner* absl_nonnull task_runner, nearby::Clock* absl_nonnull clock, + nearby::api::DeviceInfo& device_info, nearby::sharing::api::PreferenceManager& preference_manager, NearbyShareLocalDeviceDataManager* local_device_data_manager, analytics::AnalyticsRecorder* analytics_recorder = nullptr); @@ -160,6 +163,10 @@ class NearbyShareSettings std::string GetCustomSavePath() const; + nearby::sharing::sync::SyncBindingPrefs GetSyncBindingPrefs() const; + void SetSyncBindingPrefs( + const nearby::sharing::sync::SyncBindingPrefs& prefs); + // Returns true if the feature is disabled by policy. bool IsDisabledByPolicy() const; @@ -218,9 +225,9 @@ class NearbyShareSettings // Make sure thread safe to access Nearby settings mutable absl::Mutex mutex_; - Context* context_; - nearby::Clock* const clock_; - nearby::DeviceInfo& device_info_; + TaskRunner& task_runner_; + nearby::Clock& clock_; + nearby::api::DeviceInfo& device_info_; nearby::sharing::api::PreferenceManager& preference_manager_; NearbyShareLocalDeviceDataManager* const local_device_data_manager_; // Used to create analytics events. diff --git a/sharing/nearby_sharing_settings_test.cc b/sharing/nearby_sharing_settings_test.cc index 531e4ed7..4e6f029f 100644 --- a/sharing/nearby_sharing_settings_test.cc +++ b/sharing/nearby_sharing_settings_test.cc @@ -19,6 +19,8 @@ #include #include +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" @@ -27,12 +29,12 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "internal/base/files.h" +#include "internal/test/fake_clock.h" #include "internal/test/fake_device_info.h" #include "internal/test/fake_task_runner.h" #include "sharing/common/nearby_share_enums.h" #include "sharing/common/nearby_share_prefs.h" #include "sharing/internal/public/pref_names.h" -#include "sharing/internal/test/fake_context.h" #include "sharing/internal/test/fake_preference_manager.h" #include "sharing/local_device_data/fake_nearby_share_local_device_data_manager.h" #include "sharing/proto/enums.pb.h" @@ -43,6 +45,7 @@ namespace { using ::nearby::sharing::proto::DataUsage; using ::nearby::sharing::proto::DeviceVisibility; using ::nearby::sharing::proto::FastInitiationNotificationState; +using ::protobuf_matchers::EqualsProto; constexpr char kDefaultDeviceName[] = "Josh's Chromebook"; @@ -117,11 +120,12 @@ class FakeNearbyShareSettingsObserver : public NearbyShareSettings::Observer { class NearbyShareSettingsTest : public ::testing::Test { public: NearbyShareSettingsTest() - : local_device_data_manager_(kDefaultDeviceName) { + : local_device_data_manager_(kDefaultDeviceName), + fake_task_runner_(&fake_clock_, /*count=*/1) { prefs::RegisterNearbySharingPrefs(preference_manager_); nearby_share_settings_ = std::make_unique( - &context_, context_.GetClock(), fake_device_info_, preference_manager_, - &local_device_data_manager_); + &fake_task_runner_, &fake_clock_, fake_device_info_, + preference_manager_, &local_device_data_manager_); nearby_share_settings_->AddSettingsObserver(&observer_); } @@ -144,11 +148,11 @@ class NearbyShareSettingsTest : public ::testing::Test { // Waits for running tasks to complete. void Flush() { absl::SleepFor(absl::Seconds(1)); - context_.fake_task_runner()->SyncWithTimeout(absl::Milliseconds(200)); + fake_task_runner_.SyncWithTimeout(absl::Milliseconds(200)); } void FastForward(absl::Duration duration) { - context_.fake_clock()->FastForward(duration); + fake_clock_.FastForward(duration); } bool Contains(std::vector v, std::string val) { @@ -161,8 +165,9 @@ class NearbyShareSettingsTest : public ::testing::Test { protected: nearby::FakeDeviceInfo fake_device_info_; nearby::FakePreferenceManager preference_manager_; - FakeContext context_; FakeNearbyShareLocalDeviceDataManager local_device_data_manager_; + FakeClock fake_clock_; + FakeTaskRunner fake_task_runner_; FakeNearbyShareSettingsObserver observer_; std::unique_ptr nearby_share_settings_; }; @@ -298,7 +303,7 @@ TEST_F(NearbyShareSettingsTest, // Set our initial visibility to self share. settings()->SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE); // Set everyone mode temporarily. - absl::Time now = context_.GetClock()->Now(); + absl::Time now = fake_clock_.Now(); settings()->SetVisibility( DeviceVisibility::DEVICE_VISIBILITY_EVERYONE, absl::Seconds(prefs::kDefaultMaxVisibilityExpirationSeconds)); @@ -354,7 +359,7 @@ TEST_F(NearbyShareSettingsTest, TemporaryVisibilityIsCorrect) { DeviceVisibility::DEVICE_VISIBILITY_UNSPECIFIED); EXPECT_EQ(fallback_visibility.fallback_time, absl::UnixEpoch()); // Transition to temporary everyone mode. - absl::Time now = context_.GetClock()->Now(); + absl::Time now = fake_clock_.Now(); settings()->SetVisibility( DeviceVisibility::DEVICE_VISIBILITY_EVERYONE, absl::Seconds(prefs::kDefaultMaxVisibilityExpirationSeconds)); @@ -375,7 +380,7 @@ TEST_F(NearbyShareSettingsTest, SetVisibilityWithExpirationTooLong) { absl::Hours(1)); // Expiration capped at 10minutes. absl::Time expected_fallback_time = - context_.GetClock()->Now() + absl::Minutes(10); + fake_clock_.Now() + absl::Minutes(10); NearbyShareSettings::FallbackVisibilityInfo fallback_visibility = settings()->GetFallbackVisibility(); // default visibility was hidden. @@ -386,9 +391,39 @@ TEST_F(NearbyShareSettingsTest, SetVisibilityWithExpirationTooLong) { EXPECT_LT(absl::AbsDuration(time_diff), absl::Seconds(1)); } +TEST_F(NearbyShareSettingsTest, GetSyncBindingPrefs_NoBindings) { + EXPECT_THAT(settings()->GetSyncBindingPrefs(), + EqualsProto(sync::SyncBindingPrefs::default_instance())); +} + +TEST_F(NearbyShareSettingsTest, GetSyncBindingPerfs_Success) { + sync::SyncBindingPrefs sync_binding_prefs; + sync_binding_prefs.add_sync_bindings()->set_binding_id("binding_id"); + sync_binding_prefs.add_sync_bindings()->set_source_name("source_name"); + sync_binding_prefs.add_sync_bindings()->set_destination_directory( + "destination_name"); + preference_manager_.SetSyncBindingValue(sync_binding_prefs); + EXPECT_THAT(settings()->GetSyncBindingPrefs(), + EqualsProto(sync_binding_prefs)); +} + +TEST_F(NearbyShareSettingsTest, SetSyncBindingPerfs_Success) { + sync::SyncBindingPrefs sync_binding_prefs; + sync_binding_prefs.add_sync_bindings()->set_binding_id("binding_id"); + sync_binding_prefs.add_sync_bindings()->set_source_name("source_name"); + sync_binding_prefs.add_sync_bindings()->set_destination_directory( + "destination_name"); + settings()->SetSyncBindingPrefs(sync_binding_prefs); + auto sync_binding_value = preference_manager_.GetSyncBindingValue(); + ASSERT_TRUE(sync_binding_value.has_value()); + EXPECT_THAT(sync_binding_value.value(), + EqualsProto(sync_binding_prefs)); +} + TEST(NearbyShareVisibilityTest, RestoresFallbackVisibility_ExpiredTimer) { // Create Nearby Share settings dependencies. - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner fake_task_runner(&fake_clock, /*count=*/1); FakeDeviceInfo fake_device_info; FakePreferenceManager preference_manager; FakeNearbyShareLocalDeviceDataManager local_device_data_manager( @@ -400,13 +435,13 @@ TEST(NearbyShareVisibilityTest, RestoresFallbackVisibility_ExpiredTimer) { // Set expiration to 10 seconds ago. preference_manager.SetInteger( PrefNames::kVisibilityExpirationSeconds, - absl::ToUnixSeconds(context.GetClock()->Now() - absl::Seconds(10))); + absl::ToUnixSeconds(fake_clock.Now() - absl::Seconds(10))); // Set fallback visibility to self share. preference_manager.SetInteger( PrefNames::kFallbackVisibility, static_cast(DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE)); // Create a Nearby Share settings instance. - NearbyShareSettings settings(&context, context.GetClock(), fake_device_info, + NearbyShareSettings settings(&fake_task_runner, &fake_clock, fake_device_info, preference_manager, &local_device_data_manager); // Make sure we restore the correct visibility. @@ -416,7 +451,8 @@ TEST(NearbyShareVisibilityTest, RestoresFallbackVisibility_ExpiredTimer) { TEST(NearbyShareVisibilityTest, RestoresFallbackVisibility_FutureTimer) { // Create Nearby Share settings dependencies. - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner fake_task_runner(&fake_clock, /*count=*/1); FakeDeviceInfo fake_device_info; FakePreferenceManager preference_manager; FakeNearbyShareLocalDeviceDataManager local_device_data_manager( @@ -428,13 +464,13 @@ TEST(NearbyShareVisibilityTest, RestoresFallbackVisibility_FutureTimer) { // Set expiration to 10 seconds in the future. preference_manager.SetInteger( PrefNames::kVisibilityExpirationSeconds, - absl::ToUnixSeconds(context.GetClock()->Now() + absl::Seconds(10))); + absl::ToUnixSeconds(fake_clock.Now() + absl::Seconds(10))); // Set fallback visibility to self share. preference_manager.SetInteger( PrefNames::kFallbackVisibility, static_cast(DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE)); // Create a Nearby Share settings instance. - NearbyShareSettings settings(&context, context.GetClock(), fake_device_info, + NearbyShareSettings settings(&fake_task_runner, &fake_clock, fake_device_info, preference_manager, &local_device_data_manager); // Make sure we restore the correct visibility. diff --git a/sharing/nearby_sharing_util.cc b/sharing/nearby_sharing_util.cc index 1fed0e12..06c38de2 100644 --- a/sharing/nearby_sharing_util.cc +++ b/sharing/nearby_sharing_util.cc @@ -14,10 +14,7 @@ #include "sharing/nearby_sharing_util.h" -#include #include -#include -#include #include #include #include @@ -26,8 +23,6 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "internal/base/file_path.h" -#include "internal/platform/device_info.h" #include "proto/sharing_enums.pb.h" #include "sharing/advertisement.h" #include "sharing/certificates/nearby_share_decrypted_public_certificate.h" @@ -115,16 +110,4 @@ std::string GetDeviceId( return std::string(endpoint_id); } -bool IsOutOfStorage(DeviceInfo& device_info, FilePath file_path, - int64_t storage_required) { - std::optional available_storage = - device_info.GetAvailableDiskSpaceInBytes(file_path); - - if (!available_storage.has_value()) { - return false; - } - - return *available_storage <= storage_required; -} - } // namespace nearby::sharing diff --git a/sharing/nearby_sharing_util.h b/sharing/nearby_sharing_util.h index bcc4c90d..d2b2df59 100644 --- a/sharing/nearby_sharing_util.h +++ b/sharing/nearby_sharing_util.h @@ -21,23 +21,13 @@ #include #include "absl/strings/string_view.h" -#include "internal/platform/device_info.h" #include "proto/sharing_enums.pb.h" -#include "internal/base/file_path.h" #include "sharing/advertisement.h" #include "sharing/certificates/nearby_share_decrypted_public_certificate.h" #include "sharing/common/nearby_share_enums.h" namespace nearby::sharing { -// Checks whether having enough disk space for required storage. -// -// device_info - Nearby Share DeviceInfo -// file_path - The path is to store sharing contents. -// storage_required - required storage space. -bool IsOutOfStorage(nearby::DeviceInfo& device_info, FilePath file_path, - int64_t storage_required); - // Decodes certificate to find MAC address encoded in it. std::optional> GetBluetoothMacAddressFromCertificate( const NearbyShareDecryptedPublicCertificate& certificate); diff --git a/sharing/outgoing_share_session.cc b/sharing/outgoing_share_session.cc index 2522d02a..7b9b52a9 100644 --- a/sharing/outgoing_share_session.cc +++ b/sharing/outgoing_share_session.cc @@ -40,9 +40,10 @@ #include "sharing/nearby_connections_manager.h" #include "sharing/nearby_connections_types.h" #include "sharing/nearby_sharing_util.h" -#include "sharing/paired_key_verification_runner.h" #include "sharing/payload_tracker.h" +#include "sharing/proto/wire_format.pb.h" #include "sharing/share_session.h" +#include "sharing/share_session_usage.h" #include "sharing/share_target.h" #include "sharing/text_attachment.h" #include "sharing/thread_timer.h" @@ -56,6 +57,8 @@ namespace { using ::location::nearby::proto::sharing::ConnectionLayerStatus; using ::location::nearby::proto::sharing::EstablishConnectionStatus; using ::nearby::sharing::proto::DataUsage; +using ::nearby::sharing::service::proto::BindingRequest; +using ::nearby::sharing::service::proto::BindingResponse; using ::nearby::sharing::service::proto::ConnectionResponseFrame; using ::nearby::sharing::service::proto::Frame; using ::nearby::sharing::service::proto::IntroductionFrame; @@ -151,6 +154,7 @@ void OutgoingShareSession::InvokeTransferUpdateCallback( bool OutgoingShareSession::InitiateSendAttachments( std::unique_ptr attachment_container) { SetAttachmentContainer(std::move(*attachment_container)); + is_transfer_session_ = true; is_connecting_ = true; // Set session ID. @@ -182,6 +186,7 @@ bool OutgoingShareSession::InitiateSendAttachments( "create payloads."; UpdateTransferMetadata( TransferMetadataBuilder() + .set_usage(session_usage()) .set_status(TransferMetadata::Status::kMediaUnavailable) .build()); } @@ -316,7 +321,8 @@ bool OutgoingShareSession::FillIntroductionFrame( } bool OutgoingShareSession::AcceptTransfer( - std::function)> + std::function)> response_callback) { if (!IsConnected()) { LOG(WARNING) << "Accept invoked for unconnected share target"; @@ -330,6 +336,7 @@ bool OutgoingShareSession::AcceptTransfer( // Wait for remote accept in response frame. UpdateTransferMetadata( TransferMetadataBuilder() + .set_usage(session_usage()) .set_token(token()) .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance) .build()); @@ -339,10 +346,10 @@ bool OutgoingShareSession::AcceptTransfer( [callback = std::move(response_callback)](bool is_timeout, std::optional frame) { if (!frame.has_value()) { - callback(std::nullopt); + callback(is_timeout, std::nullopt); return; } - callback(frame->connection_response()); + callback(is_timeout, frame->connection_response()); }, kReadResponseFrameTimeout); return true; @@ -404,6 +411,7 @@ void OutgoingShareSession::SendAttachmentsCompleted( bool OutgoingShareSession::SendIntroduction( std::function timeout_callback) { + set_session_usage(ShareSessionUsage::kSharing); Frame frame; frame.set_version(Frame::V1); V1Frame* v1_frame = frame.mutable_v1(); @@ -429,14 +437,15 @@ bool OutgoingShareSession::SendIntroduction( std::optional OutgoingShareSession::HandleConnectionResponse( - std::optional response) { + bool is_timeout, std::optional response) { // Stop accept timer. mutual_acceptance_timeout_.reset(); if (!response.has_value()) { LOG(WARNING) << "Failed to read a response from the remote device. Disconnecting."; - return TransferMetadata::Status::kFailed; + return is_timeout ? TransferMetadata::Status::kTimedOut + : TransferMetadata::Status::kFailed; } VLOG(1) << "Successfully read the connection response frame."; @@ -445,6 +454,7 @@ OutgoingShareSession::HandleConnectionResponse( case ConnectionResponseFrame::ACCEPT: { UpdateTransferMetadata( TransferMetadataBuilder() + .set_usage(session_usage()) .set_status(TransferMetadata::Status::kInProgress) .build()); return std::nullopt; @@ -546,6 +556,7 @@ void OutgoingShareSession::Connect( // Send process initialized successfully, from now on status updated // will be sent out via TransferUpdates. UpdateTransferMetadata(TransferMetadataBuilder() + .set_usage(session_usage()) .set_status(TransferMetadata::Status::kConnecting) .build()); connection_start_time_ = clock().Now(); @@ -622,12 +633,55 @@ OutgoingShareSession::ProcessPayloadTransferUpdates() { return std::nullopt; } - std::optional metadata; + std::optional metadata_builder; for (; !updates.empty(); updates.pop()) { - metadata = + metadata_builder = get_payload_tracker()->ProcessPayloadUpdate(std::move(updates.front())); } - return metadata; + return metadata_builder.has_value() + ? std::make_optional( + metadata_builder->set_usage(session_usage()).build()) + : std::nullopt; +} + +void OutgoingShareSession::StartPeerBinding( + std::string binding_id, BindingRequest::Type binding_type, + absl::AnyInvocable callback) { + Frame frame; + frame.set_version(Frame::V1); + V1Frame* v1_frame = frame.mutable_v1(); + v1_frame->set_type(V1Frame::BINDINGS); + BindingRequest* binding_request = + v1_frame->mutable_bindings()->mutable_binding_request(); + binding_request->set_binding_id(binding_id); + binding_request->set_type(binding_type); + WriteFrame(frame); + LOG(INFO) << "Waiting for bindings response frame from " << share_target().id; + UpdateTransferMetadata( + TransferMetadataBuilder() + .set_usage(session_usage()) + .set_token(token()) + .set_status(TransferMetadata::Status::kAwaitingRemoteAcceptance) + .build()); + frames_reader()->ReadFrame( + nearby::sharing::service::proto::V1Frame::BINDINGS, + [callback = std::move(callback)]( + bool is_timeout, std::optional frame) mutable { + if (!frame.has_value()) { + std::move(callback)(BindingResponse::FAILURE); + return; + } + if (!frame->has_bindings() || + !frame->bindings().has_binding_response() || + frame->bindings().binding_response().status() != + BindingResponse::SUCCESS) { + std::move(callback)(BindingResponse::FAILURE); + return; + } + // Peer binding flow completed successfully. + std::move(callback)(BindingResponse::SUCCESS); + }, + kReadResponseFrameTimeout); } } // namespace nearby::sharing diff --git a/sharing/outgoing_share_session.h b/sharing/outgoing_share_session.h index 21b8b8e6..fb28496a 100644 --- a/sharing/outgoing_share_session.h +++ b/sharing/outgoing_share_session.h @@ -34,7 +34,6 @@ #include "sharing/nearby_connection.h" #include "sharing/nearby_connections_manager.h" #include "sharing/nearby_connections_types.h" -#include "sharing/paired_key_verification_runner.h" #include "sharing/proto/enums.pb.h" #include "sharing/share_session.h" #include "sharing/share_target.h" @@ -81,14 +80,16 @@ class OutgoingShareSession : public ShareSession { // ConnectionResponseFrame. bool AcceptTransfer( std::function< - void(std::optional< - nearby::sharing::service::proto::ConnectionResponseFrame>)> + void(bool is_timeout, + std::optional< + nearby::sharing::service::proto::ConnectionResponseFrame>)> response_callback); // Process the ConnectionResponseFrame. // On success, returns std::nullopt. // On failure, returns the status if the connection should be aborted. std::optional HandleConnectionResponse( + bool is_timeout, std::optional response); @@ -159,6 +160,21 @@ class OutgoingShareSession : public ShareSession { const std::vector& file_payloads() const { return file_payloads_; } + // Returns true if the session is a transfer session. + // Otherwise, it is a pairing session. + bool is_transfer_session() const { return is_transfer_session_; } + + // Initiates the peer binding message exchange with the remote device. + // `binding_id` is the result of a successful call to InitiateBinding rpc. + // `callback` is called when either a BindingResponse frame is received or a + // timeout occurs. + void StartPeerBinding( + std::string binding_id, + nearby::sharing::service::proto::BindingRequest::Type binding_type, + absl::AnyInvocable< + void(nearby::sharing::service::proto::BindingResponse::Status)> + callback); + protected: void InvokeTransferUpdateCallback(const TransferMetadata& metadata) override; void OnConnectionDisconnected() override; @@ -196,6 +212,8 @@ class OutgoingShareSession : public ShareSession { bool advanced_protection_enabled_ = false; bool advanced_protection_mismatch_ = false; bool is_connecting_ = false; + // Session can be for transfer or pairing. + bool is_transfer_session_ = false; }; } // namespace nearby::sharing diff --git a/sharing/outgoing_share_session_test.cc b/sharing/outgoing_share_session_test.cc index 983fc8fb..21b01d6c 100644 --- a/sharing/outgoing_share_session_test.cc +++ b/sharing/outgoing_share_session_test.cc @@ -22,20 +22,23 @@ #include #include +#include "location/nearby/analytics/cpp/logging/mock_event_logger.h" +#include "location/nearby/analytics/cpp/logging/sharing_log_matchers.h" +#include "location/nearby/analytics/cpp/proto/nearby_sharing_log.pb.h" +#include "location/nearby/analytics/cpp/proto/nearby_sharing_log.proto.static_reflection.h" +#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h" +#include "net/proto2/contrib/parse_proto/parse_text_proto.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "internal/analytics/mock_event_logger.h" -#include "internal/analytics/sharing_log_matchers.h" #include "internal/base/file_path.h" #include "internal/base/files.h" #include "internal/network/url.h" #include "internal/test/fake_clock.h" #include "internal/test/fake_device_info.h" #include "internal/test/fake_task_runner.h" -#include "sharing/analytics/analytics_recorder.h" #include "sharing/attachment_container.h" #include "sharing/certificates/test_util.h" #include "sharing/common/nearby_share_enums.h" @@ -45,10 +48,8 @@ #include "sharing/nearby_connection_impl.h" #include "sharing/nearby_connections_manager.h" #include "sharing/nearby_connections_types.h" -#include "sharing/paired_key_verification_runner.h" -#include "sharing/proto/analytics/nearby_sharing_log.pb.h" -#include "sharing/proto/analytics/nearby_sharing_log.proto.static_reflection.h" #include "sharing/proto/wire_format.pb.h" +#include "sharing/share_session_usage.h" #include "sharing/share_target.h" #include "sharing/text_attachment.h" #include "sharing/transfer_metadata.h" @@ -61,10 +62,11 @@ namespace { using ::location::nearby::proto::sharing::EstablishConnectionStatus; using ::location::nearby::proto::sharing::EventCategory; using ::location::nearby::proto::sharing::EventType; -using ::location::nearby::proto::sharing::OSType; using ::nearby::analytics::HasCategory; using ::nearby::analytics::HasEventType; using ::nearby::sharing::analytics::proto::SharingLog; +using ::nearby::sharing::service::proto::BindingRequest; +using ::nearby::sharing::service::proto::BindingResponse; using ::nearby::sharing::service::proto::ConnectionResponseFrame; using ::nearby::sharing::service::proto::Frame; using ::nearby::sharing::service::proto::IntroductionFrame; @@ -73,6 +75,7 @@ using ::nearby::sharing::service::proto::WifiCredentials; using ::testing::_; using ::testing::AllOf; using ::testing::Eq; +using ::protobuf_matchers::EqualsProto; using ::testing::InSequence; using ::testing::IsEmpty; using ::testing::IsFalse; @@ -159,8 +162,8 @@ class OutgoingShareSessionTest : public ::testing::Test { FakeClock fake_clock_; FakeTaskRunner fake_task_runner_{&fake_clock_, 1}; nearby::analytics::MockEventLogger mock_event_logger_; - analytics::AnalyticsRecorder analytics_recorder_{/*vendor_id=*/0, - &mock_event_logger_}; + analytics::AnalyticsRecorderImpl analytics_recorder_{/*vendor_id=*/0, + &mock_event_logger_}; ShareTarget share_target_; MockFunction transfer_metadata_callback_; @@ -507,7 +510,7 @@ TEST_F(OutgoingShareSessionTest, SendIntroductionTimeoutCancelled) { Call(_, HasStatus(TransferMetadata::Status::kInProgress))); std::optional status = - session_.HandleConnectionResponse(response); + session_.HandleConnectionResponse(/*is_timeout=*/false, response); EXPECT_THAT(status.has_value(), IsFalse()); fake_clock_.FastForward(absl::Seconds(60)); @@ -517,9 +520,9 @@ TEST_F(OutgoingShareSessionTest, SendIntroductionTimeoutCancelled) { } TEST_F(OutgoingShareSessionTest, AcceptTransferNotConnected) { - EXPECT_THAT( - session_.AcceptTransfer([](std::optional) {}), - IsFalse()); + EXPECT_THAT(session_.AcceptTransfer( + [](bool, std::optional) {}), + IsFalse()); } TEST_F(OutgoingShareSessionTest, AcceptTransferNotReady) { @@ -527,9 +530,9 @@ TEST_F(OutgoingShareSessionTest, AcceptTransferNotReady) { session_.set_session_id(1234); ConnectionSuccess(&connection); - EXPECT_THAT( - session_.AcceptTransfer([](std::optional) {}), - IsFalse()); + EXPECT_THAT(session_.AcceptTransfer( + [](bool, std::optional) {}), + IsFalse()); } TEST_F(OutgoingShareSessionTest, AcceptTransferSuccess) { @@ -553,12 +556,12 @@ TEST_F(OutgoingShareSessionTest, AcceptTransferSuccess) { Call(_, HasStatus(TransferMetadata::Status::kAwaitingRemoteAcceptance))); bool connection_response_received = false; - EXPECT_THAT( - session_.AcceptTransfer([&connection_response_received]( - std::optional) { - connection_response_received = true; - }), - IsTrue()); + EXPECT_THAT(session_.AcceptTransfer( + [&connection_response_received]( + bool, std::optional) { + connection_response_received = true; + }), + IsTrue()); // Send response frame nearby::sharing::service::proto::Frame frame = @@ -575,19 +578,28 @@ TEST_F(OutgoingShareSessionTest, AcceptTransferSuccess) { EXPECT_THAT(connection_response_received, IsTrue()); } -TEST_F(OutgoingShareSessionTest, HandleConnectionResponseEmptyResponse) { +TEST_F(OutgoingShareSessionTest, HandleConnectionResponseEmptyResponseFailed) { std::optional status = - session_.HandleConnectionResponse(std::nullopt); + session_.HandleConnectionResponse(/*is_timeout=*/false, std::nullopt); ASSERT_THAT(status.has_value(), IsTrue()); EXPECT_THAT(status.value(), Eq(TransferMetadata::Status::kFailed)); } +TEST_F(OutgoingShareSessionTest, + HandleConnectionResponseEmptyResponseTimedOut) { + std::optional status = + session_.HandleConnectionResponse(/*is_timeout=*/true, std::nullopt); + + ASSERT_THAT(status.has_value(), IsTrue()); + EXPECT_THAT(status.value(), Eq(TransferMetadata::Status::kTimedOut)); +} + TEST_F(OutgoingShareSessionTest, HandleConnectionResponseRejectResponse) { ConnectionResponseFrame response; response.set_status(ConnectionResponseFrame::REJECT); std::optional status = - session_.HandleConnectionResponse(response); + session_.HandleConnectionResponse(/*is_timeout=*/false, response); ASSERT_THAT(status.has_value(), IsTrue()); EXPECT_THAT(status.value(), Eq(TransferMetadata::Status::kRejected)); @@ -598,7 +610,7 @@ TEST_F(OutgoingShareSessionTest, ConnectionResponseFrame response; response.set_status(ConnectionResponseFrame::NOT_ENOUGH_SPACE); std::optional status = - session_.HandleConnectionResponse(response); + session_.HandleConnectionResponse(/*is_timeout=*/false, response); ASSERT_THAT(status.has_value(), IsTrue()); EXPECT_THAT(status.value(), Eq(TransferMetadata::Status::kNotEnoughSpace)); @@ -609,7 +621,7 @@ TEST_F(OutgoingShareSessionTest, ConnectionResponseFrame response; response.set_status(ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE); std::optional status = - session_.HandleConnectionResponse(response); + session_.HandleConnectionResponse(/*is_timeout=*/false, response); ASSERT_THAT(status.has_value(), IsTrue()); EXPECT_THAT(status.value(), @@ -620,7 +632,7 @@ TEST_F(OutgoingShareSessionTest, HandleConnectionResponseTimeoutResponse) { ConnectionResponseFrame response; response.set_status(ConnectionResponseFrame::TIMED_OUT); std::optional status = - session_.HandleConnectionResponse(response); + session_.HandleConnectionResponse(/*is_timeout=*/true, response); ASSERT_THAT(status.has_value(), IsTrue()); EXPECT_THAT(status.value(), Eq(TransferMetadata::Status::kTimedOut)); @@ -636,7 +648,7 @@ TEST_F(OutgoingShareSessionTest, HandleConnectionResponseAcceptResponse) { Call(_, HasStatus(TransferMetadata::Status::kInProgress))); std::optional status = - session_.HandleConnectionResponse(response); + session_.HandleConnectionResponse(/*is_timeout=*/false, response); ASSERT_THAT(status.has_value(), IsFalse()); } @@ -909,5 +921,193 @@ TEST_F(OutgoingShareSessionTest, EXPECT_TRUE(session_.certificate().has_value()); EXPECT_THAT(session_.endpoint_id(), Eq(endpoint_id_org)); } + +TEST_F(OutgoingShareSessionTest, StartPeerBindingSuccess) { + session_.set_session_id(1234); + session_.set_session_usage(ShareSessionUsage::kPairing); + NearbyConnectionImpl connection(device_info_); + ConnectionSuccess(&connection); + Frame expected_binding_request_frame = + proto2::contrib::parse_proto::ParseTextProtoOrDie( + R"pb( + version: V1 + v1 { + type: BINDINGS + bindings { + binding_request { + binding_id: "test_binding_id" + type: FILESYNC + } + } + } + )pb"); + std::vector frame_data; + connections_manager_.set_send_payload_callback( + [&](std::unique_ptr payload, + std::weak_ptr + listener) { + frame_data = std::move(payload->content.bytes_payload.bytes); + }); + EXPECT_CALL( + transfer_metadata_callback_, + Call(_, + AllOf(HasStatus(TransferMetadata::Status::kAwaitingRemoteAcceptance), + HasUsage(ShareSessionUsage::kPairing)))); + + BindingResponse::Status binding_response_status = BindingResponse::FAILURE; + session_.StartPeerBinding("test_binding_id", BindingRequest::FILESYNC, + [&binding_response_status]( + BindingResponse::Status status) { + binding_response_status = status; + }); + + Frame frame; + ASSERT_THAT(frame.ParseFromArray(frame_data.data(), frame_data.size()), + IsTrue()); + EXPECT_THAT(frame, EqualsProto(expected_binding_request_frame)); + + // Send response frame + nearby::sharing::service::proto::Frame response_frame = + proto2::contrib::parse_proto::ParseTextProtoOrDie( + R"pb( + version: V1 + v1 { + type: BINDINGS + bindings { + binding_response { + status: SUCCESS + } + } + } + )pb" + ); + std::vector data; + data.resize(response_frame.ByteSizeLong()); + EXPECT_THAT(response_frame.SerializeToArray(data.data(), data.size()), + IsTrue()); + connection.WriteMessage(std::move(data)); + + EXPECT_THAT(binding_response_status, Eq(BindingResponse::SUCCESS)); +} + +TEST_F(OutgoingShareSessionTest, StartPeerBindingTimeout) { + session_.set_session_id(1234); + session_.set_session_usage(ShareSessionUsage::kPairing); + NearbyConnectionImpl connection(device_info_); + ConnectionSuccess(&connection); + Frame expected_binding_request_frame = + proto2::contrib::parse_proto::ParseTextProtoOrDie( + R"pb( + version: V1 + v1 { + type: BINDINGS + bindings { + binding_request { + binding_id: "test_binding_id" + type: FILESYNC + } + } + } + )pb"); + std::vector frame_data; + connections_manager_.set_send_payload_callback( + [&](std::unique_ptr payload, + std::weak_ptr + listener) { + frame_data = std::move(payload->content.bytes_payload.bytes); + }); + EXPECT_CALL( + transfer_metadata_callback_, + Call(_, + AllOf(HasStatus(TransferMetadata::Status::kAwaitingRemoteAcceptance), + HasUsage(ShareSessionUsage::kPairing)))); + + BindingResponse::Status binding_response_status = BindingResponse::FAILURE; + session_.StartPeerBinding("test_binding_id", BindingRequest::FILESYNC, + [&binding_response_status]( + BindingResponse::Status status) { + binding_response_status = status; + }); + + Frame frame; + ASSERT_THAT(frame.ParseFromArray(frame_data.data(), frame_data.size()), + IsTrue()); + EXPECT_THAT(frame, EqualsProto(expected_binding_request_frame)); + + // Fast forward to the disconnection timeout. + fake_clock_.FastForward(absl::Seconds(60)); + fake_task_runner_.SyncWithTimeout(absl::Milliseconds(100)); + + EXPECT_THAT(binding_response_status, Eq(BindingResponse::FAILURE)); +} + +TEST_F(OutgoingShareSessionTest, StartPeerBindingFailure) { + session_.set_session_id(1234); + session_.set_session_usage(ShareSessionUsage::kPairing); + NearbyConnectionImpl connection(device_info_); + ConnectionSuccess(&connection); + Frame expected_binding_request_frame = + proto2::contrib::parse_proto::ParseTextProtoOrDie( + R"pb( + version: V1 + v1 { + type: BINDINGS + bindings { + binding_request { + binding_id: "test_binding_id" + type: FILESYNC + } + } + } + )pb"); + std::vector frame_data; + connections_manager_.set_send_payload_callback( + [&](std::unique_ptr payload, + std::weak_ptr + listener) { + frame_data = std::move(payload->content.bytes_payload.bytes); + }); + EXPECT_CALL( + transfer_metadata_callback_, + Call(_, + AllOf(HasStatus(TransferMetadata::Status::kAwaitingRemoteAcceptance), + HasUsage(ShareSessionUsage::kPairing)))); + + BindingResponse::Status binding_response_status = BindingResponse::FAILURE; + session_.StartPeerBinding("test_binding_id", BindingRequest::FILESYNC, + [&binding_response_status]( + BindingResponse::Status status) { + binding_response_status = status; + }); + + Frame frame; + ASSERT_THAT(frame.ParseFromArray(frame_data.data(), frame_data.size()), + IsTrue()); + EXPECT_THAT(frame, EqualsProto(expected_binding_request_frame)); + + // Send response frame + nearby::sharing::service::proto::Frame response_frame = + proto2::contrib::parse_proto::ParseTextProtoOrDie( + R"pb( + version: V1 + v1 { + type: BINDINGS + bindings { + binding_response { + status: FAILURE + } + } + } + )pb" + ); + std::vector data; + data.resize(response_frame.ByteSizeLong()); + EXPECT_THAT(response_frame.SerializeToArray(data.data(), data.size()), + IsTrue()); + connection.WriteMessage(std::move(data)); + + EXPECT_THAT(binding_response_status, Eq(BindingResponse::FAILURE)); +} + } // namespace } // namespace nearby::sharing diff --git a/sharing/outgoing_targets_manager.cc b/sharing/outgoing_targets_manager.cc index 86087baa..eeb490d4 100644 --- a/sharing/outgoing_targets_manager.cc +++ b/sharing/outgoing_targets_manager.cc @@ -342,4 +342,19 @@ void OutgoingTargetsManager::ForEachShareTarget( } } +std::vector OutgoingTargetsManager::GetBindingIds( + int64_t share_target_id) { + std::vector binding_ids; + auto session_it = outgoing_share_session_map_.find(share_target_id); + if (session_it == outgoing_share_session_map_.end()) { + return {}; + } + std::optional certificate = + session_it->second.certificate(); + if (certificate.has_value()) { + return {certificate->binding_id()}; + } + return {}; +} + } // namespace nearby::sharing diff --git a/sharing/outgoing_targets_manager.h b/sharing/outgoing_targets_manager.h index 6917f0e4..7da8d2b4 100644 --- a/sharing/outgoing_targets_manager.h +++ b/sharing/outgoing_targets_manager.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "absl/base/nullability.h" #include "absl/container/flat_hash_map.h" @@ -94,6 +95,8 @@ class OutgoingTargetsManager { void ForEachShareTarget( absl::AnyInvocable callback); + std::vector GetBindingIds(int64_t share_target_id); + private: // If an existing target matching either endpoint_id or share_target.device_id // is found, the existing share target id is returned. diff --git a/sharing/outgoing_targets_manager_test.cc b/sharing/outgoing_targets_manager_test.cc index 60965259..863d707b 100644 --- a/sharing/outgoing_targets_manager_test.cc +++ b/sharing/outgoing_targets_manager_test.cc @@ -18,6 +18,7 @@ #include #include +#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" @@ -25,8 +26,9 @@ #include "internal/test/fake_clock.h" #include "internal/test/fake_device_info.h" #include "internal/test/fake_task_runner.h" -#include "sharing/analytics/analytics_recorder.h" #include "sharing/attachment_container.h" +#include "sharing/certificates/nearby_share_decrypted_public_certificate.h" +#include "sharing/certificates/test_util.h" #include "sharing/fake_nearby_connections_manager.h" #include "sharing/nearby_connection_impl.h" #include "sharing/nearby_connections_types.h" @@ -59,7 +61,7 @@ class OutgoingTargetsManagerTest : public ::testing::Test { FakeClock clock_; FakeTaskRunner service_thread_; FakeNearbyConnectionsManager connections_manager_; - analytics::AnalyticsRecorder analytics_recorder_; + analytics::AnalyticsRecorderImpl analytics_recorder_; testing::MockFunction share_target_discovered_callback_; testing::MockFunction @@ -781,5 +783,36 @@ TEST_F(OutgoingTargetsManagerTest, AllTargetsLostConnectedSessionsNotClosed) { nullptr); } +TEST_F(OutgoingTargetsManagerTest, GetBindingIds_NonExistentTarget) { + EXPECT_TRUE(outgoing_targets_manager_.GetBindingIds(1234).empty()); +} + +TEST_F(OutgoingTargetsManagerTest, GetBindingIds_NoCertificate) { + constexpr int kShareTargetId = 1234; + constexpr absl::string_view kEndpointId = "endpoint_id"; + ShareTarget target; + target.id = kShareTargetId; + + outgoing_targets_manager_.OnShareTargetDiscovered( + target, kEndpointId, /*certificate=*/std::nullopt); + + EXPECT_TRUE(outgoing_targets_manager_.GetBindingIds(kShareTargetId).empty()); +} + +TEST_F(OutgoingTargetsManagerTest, GetBindingIds_WithCertificate) { + constexpr int kShareTargetId = 1234; + constexpr absl::string_view kEndpointId = "endpoint_id"; + ShareTarget target; + target.id = kShareTargetId; + NearbyShareDecryptedPublicCertificate cert = + GetNearbyShareTestDecryptedPublicCertificate(); + + outgoing_targets_manager_.OnShareTargetDiscovered(target, kEndpointId, cert); + + std::vector binding_ids = + outgoing_targets_manager_.GetBindingIds(kShareTargetId); + EXPECT_THAT(binding_ids, ElementsAre(cert.binding_id())); +} + } // namespace } // namespace nearby::sharing diff --git a/sharing/paired_key_verification_runner.cc b/sharing/paired_key_verification_runner.cc index e8cd74f3..213d6799 100644 --- a/sharing/paired_key_verification_runner.cc +++ b/sharing/paired_key_verification_runner.cc @@ -26,6 +26,7 @@ #include #include +#include "absl/base/nullability.h" #include "absl/functional/any_invocable.h" #include "absl/time/time.h" #include "internal/platform/clock.h" @@ -56,20 +57,18 @@ namespace { // if a valid signature cannot be generated. This size is consistent with the // GmsCore implementation. const size_t kNearbyShareNumBytesRandomSignature = 72; -constexpr absl::Duration kRelaxAfterSetVisibilityTimeout = absl::Minutes(15); +constexpr absl::Duration kRelaxAfterSetVisibilityTimeout = absl::Minutes(1); PairedKeyVerificationRunner::PairedKeyVerificationResult Convert( nearby::sharing::service::proto::PairedKeyResultFrame::Status status) { switch (status) { - case PairedKeyResultFrame::UNKNOWN: - return PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown; - case PairedKeyResultFrame::SUCCESS: return PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess; case PairedKeyResultFrame::FAIL: return PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail; + case PairedKeyResultFrame::UNKNOWN: case PairedKeyResultFrame::UNABLE: return PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable; } @@ -91,40 +90,24 @@ std::ostream& operator<<( } PairedKeyVerificationRunner::PairedKeyVerificationRunner( - Clock* clock, OSType os_type, bool share_target_is_incoming, + Clock* absl_nonnull clock, OSType os_type, bool share_target_is_incoming, const VisibilityHistory& visibility_history, const std::vector& token, absl::AnyInvocable frame_writer, const std::optional& certificate, - NearbyShareCertificateManager* certificate_manager, - IncomingFramesReader* frames_reader, absl::Duration read_frame_timeout) - : clock_(clock), + NearbyShareCertificateManager* absl_nonnull certificate_manager, + IncomingFramesReader* absl_nonnull frames_reader, + absl::Duration read_frame_timeout) + : clock_(*clock), + certificate_manager_(*certificate_manager), + frames_reader_(*frames_reader), + share_target_is_incoming_(share_target_is_incoming), os_type_(os_type), - raw_token_(token), - frame_writer_(std::move(frame_writer)), + visibility_history_(visibility_history), certificate_(certificate), - certificate_manager_(certificate_manager), - frames_reader_(frames_reader), - read_frame_timeout_(read_frame_timeout) { - DCHECK(clock_); - DCHECK(certificate_manager); - DCHECK(frames_reader); - - if (share_target_is_incoming) { - local_prefix_ = kNearbyShareReceiverVerificationPrefix; - remote_prefix_ = kNearbyShareSenderVerificationPrefix; - visibility_history_ = visibility_history; - } else { - remote_prefix_ = kNearbyShareReceiverVerificationPrefix; - local_prefix_ = kNearbyShareSenderVerificationPrefix; - // Sender always uses ALL_CONTACTS cert to sign and verify signature. - visibility_history_ = { - .visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, - .last_visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, - .last_visibility_time = absl::UnixEpoch(), - }; - } -} + read_frame_timeout_(read_frame_timeout), + raw_token_(token), + frame_writer_(std::move(frame_writer)) {} PairedKeyVerificationRunner::~PairedKeyVerificationRunner() = default; @@ -135,7 +118,7 @@ void PairedKeyVerificationRunner::Run( verification_result_ = PairedKeyVerificationResult::kSuccess; SendPairedKeyEncryptionFrame(); - frames_reader_->ReadFrame( + frames_reader_.ReadFrame( V1Frame::PAIRED_KEY_ENCRYPTION, [&, runner = GetWeakPtr()](bool is_timeout, std::optional frame) { @@ -169,6 +152,17 @@ void PairedKeyVerificationRunner::OnReadPairedKeyEncryptionFrame( } } + if (auth_token_hash_result == PairedKeyVerificationResult::kUnable) { + if (share_target_is_incoming_ && + visibility_history_.visibility != + DeviceVisibility::DEVICE_VISIBILITY_EVERYONE) { + VLOG(1) << __func__ << ": Incoming connection with non-everyone " + "visibility cannot verify public certificate. " + "Treating as kFail."; + auth_token_hash_result = PairedKeyVerificationResult::kFail; + } + } + ApplyResult(auth_token_hash_result); VLOG(1) << __func__ << ": Remote public certificate verification result " << auth_token_hash_result; @@ -178,10 +172,18 @@ void PairedKeyVerificationRunner::OnReadPairedKeyEncryptionFrame( ApplyResult(local_result); VLOG(1) << __func__ << ": Paired key encryption verification result " << local_result; + if (share_target_is_incoming_ && visibility_history_.visibility == + DeviceVisibility::DEVICE_VISIBILITY_HIDDEN) { + VLOG(1) << __func__ + << ": device is hidden, reject all incoming connections."; + local_result = PairedKeyVerificationResult::kFail; + ApplyResult(PairedKeyVerificationResult::kFail); + } + SendPairedKeyResultFrame(local_result); - frames_reader_->ReadFrame( + frames_reader_.ReadFrame( V1Frame::PAIRED_KEY_RESULT, [this, runner = GetWeakPtr()](bool is_timeout, std::optional frame) { @@ -240,10 +242,6 @@ void PairedKeyVerificationRunner::SendPairedKeyResultFrame( case PairedKeyVerificationResult::kFail: result_frame->set_status(PairedKeyResultFrame::FAIL); break; - - case PairedKeyVerificationResult::kUnknown: - result_frame->set_status(PairedKeyResultFrame::UNKNOWN); - break; } // Set OS type to allow remote device knowns the paring device OS type. @@ -253,9 +251,13 @@ void PairedKeyVerificationRunner::SendPairedKeyResultFrame( } void PairedKeyVerificationRunner::SendPairedKeyEncryptionFrame() { + std::vector padded_token = PadPrefix( + share_target_is_incoming_ ? kNearbyShareReceiverVerificationPrefix + : kNearbyShareSenderVerificationPrefix, + raw_token_); std::optional> signature = - certificate_manager_->SignWithPrivateCertificate( - visibility_history_.visibility, PadPrefix(local_prefix_, raw_token_)); + certificate_manager_.SignWithPrivateCertificate( + visibility_history_.visibility, padded_token); if (!signature.has_value() || signature->empty()) { signature = GenerateRandomBytes(kNearbyShareNumBytesRandomSignature); } @@ -280,9 +282,8 @@ void PairedKeyVerificationRunner::SendPairedKeyEncryptionFrame() { LOG(INFO) << "Attempts to sign authentication token with a previous private key."; std::optional> optional_signature = - certificate_manager_->SignWithPrivateCertificate( - visibility_history_.last_visibility, - PadPrefix(local_prefix_, raw_token_)); + certificate_manager_.SignWithPrivateCertificate( + visibility_history_.last_visibility, padded_token); if (optional_signature.has_value()) { encryption_frame->set_optional_signed_data(optional_signature->data(), @@ -300,7 +301,7 @@ PairedKeyVerificationRunner::VerifyAuthTokenHashWithPrivateCertificate( DeviceVisibility visibility, const nearby::sharing::service::proto::V1Frame& frame) { std::optional> hash = - certificate_manager_->HashAuthenticationTokenWithPrivateCertificate( + certificate_manager_.HashAuthenticationTokenWithPrivateCertificate( visibility, raw_token_); const std::string& frame_hash = @@ -328,8 +329,11 @@ PairedKeyVerificationRunner::VerifyPairedKeyEncryptionFrame( auto signed_data = frame.paired_key_encryption().signed_data(); std::vector data(signed_data.begin(), signed_data.end()); - if (!certificate_->VerifySignature(PadPrefix(remote_prefix_, raw_token_), - data)) { + std::vector padded_token = PadPrefix( + share_target_is_incoming_ ? kNearbyShareSenderVerificationPrefix + : kNearbyShareReceiverVerificationPrefix, + raw_token_); + if (!certificate_->VerifySignature(padded_token, data)) { if (!frame.paired_key_encryption().has_optional_signed_data()) { LOG(WARNING) << __func__ << ": Unable to verify remote paired key encryption frame. " @@ -341,8 +345,7 @@ PairedKeyVerificationRunner::VerifyPairedKeyEncryptionFrame( frame.paired_key_encryption().optional_signed_data(); std::vector optional_data(optional_signed_data.begin(), optional_signed_data.end()); - if (certificate_->VerifySignature(PadPrefix(remote_prefix_, raw_token_), - optional_data)) { + if (certificate_->VerifySignature(padded_token, optional_data)) { LOG(INFO) << "Successfully verified remote paired key encryption " "frame with the optional signed data."; } else { @@ -374,17 +377,13 @@ void PairedKeyVerificationRunner::ApplyResult( case PairedKeyVerificationResult::kUnable: verification_result_ = PairedKeyVerificationResult::kUnable; break; - case PairedKeyVerificationResult::kUnknown: - default: - verification_result_ = PairedKeyVerificationResult::kUnable; - break; } } bool PairedKeyVerificationRunner::IsVisibilityRecentlyUpdated() const { return visibility_history_.visibility != visibility_history_.last_visibility && - (clock_->Now() - visibility_history_.last_visibility_time < + (clock_.Now() - visibility_history_.last_visibility_time < kRelaxAfterSetVisibilityTimeout); } diff --git a/sharing/paired_key_verification_runner.h b/sharing/paired_key_verification_runner.h index 6bfc8026..372e656c 100644 --- a/sharing/paired_key_verification_runner.h +++ b/sharing/paired_key_verification_runner.h @@ -22,6 +22,7 @@ #include #include +#include "absl/base/nullability.h" #include "absl/functional/any_invocable.h" #include "absl/time/time.h" #include "internal/platform/clock.h" @@ -38,8 +39,6 @@ class PairedKeyVerificationRunner : public std::enable_shared_from_this { public: enum class PairedKeyVerificationResult { - // Default value for verification result. - kUnknown, // Succeeded with verification. kSuccess, // Failed to verify. @@ -55,7 +54,8 @@ class PairedKeyVerificationRunner }; PairedKeyVerificationRunner( - Clock* clock, location::nearby::proto::sharing::OSType os_type, + Clock* absl_nonnull clock, + location::nearby::proto::sharing::OSType os_type, bool share_target_is_incoming, const VisibilityHistory& visibility_history, const std::vector& token, @@ -63,8 +63,9 @@ class PairedKeyVerificationRunner void(const nearby::sharing::service::proto::Frame& frame)> frame_writer, const std::optional& certificate, - NearbyShareCertificateManager* certificate_manager, - IncomingFramesReader* frames_reader, absl::Duration read_frame_timeout); + NearbyShareCertificateManager* absl_nonnull certificate_manager, + IncomingFramesReader* absl_nonnull frames_reader, + absl::Duration read_frame_timeout); ~PairedKeyVerificationRunner(); @@ -95,22 +96,21 @@ class PairedKeyVerificationRunner // True if visibility has changed recently. bool IsVisibilityRecentlyUpdated() const; - nearby::Clock* const clock_; + nearby::Clock& clock_; + NearbyShareCertificateManager& certificate_manager_; + IncomingFramesReader& frames_reader_; + const bool share_target_is_incoming_; const location::nearby::proto::sharing::OSType os_type_; - VisibilityHistory visibility_history_; + const VisibilityHistory visibility_history_; + const std::optional certificate_; + const absl::Duration read_frame_timeout_; std::vector raw_token_; absl::AnyInvocable frame_writer_; - std::optional certificate_; - NearbyShareCertificateManager* certificate_manager_; - IncomingFramesReader* frames_reader_; - const absl::Duration read_frame_timeout_; std::function callback_; PairedKeyVerificationResult verification_result_; - char local_prefix_; - char remote_prefix_; }; } // namespace nearby::sharing diff --git a/sharing/paired_key_verification_runner_test.cc b/sharing/paired_key_verification_runner_test.cc index c022e972..6b02462d 100644 --- a/sharing/paired_key_verification_runner_test.cc +++ b/sharing/paired_key_verification_runner_test.cc @@ -28,6 +28,7 @@ #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" +#include "absl/functional/any_invocable.h" #include "absl/time/time.h" #include "internal/platform/task_runner.h" #include "internal/test/fake_clock.h" @@ -123,7 +124,6 @@ GenerateVisibilityHistory() { DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE, DeviceVisibility::DEVICE_VISIBILITY_EVERYONE, - DeviceVisibility::DEVICE_VISIBILITY_HIDDEN, }; std::list result; for (DeviceVisibility visibility : kValidVisibilities) { @@ -142,18 +142,18 @@ class MockIncomingFramesReader : public IncomingFramesReader { NearbyConnection* connection) : IncomingFramesReader(service_thread, connection) {} - MOCK_METHOD( - void, ReadFrame, - (std::function)> callback, - absl::Duration timeout), - (override)); + MOCK_METHOD(void, ReadFrame, + (absl::AnyInvocable)> + callback, + absl::Duration timeout), + (override)); - MOCK_METHOD( - void, ReadFrame, - (service::proto::V1Frame_FrameType frame_type, - std::function)> callback, - absl::Duration timeout), - (override)); + MOCK_METHOD(void, ReadFrame, + (service::proto::V1Frame_FrameType frame_type, + absl::AnyInvocable)> + callback, + absl::Duration timeout), + (override)); }; PairedKeyVerificationRunner::PairedKeyVerificationResult Merge( @@ -240,9 +240,9 @@ class PairedKeyVerificationRunnerTest : public testing::Test { ReadFrame(testing::Eq(V1Frame::PAIRED_KEY_ENCRYPTION), testing::_, testing::Eq(kTimeout))) .WillOnce(testing::WithArg<1>( - [frame_type]( - std::function)> - callback) { + [frame_type](absl::AnyInvocable)> + callback) { if (frame_type == ReturnFrameType::kNull) { std::move(callback)(/*is_timeout=*/false, std::nullopt); return; @@ -302,7 +302,8 @@ class PairedKeyVerificationRunnerTest : public testing::Test { ReadFrame(testing::Eq(V1Frame::PAIRED_KEY_RESULT), testing::_, testing::Eq(kTimeout))) .WillOnce(testing::WithArg<1>( - [=](std::function)> + [=](absl::AnyInvocable)> callback) { if (frame_type == ReturnFrameType::kNull) { std::move(callback)(/*is_timeout=*/false, std::nullopt); @@ -353,13 +354,32 @@ class PairedKeyVerificationRunnerTest : public testing::Test { }; TEST_F(PairedKeyVerificationRunnerTest, - NullCertificate_InvalidPairedKeyEncryptionFrame) { + Incoming_NullCertificate_InvalidPairedKeyEncryptionFrame) { // Empty key encryption frame fails the certificate verification. SetUpPairedKeyEncryptionFrame(ReturnFrameType::kEmpty); SetUpPairedKeyResultFrame(ReturnFrameType::kValid); RunVerification( - true, + /*is_incoming=*/true, + /*use_valid_public_certificate=*/false, + {.visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, + .last_visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, + .last_visibility_time = GetFakeClock()->Now()}, + /*expected_result=*/ + PairedKeyVerificationResult::kFail); + + ExpectPairedKeyEncryptionFrameSent(); + ExpectPairedKeyResultFrameSent(PairedKeyResultFrame::UNABLE); +} + +TEST_F(PairedKeyVerificationRunnerTest, + Outgoing_NullCertificate_InvalidPairedKeyEncryptionFrame) { + // Empty key encryption frame fails the certificate verification. + SetUpPairedKeyEncryptionFrame(ReturnFrameType::kEmpty); + SetUpPairedKeyResultFrame(ReturnFrameType::kValid); + + RunVerification( + /*is_incoming=*/false, /*use_valid_public_certificate=*/false, {.visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, .last_visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, @@ -371,6 +391,25 @@ TEST_F(PairedKeyVerificationRunnerTest, ExpectPairedKeyResultFrameSent(PairedKeyResultFrame::UNABLE); } +TEST_F(PairedKeyVerificationRunnerTest, + Incoming_HiddenDevice_FailsConnection) { + // Empty key encryption frame fails the certificate verification. + SetUpPairedKeyEncryptionFrame(ReturnFrameType::kEmpty); + SetUpPairedKeyResultFrame(ReturnFrameType::kValid); + + RunVerification( + /*is_incoming=*/true, + /*use_valid_public_certificate=*/false, + {.visibility = DeviceVisibility::DEVICE_VISIBILITY_HIDDEN, + .last_visibility = DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, + .last_visibility_time = GetFakeClock()->Now()}, + /*expected_result=*/ + PairedKeyVerificationResult::kFail); + + ExpectPairedKeyEncryptionFrameSent(); + ExpectPairedKeyResultFrameSent(PairedKeyResultFrame::FAIL); +} + TEST_F(PairedKeyVerificationRunnerTest, ValidPairedKeyEncryptionFrame_ResultFrameTimedOut) { SetUpPairedKeyEncryptionFrame(ReturnFrameType::kValid); @@ -435,14 +474,40 @@ TEST_P(ParameterisedPairedKeyVerificationRunnerTest, PairedKeyResultFrame result_frame = std::get<1>(GetParam()); PairedKeyVerificationRunner::VisibilityHistory visibility_history = std::get<2>(GetParam()); + PairedKeyVerificationRunner::PairedKeyVerificationResult result = + params.result; + // If our visibility has no certificates, then downgrade expected result to + // kUnable if it is not expected to fail. + if ((visibility_history.visibility == + DeviceVisibility::DEVICE_VISIBILITY_EVERYONE) && + !(visibility_history.last_visibility != + DeviceVisibility::DEVICE_VISIBILITY_EVERYONE && + (params.encryption_frame_type == + PairedKeyVerificationRunnerTest::ReturnFrameType::kOptionalValid || + params.encryption_frame_type == + PairedKeyVerificationRunnerTest::ReturnFrameType::kValid))) { + if (result == + PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess) { + result = + PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable; + } + } + if (params.is_incoming && + params.encryption_frame_type == + PairedKeyVerificationRunnerTest::ReturnFrameType::kEmpty && + visibility_history.visibility != + DeviceVisibility::DEVICE_VISIBILITY_EVERYONE) { + result = + PairedKeyVerificationRunner::PairedKeyVerificationResult::kFail; + } PairedKeyVerificationRunner::PairedKeyVerificationResult expected_result = - Merge(params.result, result_frame.status()); + Merge(result, result_frame.status()); LOG(ERROR) << "ValidEncryptionFrame_ValidResultFrame: " << "is_incoming=" << params.is_incoming << ", has_valid_cert=" << params.has_valid_certificate << ", encryption_frame_type=" << (int)params.encryption_frame_type - << ", result=" << (int)params.result + << ", result=" << (int)result << ", expected_result=" << (int)expected_result << ", result_frame=" << (int)result_frame.status() << ", visibility=" << (int)visibility_history.visibility @@ -461,22 +526,6 @@ TEST_P(ParameterisedPairedKeyVerificationRunnerTest, : OSType::UNKNOWN_OS_TYPE); } - // If our visibility has no certificates, then downgrade expected result to - // kUnable if it is not expected to fail. - if ((visibility_history.visibility == - DeviceVisibility::DEVICE_VISIBILITY_EVERYONE || - visibility_history.visibility == - DeviceVisibility::DEVICE_VISIBILITY_HIDDEN) && - (visibility_history.last_visibility == - DeviceVisibility::DEVICE_VISIBILITY_EVERYONE || - visibility_history.last_visibility == - DeviceVisibility::DEVICE_VISIBILITY_HIDDEN)) { - if (expected_result == - PairedKeyVerificationRunner::PairedKeyVerificationResult::kSuccess) { - expected_result = - PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnable; - } - } visibility_history.last_visibility_time = GetFakeClock()->Now(); RunVerification( /*is_incoming=*/params.is_incoming, diff --git a/sharing/payload_tracker.cc b/sharing/payload_tracker.cc index e05b4818..345a87a6 100644 --- a/sharing/payload_tracker.cc +++ b/sharing/payload_tracker.cc @@ -107,7 +107,7 @@ void PayloadTracker::OnStatusUpdate( payload_update_queue_->Queue(std::move(update)); } -std::optional PayloadTracker::ProcessPayloadUpdate( +std::optional PayloadTracker::ProcessPayloadUpdate( std::unique_ptr update) { auto it = payload_state_.find(update->payload_id); if (it == payload_state_.end()) { @@ -139,34 +139,31 @@ std::optional PayloadTracker::ProcessPayloadUpdate( return OnTransferUpdate(state); } -std::optional PayloadTracker::OnTransferUpdate( +std::optional PayloadTracker::OnTransferUpdate( const State& state) { if (IsComplete()) { VLOG(1) << __func__ << ": All payloads are complete."; - return TransferMetadataBuilder() + return std::move(TransferMetadataBuilder() .set_status(TransferMetadata::Status::kComplete) .set_progress(100) .set_total_attachments_count(payload_state_.size()) - .set_transferred_attachments_count(transferred_attachments_count_) - .build(); + .set_transferred_attachments_count(transferred_attachments_count_)); } if (IsCancelled(state)) { VLOG(1) << __func__ << ": Payloads cancelled."; - return TransferMetadataBuilder() + return std::move(TransferMetadataBuilder() .set_status(TransferMetadata::Status::kCancelled) .set_total_attachments_count(payload_state_.size()) - .set_transferred_attachments_count(transferred_attachments_count_) - .build(); + .set_transferred_attachments_count(transferred_attachments_count_)); } if (HasFailed(state)) { VLOG(1) << __func__ << ": Payloads failed."; - return TransferMetadataBuilder() + return std::move(TransferMetadataBuilder() .set_status(TransferMetadata::Status::kFailed) .set_total_attachments_count(payload_state_.size()) - .set_transferred_attachments_count(transferred_attachments_count_) - .build(); + .set_transferred_attachments_count(transferred_attachments_count_)); } double percent = CalculateProgressPercent(state); @@ -220,7 +217,7 @@ std::optional PayloadTracker::OnTransferUpdate( last_update_progress_ = current_progress; - return TransferMetadataBuilder() + return std::move(TransferMetadataBuilder() .set_status(TransferMetadata::Status::kInProgress) .set_progress(percent) .set_transferred_bytes(current_transferred_size) @@ -230,8 +227,7 @@ std::optional PayloadTracker::OnTransferUpdate( .set_transferred_attachments_count(transferred_attachments_count_) .set_in_progress_attachment_id(state.attachment_id) .set_in_progress_attachment_total_bytes(state.total_size) - .set_in_progress_attachment_transferred_bytes(state.amount_transferred) - .build(); + .set_in_progress_attachment_transferred_bytes(state.amount_transferred)); } bool PayloadTracker::IsComplete() const { diff --git a/sharing/payload_tracker.h b/sharing/payload_tracker.h index 4f73e4e6..e27025e0 100644 --- a/sharing/payload_tracker.h +++ b/sharing/payload_tracker.h @@ -27,7 +27,7 @@ #include "sharing/attachment_container.h" #include "sharing/nearby_connections_manager.h" #include "sharing/nearby_connections_types.h" -#include "sharing/transfer_metadata.h" +#include "sharing/transfer_metadata_builder.h" #include "sharing/worker_queue.h" namespace nearby { @@ -46,7 +46,7 @@ class PayloadTracker : public NearbyConnectionsManager::PayloadStatusListener { std::unique_ptr payload_queue); ~PayloadTracker() override; - std::optional ProcessPayloadUpdate( + std::optional ProcessPayloadUpdate( std::unique_ptr update); // NearbyConnectionsManager::PayloadStatusListener: @@ -64,7 +64,7 @@ class PayloadTracker : public NearbyConnectionsManager::PayloadStatusListener { PayloadStatus status = PayloadStatus::kInProgress; }; - std::optional OnTransferUpdate(const State& state); + std::optional OnTransferUpdate(const State& state); bool IsComplete() const; bool IsCancelled(const State& state) const; diff --git a/sharing/payload_tracker_test.cc b/sharing/payload_tracker_test.cc index 73cac929..8b21d2ba 100644 --- a/sharing/payload_tracker_test.cc +++ b/sharing/payload_tracker_test.cc @@ -32,6 +32,7 @@ #include "sharing/nearby_connections_types.h" #include "sharing/proto/wire_format.pb.h" #include "sharing/transfer_metadata.h" +#include "sharing/transfer_metadata_builder.h" namespace nearby::sharing { namespace { @@ -69,7 +70,12 @@ class PayloadTrackerTest : public ::testing::Test { auto transfer_update = std::make_unique( /*payload_id=*/kFileId, PayloadStatus::kInProgress, /*total_bytes=*/kFileSize, /*bytes_transferred=*/bytes_transferred); - return payload_tracker_->ProcessPayloadUpdate(std::move(transfer_update)); + std::optional metadata_builder = + payload_tracker_->ProcessPayloadUpdate(std::move(transfer_update)); + if (!metadata_builder.has_value()) { + return std::nullopt; + } + return metadata_builder->build(); } private: diff --git a/sharing/proto/analytics/nearby_sharing_log.proto b/sharing/proto/analytics/nearby_sharing_log.proto deleted file mode 100644 index 0f7b30f6..00000000 --- a/sharing/proto/analytics/nearby_sharing_log.proto +++ /dev/null @@ -1,1128 +0,0 @@ -// 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. - -syntax = "proto2"; - -package nearby.sharing.analytics.proto; - -import "google/protobuf/duration.proto"; - -// "privacy/pattributes/annotations/proto_field.proto"; -// import "storage/datapol/annotations/proto/semantic_annotations.proto"; -// import "storage/googlesql/public/proto/type_annotation.proto"; -import "proto/sharing_enums.proto"; - -option optimize_for = LITE_RUNTIME; -option java_package = "nearby.sharing.analytics.proto"; -option java_outer_classname = "SharingLogProto"; -option objc_class_prefix = "GNCP"; - -// Top-level log proto for all NearbySharing logging. -// Each log contains a key (event_type), value (a verb-noun event) pair. -// Next Tag: 90 -// LINT.IfChange -message SharingLog { - /* justification = { - collection_basis: CB_CHECKBOX - purposes: [ INFRASTRUCTURE_METRICS, BUSINESS_ANALYSIS ] - } */ - - reserved 71; // Deprecated TransferUIEvent. - - optional location.nearby.proto.sharing.EventType event_type = 1; - - optional UnknownEvent unknown_event = 2; - - optional AcceptAgreements accept_agreements = 3; - - optional EnableNearbySharing enable_nearby_sharing = 4; - - optional SetVisibility set_visibility = 5; - - optional DescribeAttachments describe_attachments = 6; - - optional ScanForShareTargetsStart scan_for_share_targets_start = 7; - - optional ScanForShareTargetsEnd scan_for_share_targets_end = 8; - - optional AdvertiseDevicePresenceStart advertise_device_presence_start = 9; - - optional AdvertiseDevicePresenceEnd advertise_device_presence_end = 10; - - optional SendFastInitialization send_initialization = 11; - - optional ReceiveFastInitialization receive_initialization = 12; - - optional DiscoverShareTarget discover_share_target = 13; - - optional SendIntroduction send_introduction = 14; - - optional ReceiveIntroduction receive_introduction = 15; - - optional RespondToIntroduction respond_introduction = 16; - - optional SendAttachmentsStart send_attachments_start = 17; - - optional SendAttachmentsEnd send_attachments_end = 18; - - optional ReceiveAttachmentsStart receive_attachments_start = 19; - - optional ReceiveAttachmentsEnd receive_attachments_end = 20; - - optional CancelSendingAttachments cancel_sending_attachments = 21; - - optional CancelReceivingAttachments cancel_receiving_attachments = 22; - - optional OpenReceivedAttachments open_received_attachments = 23; - - optional LaunchActivity launch_activity = 24; - - optional AddContact add_contact = 25; - - optional RemoveContact remove_contact = 26; - - optional location.nearby.proto.sharing.LogSource log_source = 27; - - optional FastShareServerResponse fast_share_server_response = 28; - - optional SendStart send_start = 29; - - optional AcceptFastInitialization accept_fast_initialization = 30; - - optional SetDataUsage set_data_usage = 31; - - // The version of Nearby Sharing. E.g. "v1.0.2". - optional string version = 32 /* type = ST_SOFTWARE_ID */; - - optional location.nearby.proto.sharing.EventCategory event_category = 33; - - optional DismissFastInitialization dismiss_fast_initialization = 34; - - optional CancelConnection cancel_connection = 35; - - optional DismissPrivacyNotification dismiss_privacy_notification = 36; - - // Tap privacy notification to update visibility setting. - // http://shortn/_LMJHzPFZM0 - optional TapPrivacyNotification tap_privacy_notification = 37; - - optional TapHelp tap_help = 38; - - optional TapFeedback tap_feedback = 39; - - optional AddQuickSettingsTile add_quick_settings_tile = 40; - - optional RemoveQuickSettingsTile remove_quick_settings_tile = 41; - - optional LaunchPhoneConsent launch_phone_consent = 42; - - optional TapQuickSettingsTile tap_quick_settings_tile = 43; - - optional InstallAPKStatus install_apk_status = 44; - - optional VerifyAPKStatus verify_apk_status = 45; - - optional LaunchConsent launch_consent = 46; - - optional ProcessReceivedAttachmentsEnd process_received_attachments_end = 47; - - optional ToggleShowNotification toggle_show_notification = 48; - - optional SetDeviceName set_device_name = 49; - - // This is a temporary logging field for FilesGo migration phase based on - // device geolocation. Example values are "Phase 1", "Phase 2", etc. - // Reference: http://shortn/_BkSTmDjzWc - optional string files_migration_phase = 50; - - optional DeclineAgreements decline_agreements = 51; - - optional RequestSettingPermissions request_setting_permissions = 52; - - optional DeviceSettings device_settings = 53; - - optional EstablishConnection establish_connection = 54; - - optional AutoDismissFastInitialization auto_dismiss_fast_initialization = 55; - - optional EventMetadata event_metadata = 56; - - // Used only for Nearby Share Windows app now, e.g. "1.0.408". Deprecated and - // move it to the AppInfo below. - optional string app_version = 57 - /* type = ST_SOFTWARE_ID */[deprecated = true]; - - // Used only for Nearby Share Windows app now - optional AppCrash app_crash = 58; - - // Used only for Nearby Share android app now - optional TapQuickSettingsFileShare tap_quick_settings_file_share = 59; - - // Used only for Nearby Share Windows app now. - // TODO(b/260732897): To deprecate, and will be replaced by - // NearbyClientLog.AppInfo. - optional AppInfo app_info = 60; - - // Used only for Nearby Share android app now - optional DisplayPrivacyNotification display_privacy_notification = 61; - - // Used only for Nearby Share android app now - optional DisplayPhoneConsent display_phone_consent = 62; - - // Used only for Nearby Share Windows app now. - optional PreferencesUsage preferences_usage = 63; - - // Used only for Nearby Share android app now. - optional DefaultOptIn default_opt_in = 64; - - optional SetupWizard setup_wizard = 65; - - // Used only for Nearby Share android app now. - optional TapQrCode tap_qr_code = 66; - - optional QrCodeLinkShown qr_code_link_shown = 67; - - optional ParsingFailedEndpointId parsing_failed_endpoint_id = 68; - - optional FastInitDiscoverDevice fast_init_discover_device = 69; - - optional SendDesktopNotification send_desktop_notification = 70; - - optional SendDesktopTransferEvent send_desktop_transfer_event = 72; - - optional SetAccount set_account = 73; - - optional DecryptCertificateFailure decrypt_certificate_failure = 74; - - // Used only for Nearby Share android app now. - optional ShowAllowPermissionAutoAccess show_allow_permission_auto_access = 75; - - optional ShowWaitingForAccept show_waiting_for_accept = 76; - - optional HighQualityMediumSetup high_quality_medium_setup = 77; - - optional RpcCallStatus rpc_call_status = 78; - - optional StartQrCodeSession start_qr_code_session = 79; - - optional QrCodeOpenedInWebClient qr_code_opened_in_web_client = 80; - - optional HatsJointEvent hats_joint_event = 81; - - optional ReceivePreviews receive_previews = 82; - - // Two types of QR code sharing: P2P and Cloud-based - // P2P QR code flow re-uses a lot of the existing events from scan to send. - // Cloud-based QR code flow has the following new events. - // QR code events for sender side. - optional CloudCreateSharingRequest cloud_create_sharing_request = 83; - - // QR code CLOUD_REGISTER_RECEIVER event for receiver side. - optional CloudRegisterReceiver cloud_register_receiver = 84; - - optional CloudUploadStart cloud_upload_start = 85; - - optional CloudUploadEnd cloud_upload_end = 86; - - optional CloudDownloadStart cloud_download_start = 87; - - optional CloudDownloadEnd cloud_download_end = 88; - - // Cloud sharing RPC call event. - optional CloudSharingRpcResult cloud_sharing_rpc_result = 89; - - // Used only for Nearby Share Windows app now. - message AppInfo { - // e.g. "1.0.408" - optional string app_version = 1 /* type = ST_SOFTWARE_ID */; - // e.g. en. In Windows app, it's from the registry value. - optional string app_language = 2 - /* type = ST_DEMOGRAPHIC_INFO */; - optional string update_track = - 3; // e.g. "developer". In Windows app, it's from the registry value. - } - - message DeviceSettings { - // Device visibility setting at Nearby Share settings page, e.g. Contacts. - optional location.nearby.proto.sharing.Visibility visibility = 1; - // Device data usage preference at Nearby Share settings page, e.g.Wi-Fi - // only, Data, etc. - optional location.nearby.proto.sharing.DataUsage data_usage = 2; - // Device name length - optional int32 device_name_size = 3; - // Whether device allows show notification when devices are sharing nearby. - optional bool is_show_notification_enabled = 4; - // True if the BlueTooth setting is enabled - optional bool is_bt_enabled = 5; - // True if the location setting is enabled - optional bool is_location_enabled = 6; - // True if the wifi setting is enabled - optional bool is_wifi_enabled = 7; - // Date(YYYYMMDD) in decimal format for the first successful transfer in - // America/Los_Angeles timezone. If no successful transfer exists, the value - // is 0. - optional int32 first_successful_transfer_date = 8 - /* format = googlesql.format */; - // Date(YYYYMMDD) in decimal format for the previous successful transfer in - // America/Los_Angeles timezone. If no successful transfer exists, the value - // is 0. - optional int32 previous_successful_transfer_date = 9 - /* format = googlesql.format */; - // The cumulative number of transfers the device has completed. - // Exact transfer count stored on device, but when logging put the transfer - // count in buckets, initially we use buckets: 1, 2, 3, …, 10, 11+ - optional int32 lifetime_transfer_count = 10; - // Upload Contact data according to Device consent or Quick Share consent. - optional location.nearby.proto.sharing.ContactAccess contact_access = 11; - // Phone number verification. - optional location.nearby.proto.sharing.IdentityVerification - identity_verification = 12; - } - - // Used only for Nearby Share Windows app now. Here is the screenshot about - // where preferences are set: - // https://screenshot.googleplex.com/6HFrEfKCPxuSiYz. - message PreferencesUsage { - optional location.nearby.proto.sharing.PreferencesAction action = 1; - optional location.nearby.proto.sharing.PreferencesActionStatus - action_status = 2; - optional location.nearby.proto.sharing.PreferencesAction prev_sub_action = - 3; - optional location.nearby.proto.sharing.PreferencesAction next_sub_action = - 4; - } - - // EventType: UNKNOWN_EVENT_TYPE - message UnknownEvent {} - - // EventType: ESTABLISH_CONNECTION - message EstablishConnection { - // The result status of the attempt to establish a connection. - optional location.nearby.proto.sharing.EstablishConnectionStatus status = 1; - - optional int64 session_id = 2 /* type = ST_SESSION_ID */; - // For group share, 1-based number for transfer position. - optional int32 transfer_position = 3; - // For group share. - optional int32 concurrent_connections = 4; - // For calculating latency. - optional int64 duration_millis = 5; - optional ShareTargetInfo share_target_info = 6; - optional string referrer_name = 7; - // Deprecated. Use share_target_info.has_matching_qr_code instead. - optional bool qr_code_flow = 8 [deprecated = true]; - // True if the connection established from receiver - optional bool is_incoming_connection = 9; - // Duration from when the receiver attempts to receive from a QR code to - // when the QR code sender successfully connects to this receiver. Only set - // for QR-code based receive flows. - optional google.protobuf.Duration qr_code_receiver_connect_latency = 10; - } - - // EventType: ACCEPT_AGREEMENTS - message AcceptAgreements {} - - // EventType: DECLINE_AGREEMENTS - message DeclineAgreements {} - - // EventType: ENABLE_NEARBY_SHARING - message EnableNearbySharing { - optional location.nearby.proto.sharing.NearbySharingStatus status = 1; - optional bool has_opted_in = 2; - } - - // EventType: SET_ACCOUNT - // Activity Name: SETUP_ACTIVITY or SETTINGS_ACTIVITY - message SetAccount { - optional location.nearby.proto.sharing.ActivityName activity_name = 1; - } - - // EventType: SET_VISIBILITY - message SetVisibility { - // The new visibility that the device is set to. - optional location.nearby.proto.sharing.Visibility visibility = 1; - - // The current visibility of the device. - optional location.nearby.proto.sharing.Visibility source_visibility = 2; - - // The duration in millis of this visibility setting. - optional int64 duration_millis = 3; - - optional location.nearby.proto.sharing.ActivityName source_activity_name = 4 - /* type = ST_NOT_REQUIRED */; - } - - // EventType: SET_DATA_USAGE - message SetDataUsage { - // The current data usage preference of the device. - optional location.nearby.proto.sharing.DataUsage original_preference = 1; - - // The new data usage preference that the device is set to. - optional location.nearby.proto.sharing.DataUsage preference = 2; - } - - // EventType: SCAN_FOR_SHARE_TARGETS_START - message ScanForShareTargetsStart { - // A randomly generated number to be used to join the start and end of a - // session (mostly used to compute the duration of the session, e.g. how - // long does it take for attachments to be shared/sent via the Nearby - // Connections api). A same number is used twice for the start and - // end of a session. It is not designed to be associated to user or device, - // and can only be used to join the start and end of a particular session. - // Each session itself does not contain user or device information, and is - // not designed to be joined with other sessions/events of the same user to - // reconstruct particular user's activity pattern. - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.SessionStatus status = 2; - optional location.nearby.proto.sharing.ScanType scan_type = 3; - optional int64 flow_id = 4 /* type = ST_SESSION_ID */; - optional string referrer_name = 5; - // Represents whether this scan was started with an active QR code session - // that can be used to help discover targets that have scanned the same QR - // code - optional bool use_qr_code = 6; - } - - // EventType: SCAN_FOR_SHARE_TARGETS_END - message ScanForShareTargetsEnd { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - } - - // EventType: ADVERTISE_DEVICE_PRESENCE_START - message AdvertiseDevicePresenceStart { - // No longer needed for advertisement. - optional int64 session_id = 1 - /* type = ST_SESSION_ID */[deprecated = true]; - optional location.nearby.proto.sharing.Visibility visibility = 2; - optional location.nearby.proto.sharing.SessionStatus status = 3; - optional location.nearby.proto.sharing.DataUsage data_usage = 4; - // No longer needed for advertisement, replace this with - // SET_NAME_DEVICE. - optional int32 device_name_size = 5 [deprecated = true]; - optional string referrer_name = 6; - optional location.nearby.proto.sharing.AdvertisingMode advertising_mode = 7; - optional bool qr_code_flow = 8; - } - - // EventType: ADVERTISE_DEVICE_PRESENCE_END - message AdvertiseDevicePresenceEnd { - // No longer needed for advertisement. - optional int64 session_id = 1 - /* type = ST_SESSION_ID */[deprecated = true]; - } - - // EventType: SEND_FAST_INITIALIZATION - message SendFastInitialization {} - - // EventType: RECEIVE_FAST_INITIALIZATION - message ReceiveFastInitialization { - // The time elapse from the beginning of screen unlock to the time - // when the FastInitialization is received. - optional int64 time_elapse_since_screen_unlock_millis = 1; - // True if the notification is enabled - optional bool notifications_enabled = 2; - // True if the notification is being filtered when being shown - optional bool notifications_filtered = 3; - } - - // EventType: DISMISS_FAST_INITIALIZATION - message DismissFastInitialization {} - - // EventType: AUTO_DISMISS_FAST_INITIALIZATION - message AutoDismissFastInitialization {} - - // TODO(b/302987763): We need to deprecate flow_id and session_id in each - // event once these two fields in metadata are released to prod and - // pipelines are updated to read them. - message EventMetadata { - optional location.nearby.proto.sharing.SharingUseCase use_case = 1; - // The opt-in status before the user enters the first opt-in screen in each - // time file share or it is always “true” if the user has opted in before. - // Deprecated. - optional bool initial_opt_in = 2 [deprecated = true]; - // The opt-in status after the user leaves the first opt-in screen in each - // time file share or it is always “true” if the user has opted in before. - // Deprecated. - optional bool opt_in = 3 [deprecated = true]; - // The Nearby Share enable status before the user enters the first - // opt-in screen in each time file share. - // Deprecated. - optional bool initial_enable_status = 4 [deprecated = true]; - // The same id means it is in the same sharing file flow of sender side. - // Ex: when sender share file to 2 receivers, the flow_id in sender side is - // the same for all the discovery/connection/transfer events. - optional int64 flow_id = 5 /* type = ST_SESSION_ID */; - // A randomly generated number to be used to join the start and end of a - // session (mostly used to compute the duration of the session, e.g. how - // long does it take for attachments to be shared/sent via the Nearby - // Connections api). A same number is used twice for the start and - // end of a session. It is not designed to be associated to user or device, - // and can only be used to join the start and end of a particular session. - // Each session itself does not contain user or device information, and is - // not designed to be joined with other sessions/events of the same user to - // reconstruct particular user's activity pattern. - optional int64 session_id = 6 /* type = ST_SESSION_ID */; - optional int32 vendor_id = 7 /* type = ST_PARTNER_ID */; - - // The cloud_sharing_id: used by both sender and receiver during QR code - // cloud sharing flow to join sender and receiver events. - optional string cloud_sharing_id = 8 - /* type = ST_SESSION_ID */; - // receiver session id: used by QR code cloud receiver. - optional string cloud_receiver_session_id = 9 - /* type = ST_SESSION_ID */; - - // The name of the external provider, it will not be set if the provider is - // not external. - optional string external_provider_name = 10; - // The service id of the external provider, it will not be set if the - // provider is not external. - optional string external_provider_id = 11 - /* type = ST_SESSION_ID */; - // Is this file transfer from a direct share target. This is only available - // for the sender log. - optional bool is_direct_share = 12; - } - - // TODO(fdi): may consider adding a field about decipherability later. - // EventType: DISCOVER_SHARE_TARGET - message DiscoverShareTarget { - optional ShareTargetInfo share_target_info = 1; - // The time elapse from the beginning of an scanning session to the time - // when the share target is discovered. - optional google.protobuf.Duration duration_since_scanning = 2; - optional int64 session_id = 3 /* type = ST_SESSION_ID */; - optional int64 flow_id = 4 /* type = ST_SESSION_ID */; - optional string referrer_name = 5; - // The time elapse from the share sheet activity starts (foreground - // send surface) to the time when the share target is discovered. - // Only uses foreground send surfaces, since this is when users - // directly engage with NS to send. - optional int64 latency_since_activity_start_millis = 6 [default = -1]; - optional location.nearby.proto.sharing.ScanType scan_type = 7; - - // receiver session id: used by QR code cloud receiver. - optional string cloud_receiver_session_id = 8 - /* type = ST_SESSION_ID */; - } - - // EventType: PARSING_FAILED_ENDPOINT_ID - message ParsingFailedEndpointId { - optional string endpoint_id = 1 /* type = ST_SESSION_ID */; - // The time elapse from the beginning of an scanning session to the time - // when the share target is discovered. - optional google.protobuf.Duration duration_since_scanning = 2; - optional int64 session_id = 3 /* type = ST_SESSION_ID */; - optional int64 flow_id = 4 /* type = ST_SESSION_ID */; - optional string referrer_name = 5 - /* type = ST_REFERER_URL */; - // The time elapse from the share sheet activity starts to the time - // when the share target is discovered. - optional int64 latency_since_activity_start_millis = 6 [default = -1]; - optional location.nearby.proto.sharing.ScanType scan_type = 7; - // The time elapse from the beginning of sync to download the certificates - // to the time when the scanning fails in parsing. - optional google.protobuf.Duration duration_since_last_sync = 8; - optional location.nearby.proto.sharing.ParsingFailedType - parsing_failed_type = 9; - optional location.nearby.proto.sharing.DiscoveryMode discovery_mode = 10; - } - - // EventType: DESCRIBE_ATTACHMENTS - message DescribeAttachments { - optional AttachmentsInfo attachments_info = 1; - - // Time taken to download the attachments before sending - optional google.protobuf.Duration download_duration = 2; - } - - // TODO(fdi): may want to add duration_from_scanning_millis later. - // EventType: SEND_INTRODUCTION - message SendIntroduction { - optional ShareTargetInfo share_target_info = 1; - optional int64 session_id = 2 /* type = ST_SESSION_ID */; - // 1-based number for transfer position. - optional int32 transfer_position = 3; - optional int32 concurrent_connections = 4; - } - - // EventType: RECEIVE_INTRODUCTION - message ReceiveIntroduction { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional ShareTargetInfo share_target_info = 2; - optional string referrer_name = 3; - } - - // TODO(fdi): may add AttachmentInfo, or ShareTargetInfo later. - // EventType: RESPOND_TO_INTRODUCTION - message RespondToIntroduction { - optional location.nearby.proto.sharing.ResponseToIntroduction action = 1; - optional int64 session_id = 2 /* type = ST_SESSION_ID */; - optional bool qr_code_flow = 3; - } - - // EventType: SEND_ATTACHMENTS_START - message SendAttachmentsStart { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional AttachmentsInfo attachments_info = 2; - // 1-based number for transfer position. - optional int32 transfer_position = 3; - optional int32 concurrent_connections = 4; - // Deprecated. Use share_target_info.has_matching_qr_code instead. - optional bool qr_code_flow = 5 [deprecated = true]; - optional ShareTargetInfo share_target_info = 6; - // True if the advanced protection is enabled and the sender needed to - // confirm the transfer. - optional bool advanced_protection_enabled = 7; - // True if the advanced protection flag from NearbyService BE is different - // from the mendel flag. - optional bool advanced_protection_mismatch = 8; - } - - // EventType: SEND_ATTACHMENTS_END - message SendAttachmentsEnd { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional int64 sent_bytes = 2; - optional location.nearby.proto.sharing.AttachmentTransmissionStatus status = - 3; - // 1-based number for transfer position. - optional int32 transfer_position = 4; - optional int32 concurrent_connections = 5; - optional AttachmentsInfo attachments_info = 6; - // the duration from transfer start to transfer is finished. - optional int64 duration_millis = 7; - optional ShareTargetInfo share_target_info = 8; - optional string referrer_name = 9; - // connection status from nearby connections layer - optional location.nearby.proto.sharing.ConnectionLayerStatus - connection_layer_status = 10; - // Date(YYYYMMDD) in decimal format for the first successful transfer in - // America/Los_Angeles timezone. If no successful transfer exists, the value - // is 0. - optional int32 first_successful_transfer_date = 11 - /* format = googlesql.format */; - // Date(YYYYMMDD) in decimal format for the previous successful transfer in - // America/Los_Angeles timezone. If no successful transfer exists, the value - // is 0. - optional int32 previous_successful_transfer_date = 12 - /* format = googlesql.format */; - // The cumulative number of transfers the device has completed. - // Exact transfer count stored on device, but when logging put the transfer - // count in buckets, initially we use buckets: 1, 2, 3, …, 10, 11+ - optional int32 lifetime_transfer_count = 13; - // The medium used for the connection. - optional int32 connection_medium = 14; - // The data usage of the user settings. - optional location.nearby.proto.sharing.DataUsage data_usage = 15; - - // True if the sender and receiver are mutual contacts. - optional bool is_mutual_contact = 16; - } - - // EventType: RECEIVE_ATTACHMENTS_START - message ReceiveAttachmentsStart { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional AttachmentsInfo attachments_info = 2; - optional ShareTargetInfo share_target_info = 3; - } - - // EventType: RECEIVE_ATTACHMENTS_END - message ReceiveAttachmentsEnd { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional int64 received_bytes = 2; - optional location.nearby.proto.sharing.AttachmentTransmissionStatus status = - 3; - optional string referrer_name = 4; - optional ShareTargetInfo share_target_info = 5; - // Date(YYYYMMDD) in decimal format for the first successful transfer in - // America/Los_Angeles timezone. If no successful transfer exists, the value - // is 0. - optional int32 first_successful_transfer_date = 6 - /* format = googlesql.format */; - // Date(YYYYMMDD) in decimal format for the previous successful transfer in - // America/Los_Angeles timezone. If no successful transfer exists, the value - // is 0. - optional int32 previous_successful_transfer_date = 7 - /* format = googlesql.format */; - // The cumulative number of transfers the device has completed. - // Exact transfer count stored on device, but when logging put the transfer - // count in buckets, initially we use buckets: 1, 2, 3, …, 10, 11+ - optional int32 lifetime_transfer_count = 8; - // The medium used for the connection. - optional int32 connection_medium = 14; - // The data usage of the user settings. - optional location.nearby.proto.sharing.DataUsage data_usage = 15; - } - - // EventType: CANCEL_CONNECTION - message CancelConnection { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - // 1-based number for transfer position. 1 if log is from receiver side. - optional int32 transfer_position = 2; - optional int32 concurrent_connections = 3; - } - - // EventType: CANCEL_SENDING_ATTACHMENTS - message CancelSendingAttachments {} - - // EventType: CANCEL_RECEIVING_ATTACHMENTS - message CancelReceivingAttachments {} - - // EventType: PROCESS_RECEIVED_ATTACHMENTS_END - message ProcessReceivedAttachmentsEnd { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.ProcessReceivedAttachmentsStatus - status = 2; - } - - // EventType: OPEN_RECEIVED_ATTACHMENTS - message OpenReceivedAttachments { - optional AttachmentsInfo attachments_info = 3; - optional int64 session_id = 4 /* type = ST_SESSION_ID */; - } - - // EventType: LAUNCH_SETUP_ACTIVITY - message LaunchSetupActivity {} - - // EventType: ADD_CONTACT - message AddContact { - optional bool was_phone_added = 1; - optional bool was_email_added = 2; - } - - // EventType: REMOVE_CONTACT - message RemoveContact { - optional bool was_phone_removed = 1; - optional bool was_email_removed = 2; - } - - // EventType: FAST_SHARE_SERVER_RESPONSE - message FastShareServerResponse { - optional location.nearby.proto.sharing.ServerResponseState status = 1; - optional location.nearby.proto.sharing.ServerActionName name = 2; - optional int64 latency_millis = 3; - optional location.nearby.proto.sharing.SyncPurpose purpose = 4; - optional location.nearby.proto.sharing.ClientRole requester = 5; - optional location.nearby.proto.sharing.DeviceType device_type = 6; - } - - // EventType: SEND_START - message SendStart { - optional int64 session_id = 1 /* type = ST_SESSION_ID */; - // 1-based number for transfer position. - optional int32 transfer_position = 2; - optional int32 concurrent_connections = 3; - optional ShareTargetInfo share_target_info = 4; - } - - // EventType: ACCEPT_FAST_INITIALIZATION - message AcceptFastInitialization {} - - // EventType: LAUNCH_ACTIVITY - message LaunchActivity { - optional location.nearby.proto.sharing.ActivityName activity_name = 1; - // Elapsed time in milliseconds between startActivity and stopActivity. - optional int64 duration_millis = 2; - // The name of the package that launched the activity - optional string referrer_name = 3; - // Is previous transfer in progress. - optional bool previous_transfer_in_progress = 4; - // Whether user has opted in before. For SETUP_ACTIVITY (Opt-In half sheet) - // and SETTINGS_ACTIVITY (Settings page). b/202415050, b/203248230 - optional bool has_opted_in = 5; - // Indicate which UI interaction triggers the opt-in half sheet. Currently - // this only applies to SETUP_ACTIVITY - optional location.nearby.proto.sharing.ActivityName source_activity_name = - 6; - // Is the activity simply pausing or completely finishing. - optional bool is_finishing = 7; - } - - // EventType: DISMISS_PRIVACY_NOTIFICATION - message DismissPrivacyNotification {} - - // EventType: TAP_PRIVACY_NOTIFICATION - message TapPrivacyNotification {} - - // EventType: TAP_HELP - message TapHelp {} - - // EventType: TAP_FEEDBACK - message TapFeedback {} - - // EventType: ADD_QUICK_SETTINGS_TILE - message AddQuickSettingsTile {} - - // EventType: REMOVE_QUICK_SETTINGS_TILE - message RemoveQuickSettingsTile {} - - // EventType: LAUNCH_PHONE_CONSENT - message LaunchPhoneConsent {} - - // EventType: DISPLAY_PHONE_CONSENT - message DisplayPhoneConsent {} - - // EventType: TAP_QUICK_SETTINGS_TILE - message TapQuickSettingsTile {} - - // EventType: TAP_QUICK_SETTINGS_FILE_SHARE - message TapQuickSettingsFileShare {} - - // EventType: DISPLAY_PRIVACY_NOTIFICATION - message DisplayPrivacyNotification {} - - // EventType: DEFAULT_OPT_IN - message DefaultOptIn {} - - // EventType: SET_DEVICE_NAME - message SetDeviceName { - optional int32 device_name_size = 1; - } - - // EventType: REQUEST_SETTING_PERMISSIONS - message RequestSettingPermissions { - optional location.nearby.proto.sharing.PermissionRequestType - permission_type = 1; - optional location.nearby.proto.sharing.PermissionRequestResult - permission_request_result = 2; - } - - // EventType: LAUNCH_CONSENT - message LaunchConsent { - optional location.nearby.proto.sharing.ConsentType consent_type = 1; - optional location.nearby.proto.sharing.ConsentAcceptanceStatus status = 2; - } - - // EventType: INSTALL_APK_STATUS - message InstallAPKStatus { - repeated location.nearby.proto.sharing.InstallAPKStatus status = 1 - [packed = true]; - repeated location.nearby.proto.sharing.ApkSource source = 2 [packed = true]; - } - - // EventType: VERIFY_APK_STATUS - message VerifyAPKStatus { - repeated location.nearby.proto.sharing.VerifyAPKStatus status = 1 - [packed = true]; - repeated location.nearby.proto.sharing.ApkSource source = 2 [packed = true]; - } - - // EventType: TOGGLE_SHOW_NOTIFICATION - message ToggleShowNotification { - optional location.nearby.proto.sharing.ShowNotificationStatus - previous_status = 1; - optional location.nearby.proto.sharing.ShowNotificationStatus - current_status = 2; - } - - // EventType: DECRYPT_CERTIFICATE_FAILURE - message DecryptCertificateFailure { - optional location.nearby.proto.sharing.DecryptCertificateFailureStatus - status = 1; - } - - // EventType: SHOW_ALLOW_PERMISSION_AUTO_ACCESS - message ShowAllowPermissionAutoAccess { - // Auto permission UI activity name - // Shows the auto permission UI if the device lacks Wifi or Bluetooth - // permission and the user has not allowed Nearby Share to automatically - // enable these permissions. Once the user allows access, the UI will - // not be shown again. - // Currently, only the SHARE_SHEET_ACTIVITY and RECEIVE_SURFACE_ACTIVITY - // show the UI. - optional location.nearby.proto.sharing.ActivityName activity_name = 1; - // True if user allowed NS to auto enable Wifi/BT permissions during file - // transfer and NS will recover the permissions after transffer is complete. - optional bool allowed_auto_access = 2; - // True if the device lacks Wifi permission. - optional bool is_wifi_missing = 3; - // True if the device lacks Bluetooth permission. - optional bool is_bt_missing = 4; - } - - // EventType: TAP_QR_CODE - message TapQrCode {} - - // QR_CODE_LINK_SHOWN - message QrCodeLinkShown {} - - // EventType: FAST_INIT_DISCOVER_DEVICE - message FastInitDiscoverDevice { - reserved 1; - // The advertisement type is NOTIFY or SILENT. - optional location.nearby.proto.sharing.FastInitType fast_init_type = 2; - // The distance of the found nearby fast init advertisement. - optional location.nearby.proto.sharing.FastInitState fast_init_state = 3; - } - - // The metadata of a share target. - message ShareTargetInfo { - optional location.nearby.proto.sharing.DeviceType device_type = 1; - optional location.nearby.proto.sharing.OSType os_type = 2; - optional location.nearby.proto.sharing.DeviceRelationship - device_relationship = 3; - // Represents whether the share target has the same QR code as the local - // device. - // In sender side events, this returns whether the receiver represented by - // this ShareTargetInfo has scanned the QR code generated by this sender. - // In receiver side events, this returns whether the sender represented by - // this ShareTargetInfo is the one that generated the QR code scanned by - // this receiver. - optional bool has_matching_qr_code = 4; - - // Represents whether the share target is from external provider. - optional bool is_external = 5; - } - - // The metadata of attachments to be shared. - message AttachmentsInfo { - repeated TextAttachment text_attachment = 1; - repeated FileAttachment file_attachment = 2; - // The App required by sender to open the attachments. - optional string required_app = 3; - repeated WifiCredentialsAttachment wifi_credentials_attachment = 4; - repeated AppAttachment app_attachment = 5; - repeated StreamAttachment stream_attachment = 6; - repeated FolderAttachment folder_attachment = 7; - } - - message TextAttachment { - optional Type type = 1; - optional int64 size_bytes = 2; - // attachments are batched together by some source - optional int64 batch_id = 3 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.AttachmentSourceType source_type = 4; - - enum Type { - UNKNOWN_TEXT_TYPE = 0; - URL = 1; - ADDRESS = 2; - PHONE_NUMBER = 3; - } - } - - message FileAttachment { - optional Type type = 1; - optional int64 size_bytes = 2; - reserved 3; // optional string mime_type = 3 - optional int64 offset_bytes = 4; - // attachments are batched together by some source - optional int64 batch_id = 5 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.AttachmentSourceType source_type = 6; - - enum Type { - UNKNOWN_FILE_TYPE = 0; - IMAGE = 1; - VIDEO = 2; - ANDROID_APP = 3; - AUDIO = 4; - DOCUMENT = 5; - CONTACT_CARD = 6; - } - } - - message WifiCredentialsAttachment { - optional int32 security_type = 1; - // attachments are batched together by some source - optional int64 batch_id = 2 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.AttachmentSourceType source_type = 3; - } - - message AppAttachment { - optional string package_name = 1 /* type = ST_SOFTWARE_ID */; - // App size in bytes. - optional int64 size = 2; - // attachments are batched together by some source - optional int64 batch_id = 3 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.AttachmentSourceType source_type = 4; - } - - message StreamAttachment { - optional string package_name = 1 /* type = ST_SOFTWARE_ID */; - // attachments are batched together by some source - optional int64 batch_id = 2 /* type = ST_SESSION_ID */; - optional location.nearby.proto.sharing.AttachmentSourceType source_type = 3; - } - - message CloudAttachmentInfo { - optional location.nearby.proto.sharing.AttachmentTransmissionStatus status = - 1; - oneof CloudAttachment { - TextAttachment text_attachment = 2; - FileAttachment file_attachment = 3; - WifiCredentialsAttachment wifi_credentials_attachment = 4; - AppAttachment app_attachment = 5; - StreamAttachment stream_attachment = 6; - } - // The total bytes of all attachments transferred. - optional int64 transferred_bytes = 7; - // The duration from transfer start to transfer end. - optional int64 duration_millis = 8; - } - - message FolderAttachment {} - - // EventType: APP_CRASH - // Used only for Nearby Share Windows App now - message AppCrash { - optional location.nearby.proto.sharing.AppCrashReason crash_reason = 1; - } - - // EventType: SETUP_WIZARD - // The results of a setup wizard flow - message SetupWizard { - // The new visibility of the device. - optional location.nearby.proto.sharing.Visibility visibility = 1; - // The previous visibility of the device. - optional location.nearby.proto.sharing.Visibility previous_visibility = 2; - } - - message SendDesktopNotification { - reserved 2; - optional location.nearby.proto.sharing.DesktopNotification event = 1; - } - - message SendDesktopTransferEvent { - optional location.nearby.proto.sharing.DesktopTransferEventType event = 1; - } - - message ShowWaitingForAccept { - optional location.nearby.proto.sharing.ButtonStatus button_status = 1; - } - - message HighQualityMediumSetup { - optional ShareTargetInfo share_target_info = 1; - optional int64 session_id = 2 /* type = ST_SESSION_ID */; - optional int64 duration_millis = 3; - optional bool is_timeout = 4; - optional int32 original_quality = 5; - optional int32 connection_medium = 6; - optional int32 connection_mode = 7; - optional int32 instant_connection_result = 8; - } - - message RpcCallStatus { - enum RpcDirection { - UNKNOWN_RPC_DIRECTION = 0; - INCOMING = 1; - OUTGOING = 2; - } - - optional RpcDirection direction = 1; - // Name of RPC in . format. - optional string rpc_name = 2; - // Canonical error code of RPC. - optional int32 error_code = 3; - // Latency of RPC call in milliseconds. - optional int64 latency_millis = 4; - } - - // EventType: START_QR_CODE_SESSION - message StartQrCodeSession {} - - // EventType: QR_CODE_OPENED_IN_WEB_CLIENT - message QrCodeOpenedInWebClient { - enum ClientPlatform { - UNKNOWN_CLIENT_PLATFORM = 0; - // Used when the client platform is not one of the types below - GENERIC = 1; - ANDROID = 2; - IOS = 3; - CHROME_OS = 4; - WINDOWS = 5; - } - optional ClientPlatform client_platform = 1; - - // Whether the /qrcode page was opened in the browser again after the user - // clicked on the "Try again" button - optional bool is_retry = 2; - } - // EventType: HATS_JOINT_EVENT - message HatsJointEvent { - optional int64 flow_id = 1 /* type = ST_SESSION_ID */; - optional string hats_session_id = 2 - /* type = ST_SESSION_ID */; - } - - // EventType: RECEIVE_PREVIEWS - message ReceivePreviews { - optional int32 num_previews = 1; - } - - // EventType: CLOUD_CREATE_SHARING_REQUEST - message CloudCreateSharingRequest { - optional AttachmentsInfo attachments_info = 1; - optional location.nearby.proto.sharing.CloudCreateSharingResult result = 2; - // Time taken to download attachments from the Intent in milliseconds. - optional int64 attachment_download_latency_millis = 3; - // Time taken to generate and encrypt the preview thumbnail in milliseconds. - optional int64 preview_thumbnail_latency_millis = 4; - // Time taken to make the CreateSharing RPC call in milliseconds. - optional int64 rpc_latency_millis = 5; - } - - // EventType: CLOUD_REGISTER_RECEIVER used by QR code cloud web receiver - message CloudRegisterReceiver { - optional location.nearby.proto.sharing.CloudRegisterReceiverResult result = - 1; - } - - // EventType: CLOUD_UPLOAD_START used by QR code cloud web sender - // The cloud_sharing_id and flow_id are logged in the event metadata. - message CloudUploadStart { - optional AttachmentsInfo attachments_info = 1; - optional location.nearby.proto.sharing.CloudActionType action_type = 2; - } - - // EventType: CLOUD_UPLOAD_END used by QR code cloud web sender - // The cloud_sharing_id and flow_id are logged in the event metadata. - message CloudUploadEnd { - repeated CloudAttachmentInfo upload_infos = 1; - optional location.nearby.proto.sharing.CloudActionType action_type = 2; - } - - // EventType: CLOUD_DOWNLOAD_START used by QR code cloud web receiver - // The cloud_sharing_id and cloud_receiver_session_id are logged in the - // event_metadata into the anonymous logs. - message CloudDownloadStart { - optional AttachmentsInfo attachments_info = 1; - optional location.nearby.proto.sharing.CloudActionType action_type = 2; - } - - // EventType: CLOUD_DOWNLOAD_END used by QR code cloud web receiver - // The cloud_sharing_id and cloud_receiver_session_id are logged in the - // event_metadata into the anonymous logs. - message CloudDownloadEnd { - repeated CloudAttachmentInfo download_infos = 1; - optional location.nearby.proto.sharing.CloudActionType action_type = 2; - } - - // EventType: CLOUD_SHARING_RPC_RESULT - // Event logging the result of a Cloud Sharing RPC call. This event captures - // the type of RPC, its outcome, and performance metrics. - message CloudSharingRpcResult { - // The specific RPC method that was called. - optional string rpc_name = 1; - // The canonical gRPC status code (io.grpc.Status.Code) resulting from the - // call. - optional int32 status_code = 2; - // The total time taken for the RPC call to complete, in milliseconds. - optional int64 latency_millis = 3; - // The unique identifier for the cloud sharing session, if available at the - // time of the call. This helps correlate RPC events to a specific sharing - // session. - optional string cloud_sharing_id = 4; - } -} -// LINT.ThenChange(//depot/google3/logs/proto/location/nearby/nearby_client_log.proto) diff --git a/sharing/proto/wire_format.proto b/sharing/proto/wire_format.proto index 2d35c6a7..b0db8294 100644 --- a/sharing/proto/wire_format.proto +++ b/sharing/proto/wire_format.proto @@ -196,7 +196,7 @@ message V1Frame { CANCEL = 6; // No longer used. PROGRESS_UPDATE = 7; - FILE_SYNC = 8; + BINDINGS = 8; } optional FrameType type = 1; @@ -208,7 +208,7 @@ message V1Frame { optional PairedKeyResultFrame paired_key_result = 5; optional CertificateInfoFrame certificate_info = 6 [deprecated = true]; optional ProgressUpdateFrame progress_update = 7 [deprecated = true]; - optional SyncFrame file_sync = 8; + optional BindingFrame bindings = 8; } // An introduction packet sent by the sending side. Contains a list of files @@ -219,6 +219,7 @@ message IntroductionFrame { UNKNOWN = 0; NEARBY_SHARE = 1; REMOTE_COPY = 2; + TAP_TO_SHARE = 9; } repeated FileMetadata file_metadata = 1; @@ -243,41 +244,35 @@ message ProgressUpdateFrame { optional bool start_transfer = 2; } -// A packet for file sync messages. -// NEXT_ID=3 -message SyncFrame { +// Messages used to create pair bindings between devices. +// An initiator device requests a new bindingId from the BE using the +// InitiateBinding rpc. This new bindingId is passed to the peer device using +// a BindingRequest frame. The peer device will use this bindingId to call +// JoinBinding rpc. If successful, the peer device is response with a +// BindingResponse frame with status of SUCCESS. +message BindingFrame { oneof content { - SyncHandshake handshake = 1; - SyncConfig config = 2; + BindingRequest binding_request = 1; + BindingResponse binding_response = 2; } } -// A packet for file sync handshake messages. -// NEXT_ID=1 -message SyncHandshake {} - -// A packet for file sync config messages. -// NEXT_ID=2 -message SyncConfig { - repeated SyncFolder folders = 1; +message BindingRequest { + enum Type { + UNKNOWN = 0; + FILESYNC = 1; + } + optional string binding_id = 1; + optional Type type = 2; } -// A packet for file sync folder messages. -// NEXT_ID=5 -message SyncFolder { - // An identifier of the folder for the pair of source and target devices to - // uniquely identify it among all folders that are being synced. - optional string id = 1; - // Human readable name of the folder. - optional string label = 2; - // A randomly generated id when the index is created. Regenerate when the - // index is reset. - optional int32 index_id = 3; - // The maximum sequence number of the folder. Each number represents an update - // to a file in the folder. Sequence numbers are only valid within the scope - // of a valid index_id. If an index is reset, all sequence numbers need to be - // regenerated, including max_sequence. - optional int64 max_sequence = 4; +message BindingResponse { + enum Status { + UNKNOWN = 0; + SUCCESS = 1; + FAILURE = 2; // TODO: b/485307320 - Add more specific error codes. + } + optional Status status = 1; } // A response packet sent by the receiving side. Accepts or rejects the list of diff --git a/sharing/share_session.cc b/sharing/share_session.cc index 885e8396..3c7d1676 100644 --- a/sharing/share_session.cc +++ b/sharing/share_session.cc @@ -176,7 +176,10 @@ void ShareSession::Abort(TransferMetadata::Status status) { // First invoke the appropriate transfer callback with the final // |status|. - UpdateTransferMetadata(TransferMetadataBuilder().set_status(status).build()); + UpdateTransferMetadata(TransferMetadataBuilder() + .set_usage(session_usage()) + .set_status(status) + .build()); Disconnect(); } @@ -232,12 +235,6 @@ bool ShareSession::ProcessKeyVerificationResult( // share flag. self_share_ = false; break; - - case PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown: - LOG(WARNING) << __func__ - << ": Unknown PairedKeyVerificationResult for target " - << share_target().id << ". Disconnecting."; - return false; } return true; } @@ -246,7 +243,10 @@ void ShareSession::OnDisconnect() { OnConnectionDisconnected(); if (disconnect_status_ != TransferMetadata::Status::kUnknown) { UpdateTransferMetadata( - TransferMetadataBuilder().set_status(disconnect_status_).build()); + TransferMetadataBuilder() + .set_usage(session_usage()) + .set_status(disconnect_status_) + .build()); } connection_ = nullptr; } diff --git a/sharing/share_session.h b/sharing/share_session.h index d0dc0f03..0a6675d7 100644 --- a/sharing/share_session.h +++ b/sharing/share_session.h @@ -38,6 +38,7 @@ #include "sharing/paired_key_verification_runner.h" #include "sharing/payload_tracker.h" #include "sharing/proto/wire_format.pb.h" +#include "sharing/share_session_usage.h" #include "sharing/share_target.h" #include "sharing/transfer_metadata.h" @@ -96,6 +97,11 @@ class ShareSession { const ShareTarget& share_target() const { return share_target_; } + ShareSessionUsage session_usage() const { return session_usage_; } + void set_session_usage(ShareSessionUsage session_usage) { + session_usage_ = session_usage; + } + // Sets the status to send in the TransferMetadataUpdate on connection // disconnect. If |status| is kUnknown, then no TransferMetadataUpdate will be // sent. If |status| is set, it must be a final status. @@ -221,6 +227,7 @@ class ShareSession { absl::flat_hash_map attachment_payload_map_; PayloadTracker::PayloadUpdateQueue* payload_updates_queue_ = nullptr; bool is_cancelled_ = false; + ShareSessionUsage session_usage_ = ShareSessionUsage::kUnknown; }; } // namespace nearby::sharing diff --git a/sharing/share_session_test.cc b/sharing/share_session_test.cc index fc6d9211..98a969fb 100644 --- a/sharing/share_session_test.cc +++ b/sharing/share_session_test.cc @@ -21,6 +21,8 @@ #include #include +#include "location/nearby/analytics/cpp/logging/mock_event_logger.h" +#include "location/nearby/sharing/lib/analytics/analytics_recorder_impl.h" #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" @@ -28,11 +30,9 @@ #include "absl/synchronization/notification.h" #include "absl/time/clock.h" #include "absl/time/time.h" -#include "internal/analytics/mock_event_logger.h" #include "internal/test/fake_clock.h" #include "internal/test/fake_device_info.h" #include "internal/test/fake_task_runner.h" -#include "sharing/analytics/analytics_recorder.h" #include "sharing/certificates/fake_nearby_share_certificate_manager.h" #include "sharing/fake_nearby_connections_manager.h" #include "sharing/nearby_connection.h" @@ -97,8 +97,8 @@ class TestShareSession : public ShareSession { FakeNearbyConnectionsManager connections_manager_; FakeDeviceInfo device_info_; nearby::analytics::MockEventLogger mock_event_logger_; - analytics::AnalyticsRecorder analytics_recorder_{/*vendor_id=*/0, - &mock_event_logger_}; + analytics::AnalyticsRecorderImpl analytics_recorder_{/*vendor_id=*/0, + &mock_event_logger_}; const bool is_incoming_; }; @@ -389,20 +389,6 @@ TEST(ShareSessionTest, ProcessKeyVerificationResultNotSelfShareUnable) { EXPECT_FALSE(session.token().empty()); } -TEST(ShareSessionTest, ProcessKeyVerificationResultUnknown) { - ShareTarget share_target; - TestShareSession session(std::string(kEndpointId), share_target); - NearbyConnectionImpl connection(session.device_info()); - session.SetNearbyConnection(&connection); - session.SetTokenForTests("9876"); - - EXPECT_FALSE(session.ProcessKeyVerificationResult( - PairedKeyVerificationRunner::PairedKeyVerificationResult::kUnknown, - OSType::WINDOWS)); - EXPECT_EQ(session.os_type(), OSType::WINDOWS); - EXPECT_FALSE(session.token().empty()); -} - TEST(ShareSessionTest, AbortNotConnected) { ShareTarget share_target; TestShareSession session(std::string(kEndpointId), share_target); diff --git a/sharing/share_session_usage.h b/sharing/share_session_usage.h new file mode 100644 index 00000000..0a2e2ded --- /dev/null +++ b/sharing/share_session_usage.h @@ -0,0 +1,45 @@ +// Copyright 2026 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_SHARING_SHARE_SESSION_USAGE_H_ +#define THIRD_PARTY_NEARBY_SHARING_SHARE_SESSION_USAGE_H_ + +#include + +namespace nearby::sharing { + +enum class ShareSessionUsage { + kUnknown, + kSharing, // Connection is used for quick share. + kPairing, // Connection is used for setting up a binding. + kFileSync, // Connection is used for file sync. +}; + +inline std::string ShareSessionUsageToString( + ShareSessionUsage transfer_usage) { + switch (transfer_usage) { + case ShareSessionUsage::kSharing: + return "Sharing"; + case ShareSessionUsage::kPairing: + return "Pairing"; + case ShareSessionUsage::kFileSync: + return "FileSync"; + case ShareSessionUsage::kUnknown: + return "Unknown"; + } +} + +} // namespace nearby::sharing + +#endif // THIRD_PARTY_NEARBY_SHARING_SHARE_SESSION_USAGE_H_ diff --git a/sharing/transfer_manager.cc b/sharing/transfer_manager.cc index dede2870..fa38384b 100644 --- a/sharing/transfer_manager.cc +++ b/sharing/transfer_manager.cc @@ -14,15 +14,15 @@ #include "sharing/transfer_manager.h" -#include #include #include -#include +#include +#include "absl/base/nullability.h" +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" -#include "absl/time/time.h" -#include "sharing/internal/public/context.h" +#include "internal/platform/task_runner.h" #include "sharing/internal/public/logging.h" #include "sharing/nearby_connections_types.h" #include "sharing/thread_timer.h" @@ -43,28 +43,32 @@ bool IsHighQualityMedium(Medium medium) { } // namespace -TransferManager::TransferManager(Context* context, - absl::string_view endpoint_id) - : context_(context), endpoint_id_(endpoint_id) {} +TransferManager::TransferManager( + TaskRunner* absl_nonnull runner, absl::string_view endpoint_id, + absl::AnyInvocable payload)> + deferred_send_function) + : runner_(*runner), + endpoint_id_(endpoint_id), + deferred_send_function_(std::move(deferred_send_function)) {} TransferManager::~TransferManager() { absl::MutexLock lock(mutex_); timeout_timer_.reset(); - pending_tasks_.clear(); } -void TransferManager::Send(std::function task) { +void TransferManager::Send(std::unique_ptr payload) { absl::MutexLock lock(mutex_); if (is_waiting_for_high_quality_medium_) { LOG(INFO) << "Connection to endpoint " << endpoint_id_ << " is waiting for a high quality medium, delaying payload transfer."; - pending_tasks_.push_back(task); + pending_payloads_.push(std::move(payload)); return; } - task(); + deferred_send_function_(endpoint_id_, std::move(payload)); } void TransferManager::OnMediumQualityChanged(Medium current_medium) { @@ -101,8 +105,8 @@ bool TransferManager::StartTransfer() { } timeout_timer_ = std::make_unique( - *context_->GetTaskRunner(), "transfer_manager_timeout_timer", - kMediumUpgradeTimeout, [this]() { + runner_, "transfer_manager_timeout_timer", kMediumUpgradeTimeout, + [this]() { absl::MutexLock lock(mutex_); LOG(INFO) << "Timed out for endpoint " << endpoint_id_ << " after " @@ -113,8 +117,7 @@ bool TransferManager::StartTransfer() { LOG(INFO) << "Attempting to upgrade the bandwidth for endpoint " + endpoint_id_ + ". Large payloads will be delayed" + " until either bandwidth is upgraded or a timeout of " - << (kMediumUpgradeTimeout / absl::Milliseconds(1)) - << " milliseconds is reached"; + << kMediumUpgradeTimeout << " is reached"; return true; } @@ -132,15 +135,16 @@ bool TransferManager::CancelTransfer() { } void TransferManager::StopWaitingForHighQualityMedium() { + timeout_timer_.reset(); is_waiting_for_high_quality_medium_ = false; - for (const auto& task : pending_tasks_) { - LOG(INFO) << "Sending delayed payload to endpoint " << endpoint_id_; - task(); + LOG(INFO) << "Sending " << pending_payloads_.size() + << " delayed payloads to endpoint " << endpoint_id_; + while (!pending_payloads_.empty()) { + auto payload = std::move(pending_payloads_.front()); + pending_payloads_.pop(); + deferred_send_function_(endpoint_id_, std::move(payload)); } - - pending_tasks_.clear(); - timeout_timer_.reset(); } } // namespace sharing diff --git a/sharing/transfer_manager.h b/sharing/transfer_manager.h index e33d1f33..619b2b0e 100644 --- a/sharing/transfer_manager.h +++ b/sharing/transfer_manager.h @@ -15,16 +15,17 @@ #ifndef THIRD_PARTY_NEARBY_SHARING_TRANSFER_MANAGER_H_ #define THIRD_PARTY_NEARBY_SHARING_TRANSFER_MANAGER_H_ -#include #include +#include #include -#include +#include "absl/base/nullability.h" #include "absl/base/thread_annotations.h" +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" -#include "sharing/internal/public/context.h" +#include "internal/platform/task_runner.h" #include "sharing/nearby_connections_types.h" #include "sharing/thread_timer.h" @@ -39,11 +40,15 @@ class TransferManager { // Used to wait for the medium upgrade. static constexpr absl::Duration kMediumUpgradeTimeout = absl::Seconds(10); - TransferManager(Context* context, absl::string_view endpoint_id); + TransferManager(TaskRunner* absl_nonnull runner, + absl::string_view endpoint_id, + absl::AnyInvocable payload)> + deferred_send_function); ~TransferManager(); - void Send(std::function task) ABSL_LOCKS_EXCLUDED(mutex_); + void Send(std::unique_ptr payload) ABSL_LOCKS_EXCLUDED(mutex_); void OnMediumQualityChanged(Medium current_medium) ABSL_LOCKS_EXCLUDED(mutex_); bool StartTransfer() ABSL_LOCKS_EXCLUDED(mutex_); @@ -52,11 +57,15 @@ class TransferManager { private: void StopWaitingForHighQualityMedium() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - Context* context_; - std::string endpoint_id_; + TaskRunner& runner_; + const std::string endpoint_id_; + absl::AnyInvocable payload)> + deferred_send_function_; absl::Mutex mutex_; bool is_waiting_for_high_quality_medium_ ABSL_GUARDED_BY(mutex_) = true; - std::vector> pending_tasks_ ABSL_GUARDED_BY(mutex_); + std::queue> pending_payloads_ + ABSL_GUARDED_BY(mutex_); std::unique_ptr timeout_timer_ ABSL_GUARDED_BY(mutex_) = nullptr; }; diff --git a/sharing/transfer_manager_test.cc b/sharing/transfer_manager_test.cc index f6ed6fc0..63f0616c 100644 --- a/sharing/transfer_manager_test.cc +++ b/sharing/transfer_manager_test.cc @@ -14,6 +14,7 @@ #include "sharing/transfer_manager.h" +#include #include #include "gtest/gtest.h" @@ -21,7 +22,7 @@ #include "absl/synchronization/notification.h" #include "absl/time/time.h" #include "internal/test/fake_clock.h" -#include "sharing/internal/test/fake_context.h" +#include "internal/test/fake_task_runner.h" #include "sharing/nearby_connections_types.h" namespace nearby { @@ -32,15 +33,20 @@ constexpr absl::string_view kEndpointId = "endpoint"; constexpr absl::Duration kNotificationTimeout = absl::Milliseconds(200); TEST(TransferManager, MediumUpgradeSuccess) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); ASSERT_FALSE(is_called); ASSERT_TRUE(transfer_manager.StartTransfer()); @@ -53,15 +59,20 @@ TEST(TransferManager, MediumUpgradeSuccess) { } TEST(TransferManager, SendAfterMediumUpgradeSuccess) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); ASSERT_FALSE(is_called); ASSERT_TRUE(transfer_manager.StartTransfer()); @@ -70,20 +81,25 @@ TEST(TransferManager, SendAfterMediumUpgradeSuccess) { notification.WaitForNotificationWithTimeout(kNotificationTimeout)); ASSERT_TRUE(is_called); is_called = false; - transfer_manager.Send([&]() { is_called = true; }); + transfer_manager.Send(std::make_unique()); ASSERT_TRUE(is_called); } TEST(TransferManager, MediumUpgradeFailed) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); ASSERT_FALSE(is_called); ASSERT_TRUE(transfer_manager.StartTransfer()); @@ -94,20 +110,24 @@ TEST(TransferManager, MediumUpgradeFailed) { } TEST(TransferManager, MediumUpgradeTimeout) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); ASSERT_FALSE(is_called); ASSERT_TRUE(transfer_manager.StartTransfer()); - FakeClock* clock = static_cast(context.GetClock()); - clock->FastForward(TransferManager::kMediumUpgradeTimeout); + fake_clock.FastForward(TransferManager::kMediumUpgradeTimeout); ASSERT_TRUE( notification.WaitForNotificationWithTimeout(kNotificationTimeout)); @@ -115,20 +135,24 @@ TEST(TransferManager, MediumUpgradeTimeout) { } TEST(TransferManager, CancelStartedTransfer) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); ASSERT_FALSE(is_called); ASSERT_TRUE(transfer_manager.StartTransfer()); - FakeClock* clock = static_cast(context.GetClock()); - clock->FastForward(absl::Seconds(5)); + fake_clock.FastForward(absl::Seconds(5)); ASSERT_TRUE(transfer_manager.CancelTransfer()); ASSERT_FALSE( @@ -137,20 +161,24 @@ TEST(TransferManager, CancelStartedTransfer) { } TEST(TransferManager, CancelTimedOutMediumUpgrade) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); ASSERT_FALSE(is_called); ASSERT_TRUE(transfer_manager.StartTransfer()); - FakeClock* clock = static_cast(context.GetClock()); - clock->FastForward(TransferManager::kMediumUpgradeTimeout); + fake_clock.FastForward(TransferManager::kMediumUpgradeTimeout); ASSERT_TRUE( notification.WaitForNotificationWithTimeout(kNotificationTimeout)); @@ -159,15 +187,20 @@ TEST(TransferManager, CancelTimedOutMediumUpgrade) { } TEST(TransferManager, MediumUpgradeBeforeStartTransfer) { - FakeContext context; + FakeClock fake_clock; + FakeTaskRunner executor(&fake_clock, /*concurrent_count=*/1); absl::Notification notification; bool is_called = false; - TransferManager transfer_manager{&context, kEndpointId}; - transfer_manager.Send([&]() { - is_called = true; - notification.Notify(); - }); + TransferManager transfer_manager{ + &executor, kEndpointId, + [&](absl::string_view endpoint_id, std::unique_ptr payload) { + is_called = true; + if (!notification.HasBeenNotified()) { + notification.Notify(); + } + }}; + transfer_manager.Send(std::make_unique()); transfer_manager.OnMediumQualityChanged(Medium::kWifiLan); diff --git a/sharing/transfer_metadata.cc b/sharing/transfer_metadata.cc index 82462b89..d62e2a9e 100644 --- a/sharing/transfer_metadata.cc +++ b/sharing/transfer_metadata.cc @@ -24,9 +24,10 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "sharing/share_session_usage.h" -namespace nearby { -namespace sharing { +namespace nearby::sharing { // static bool TransferMetadata::IsFinalStatus(Status status) { @@ -90,15 +91,17 @@ std::string TransferMetadata::StatusToString(Status status) { // LINT.ThenChange(//depot/google3/location/nearby/cpp/sharing/clients/dart/platform/lib/types/transfer_status.dart) TransferMetadata::TransferMetadata( - Status status, float progress, std::optional token, - bool is_original, bool is_final_status, bool is_self_share, - uint64_t transferred_bytes, uint64_t transfer_speed, + ShareSessionUsage usage, Status status, float progress, + std::optional token, bool is_original, bool is_final_status, + bool is_self_share, uint64_t transferred_bytes, uint64_t transfer_speed, uint64_t estimated_time_remaining, int total_attachments_count, int transferred_attachments_count, std::optional in_progress_attachment_id, std::optional in_progress_attachment_transferred_bytes, - std::optional in_progress_attachment_total_bytes) - : status_(status), + std::optional in_progress_attachment_total_bytes, + absl::string_view binding_id) + : usage_(usage), + status_(status), progress_(progress), token_(std::move(token)), is_original_(is_original), @@ -112,7 +115,8 @@ TransferMetadata::TransferMetadata( in_progress_attachment_id_(in_progress_attachment_id), in_progress_attachment_transferred_bytes_( in_progress_attachment_transferred_bytes), - in_progress_attachment_total_bytes_(in_progress_attachment_total_bytes) {} + in_progress_attachment_total_bytes_(in_progress_attachment_total_bytes), + binding_id_(binding_id) {} TransferMetadata::~TransferMetadata() = default; @@ -123,22 +127,26 @@ TransferMetadata& TransferMetadata::operator=(const TransferMetadata&) = std::string TransferMetadata::ToString() const { std::vector fmt; - + fmt.push_back( + absl::StrFormat("usage: %s", ShareSessionUsageToString(usage_))); fmt.push_back(absl::StrFormat("status: %s", StatusToString(status_))); - fmt.push_back(absl::StrFormat("progress: %.2f", progress_)); - if (token_) { - fmt.push_back(absl::StrFormat("token: %s", *token_)); - } - fmt.push_back(absl::StrFormat("is_original: %d", is_original_)); fmt.push_back(absl::StrFormat("is_final_status: %d", is_final_status_)); fmt.push_back(absl::StrFormat("is_self_share: %d", is_self_share_)); - fmt.push_back(absl::StrFormat("transferred_bytes: %d", transferred_bytes_)); - fmt.push_back(absl::StrFormat("transfer_speed: %d", transfer_speed_)); - fmt.push_back(absl::StrFormat("estimated_time_remaining: %d", - estimated_time_remaining_)); + if (usage_ != ShareSessionUsage::kPairing) { + fmt.push_back(absl::StrFormat("progress: %.2f", progress_)); + if (token_) { + fmt.push_back(absl::StrFormat("token: %s", *token_)); + } + fmt.push_back(absl::StrFormat("is_original: %d", is_original_)); + fmt.push_back(absl::StrFormat("transferred_bytes: %d", transferred_bytes_)); + fmt.push_back(absl::StrFormat("transfer_speed: %d", transfer_speed_)); + fmt.push_back(absl::StrFormat("estimated_time_remaining: %d", + estimated_time_remaining_)); + } else { + fmt.push_back(absl::StrFormat("binding_id: %s", binding_id_)); + } return absl::StrCat("TransferMetadata<", absl::StrJoin(fmt, ", "), ">"); } -} // namespace sharing -} // namespace nearby +} // namespace nearby::sharing diff --git a/sharing/transfer_metadata.h b/sharing/transfer_metadata.h index 03171a78..bc665e1f 100644 --- a/sharing/transfer_metadata.h +++ b/sharing/transfer_metadata.h @@ -19,6 +19,10 @@ #include #include +#include + +#include "absl/strings/string_view.h" +#include "sharing/share_session_usage.h" namespace nearby { namespace sharing { @@ -50,23 +54,31 @@ class TransferMetadata { // LINT.ThenChange(//depot/google3/location/nearby/cpp/sharing/clients/dart/platform/lib/types/transfer_status.dart) static bool IsFinalStatus(Status status); - static std::string StatusToString(TransferMetadata::Status status); + static std::string StatusToString(Status status); TransferMetadata( - Status status, float progress, std::optional token, - bool is_original, bool is_final_status, bool is_self_share, - uint64_t transferred_bytes, uint64_t transfer_speed, + ShareSessionUsage usage, Status status, float progress, + std::optional token, bool is_original, bool is_final_status, + bool is_self_share, uint64_t transferred_bytes, uint64_t transfer_speed, uint64_t estimated_time_remaining, int total_attachments_count, int transferred_attachments_count, std::optional in_progress_attachment_id, std::optional in_progress_attachment_transferred_bytes, - std::optional in_progress_attachment_total_bytes); + std::optional in_progress_attachment_total_bytes, + absl::string_view binding_id + ); ~TransferMetadata(); TransferMetadata(const TransferMetadata&); TransferMetadata& operator=(const TransferMetadata&); + ShareSessionUsage usage() const { return usage_; } Status status() const { return status_; } + std::string binding_id() const { return binding_id_; } + void set_binding_id(std::string binding_id) { + binding_id_ = std::move(binding_id); + } + // Returns transfer progress as percentage. float progress() const { return progress_; } @@ -118,6 +130,7 @@ class TransferMetadata { } private: + ShareSessionUsage usage_; Status status_; float progress_; std::optional token_; @@ -132,6 +145,9 @@ class TransferMetadata { std::optional in_progress_attachment_id_; std::optional in_progress_attachment_transferred_bytes_; std::optional in_progress_attachment_total_bytes_; + // If usage_ is kPairing and status_ is kComplete, this will be set to the + // binding id. Otherwise, this will be empty. + std::string binding_id_; }; } // namespace sharing diff --git a/sharing/transfer_metadata_builder.cc b/sharing/transfer_metadata_builder.cc index 3f849a2c..0fde6cdf 100644 --- a/sharing/transfer_metadata_builder.cc +++ b/sharing/transfer_metadata_builder.cc @@ -19,6 +19,8 @@ #include #include +#include "absl/strings/string_view.h" +#include "sharing/share_session_usage.h" #include "sharing/transfer_metadata.h" namespace nearby { @@ -27,6 +29,7 @@ namespace sharing { TransferMetadataBuilder TransferMetadataBuilder::Clone( const TransferMetadata& metadata) { TransferMetadataBuilder builder; + builder.usage_ = metadata.usage(); builder.is_original_ = metadata.is_original(); builder.progress_ = metadata.progress(); builder.status_ = metadata.status(); @@ -54,6 +57,18 @@ TransferMetadataBuilder& TransferMetadataBuilder::operator=( TransferMetadataBuilder::~TransferMetadataBuilder() = default; +TransferMetadataBuilder& TransferMetadataBuilder::set_usage( + ShareSessionUsage usage) { + usage_ = usage; + return *this; +} + +TransferMetadataBuilder& TransferMetadataBuilder::set_binding_id( + absl::string_view binding_id) { + binding_id_ = binding_id; + return *this; +} + TransferMetadataBuilder& TransferMetadataBuilder::set_is_original( bool is_original) { is_original_ = is_original; @@ -138,12 +153,12 @@ TransferMetadataBuilder::set_in_progress_attachment_total_bytes( TransferMetadata TransferMetadataBuilder::build() const { return TransferMetadata( - status_, progress_, token_, is_original_, + usage_, status_, progress_, token_, is_original_, TransferMetadata::IsFinalStatus(status_), is_self_share_, transferred_bytes_, transfer_speed_, estimated_time_remaining_, total_attachments_count_, transferred_attachments_count_, in_progress_attachment_id_, in_progress_attachment_transferred_bytes_, - in_progress_attachment_total_bytes_); + in_progress_attachment_total_bytes_, binding_id_); } } // namespace sharing diff --git a/sharing/transfer_metadata_builder.h b/sharing/transfer_metadata_builder.h index 208a8cca..aaaebf42 100644 --- a/sharing/transfer_metadata_builder.h +++ b/sharing/transfer_metadata_builder.h @@ -20,6 +20,8 @@ #include #include +#include "absl/strings/string_view.h" +#include "sharing/share_session_usage.h" #include "sharing/transfer_metadata.h" namespace nearby { @@ -34,6 +36,10 @@ class TransferMetadataBuilder { TransferMetadataBuilder& operator=(TransferMetadataBuilder&&); ~TransferMetadataBuilder(); + TransferMetadataBuilder& set_usage(ShareSessionUsage usage); + + TransferMetadataBuilder& set_binding_id(absl::string_view binding_id); + TransferMetadataBuilder& set_is_original(bool is_original); TransferMetadataBuilder& set_progress(double progress); @@ -69,6 +75,7 @@ class TransferMetadataBuilder { TransferMetadata build() const; private: + ShareSessionUsage usage_ = ShareSessionUsage::kUnknown; bool is_original_ = false; double progress_ = 0; TransferMetadata::Status status_ = TransferMetadata::Status::kInProgress; @@ -83,6 +90,7 @@ class TransferMetadataBuilder { std::optional in_progress_attachment_transferred_bytes_ = std::nullopt; std::optional in_progress_attachment_total_bytes_ = std::nullopt; + std::string binding_id_; }; } // namespace sharing diff --git a/sharing/transfer_metadata_matchers.h b/sharing/transfer_metadata_matchers.h index 64921792..9e85348b 100644 --- a/sharing/transfer_metadata_matchers.h +++ b/sharing/transfer_metadata_matchers.h @@ -23,6 +23,11 @@ MATCHER_P(HasStatus, status, "has status") { return arg.status() == status; } +MATCHER_P(HasUsage, usage, "has usage") { + return arg.usage() == usage; +} + + MATCHER(IsFinalStatus, "is final") { return arg.is_final_status(); } diff --git a/sharing/transfer_metadata_test.cc b/sharing/transfer_metadata_test.cc index ef2d7493..09721dcc 100644 --- a/sharing/transfer_metadata_test.cc +++ b/sharing/transfer_metadata_test.cc @@ -19,6 +19,7 @@ #include #include "gtest/gtest.h" +#include "sharing/share_session_usage.h" namespace nearby { namespace sharing { @@ -34,6 +35,7 @@ std::vector GetTestData() { kTransferMetadataToStringTestData = new std::vector({ {TransferMetadata( + ShareSessionUsage::kSharing, TransferMetadata::Status::kConnecting, /*progress=*/12.321f, /*token=*/std::nullopt, /*is_original=*/true, /*is_final_status=*/false, @@ -45,12 +47,14 @@ std::vector GetTestData() { /*transferred_attachments_count=*/0, /*in_progress_attachment_id=*/std::nullopt, /*in_progress_attachment_transferred_bytes=*/std::nullopt, - /*in_progress_attachment_total_bytes=*/std::nullopt), - "TransferMetadata"}, + /*in_progress_attachment_total_bytes=*/std::nullopt, + /*binding_id=*/""), + "TransferMetadata"}, {TransferMetadata( + ShareSessionUsage::kSharing, TransferMetadata::Status::kCancelled, /*progress=*/77.795f, std::optional{"test_token"}, @@ -62,11 +66,51 @@ std::vector GetTestData() { /*transferred_attachments_count=*/0, /*in_progress_attachment_id=*/std::nullopt, /*in_progress_attachment_transferred_bytes=*/std::nullopt, - /*in_progress_attachment_total_bytes=*/std::nullopt), - "TransferMetadata"}, + {TransferMetadata( + ShareSessionUsage::kFileSync, + TransferMetadata::Status::kCancelled, + /*progress=*/77.795f, + std::optional{"test_token"}, + /*is_original=*/false, + /*is_final_status=*/true, /*is_self_share=*/true, + /*transferred_bytes=*/123456789, /*transfer_speed=*/0, + /*estimated_time_remaining=*/123456789, + /*total_attachments_count=*/1, + /*transferred_attachments_count=*/0, + /*in_progress_attachment_id=*/std::nullopt, + /*in_progress_attachment_transferred_bytes=*/std::nullopt, + /*in_progress_attachment_total_bytes=*/std::nullopt, + /*binding_id=*/""), + "TransferMetadata"}, + {TransferMetadata( + ShareSessionUsage::kPairing, + TransferMetadata::Status::kComplete, + /*progress=*/0.0f, + std::optional{"test_token"}, + /*is_original=*/false, + /*is_final_status=*/true, /*is_self_share=*/true, + /*transferred_bytes=*/0, /*transfer_speed=*/0, + /*estimated_time_remaining=*/0, + /*total_attachments_count=*/0, + /*transferred_attachments_count=*/0, + /*in_progress_attachment_id=*/std::nullopt, + /*in_progress_attachment_transferred_bytes=*/std::nullopt, + /*in_progress_attachment_total_bytes=*/std::nullopt, + /*binding_id=*/"test_binding_id"), + "TransferMetadata"}, }); return *kTransferMetadataToStringTestData; @@ -80,7 +124,7 @@ TEST_P(TransferMetadataToStringTest, ToStringResultMatches) { GetParam().transfer_metadata.ToString()); } -INSTANTIATE_TEST_CASE_P(TransferMetadataToStringTest, +INSTANTIATE_TEST_SUITE_P(TransferMetadataToStringTest, TransferMetadataToStringTest, testing::ValuesIn(GetTestData())); diff --git a/sharing/worker_queue.h b/sharing/worker_queue.h index 0fe8a928..b9c4d958 100644 --- a/sharing/worker_queue.h +++ b/sharing/worker_queue.h @@ -16,6 +16,7 @@ #define THIRD_PARTY_NEARBY_SHARING_WORKER_QUEUE_H_ #include +#include #include #include @@ -38,7 +39,11 @@ namespace nearby::sharing { template class WorkerQueue { public: - explicit WorkerQueue(TaskRunner* task_runner) : task_runner_(task_runner) {} + explicit WorkerQueue(TaskRunner* task_runner) + : task_runner_(task_runner), + run_data_(std::make_shared()) { + run_data_->is_stopped = false; + } ~WorkerQueue() { Stop(); } @@ -52,11 +57,11 @@ class WorkerQueue { LOG(ERROR) << "WorkerQueue is already started."; return false; } - if (is_stopped_) { + if (run_data_->is_stopped) { LOG(ERROR) << "WorkerQueue is already stopped, cannot restart."; return false; } - callback_ = std::move(callback); + run_data_->callback = std::move(callback); { absl::MutexLock lock(mutex_); if (!queue_.empty()) { @@ -67,12 +72,22 @@ class WorkerQueue { } // Stops the queue. No new callback will be scheduled. + // This method will block until the callback finishes if it is currently + // running. void Stop() { - bool already_stopped = is_stopped_.exchange(true); + bool already_stopped = run_data_->is_stopped.exchange(true); if (already_stopped || !is_started_) { return; } + // Prevent new callbacks from being scheduled. is_scheduled_ = true; + // Wait for inflight callback to finish. + absl::MutexLock lock(run_data_->running_mutex); + auto stopped_running = + [this]() ABSL_EXCLUSIVE_LOCKS_REQUIRED(run_data_->running_mutex) { + return !run_data_->is_running; + }; + run_data_->running_mutex.Await(absl::Condition(&stopped_running)); } // Queues an item to be processed by the callback. @@ -95,9 +110,16 @@ class WorkerQueue { } private: + struct RunData { + std::atomic is_stopped; + absl::AnyInvocable callback; + absl::Mutex running_mutex; + bool is_running ABSL_GUARDED_BY(running_mutex) = false; + }; + void ScheduleCallback() { // Skip if not started or stopped - if (!is_started_ || is_stopped_) { + if (!is_started_ || run_data_->is_stopped) { return; } if (is_scheduled_.exchange(true)) { @@ -106,20 +128,26 @@ class WorkerQueue { return; } VLOG(1) << "Scheduling callback"; - task_runner_->PostTask([this]() { - if (is_stopped_) { - return; + task_runner_->PostTask([run_data = run_data_]() { + { + absl::MutexLock lock(run_data->running_mutex); + run_data->is_running = true; + } + if (!run_data->is_stopped) { + run_data->callback(); + } + { + absl::MutexLock lock(run_data->running_mutex); + run_data->is_running = false; } - callback_(); }); } TaskRunner* const task_runner_ = nullptr; - absl::AnyInvocable callback_; + std::shared_ptr run_data_; // Tracks whether Start() has been called. std::atomic is_started_ = false; // Tracks whether Stop() has been called. - std::atomic is_stopped_ = false; absl::Mutex mutex_; std::queue queue_ ABSL_GUARDED_BY(mutex_); // This is used track whether the callback is already scheduled so as to avoid diff --git a/sharing/worker_queue_test.cc b/sharing/worker_queue_test.cc index e9b6e3b0..a3671d61 100644 --- a/sharing/worker_queue_test.cc +++ b/sharing/worker_queue_test.cc @@ -14,10 +14,12 @@ #include "sharing/worker_queue.h" +#include #include #include "gtest/gtest.h" #include "absl/synchronization/notification.h" +#include "absl/time/time.h" #include "internal/test/fake_clock.h" #include "internal/test/fake_task_runner.h" @@ -91,12 +93,13 @@ TEST(WorkerQueueTest, QueueItemsWhileCallbackRunning) { TEST(WorkerQueueTest, StopStopsCallback) { FakeClock fake_clock; FakeTaskRunner task_runner(&fake_clock, 1); - WorkerQueue queue(&task_runner); - queue.Queue(1); - queue.Queue(2); + auto queue = std::make_unique>(&task_runner); + queue->Queue(1); + queue->Queue(2); absl::Notification notification; - EXPECT_TRUE(queue.Start([&queue, ¬ification]() { - std::queue items = queue.ReadAll(); + auto queue_ptr = queue.get(); + EXPECT_TRUE(queue->Start([queue_ptr, ¬ification]() { + std::queue items = queue_ptr->ReadAll(); EXPECT_EQ(items.size(), 2); EXPECT_EQ(items.front(), 1); EXPECT_EQ(items.back(), 2); @@ -104,8 +107,34 @@ TEST(WorkerQueueTest, StopStopsCallback) { })); // Wait for the callback to start. notification.WaitForNotification(); - queue.Stop(); - queue.Queue(3); + queue->Stop(); + queue->Queue(3); + queue.reset(); + task_runner.Sync(); + // No more callbacks. +} + +TEST(WorkerQueueTest, StopWaitsForInFlightCallback) { + FakeClock fake_clock; + FakeTaskRunner task_runner(&fake_clock, 1); + auto queue = std::make_unique>(&task_runner); + absl::Notification notification1; + absl::Notification notification2; + auto queue_ptr = queue.get(); + EXPECT_TRUE(queue->Start([queue_ptr, ¬ification1, ¬ification2]() { + std::queue items = queue_ptr->ReadAll(); + notification1.Notify(); + notification2.WaitForNotificationWithTimeout(absl::Milliseconds(500)); + EXPECT_EQ(items.size(), 2); + EXPECT_EQ(items.front(), 1); + EXPECT_EQ(items.back(), 2); + })); + queue->Queue(1); + queue->Queue(2); + // Wait for the callback to start. + notification1.WaitForNotification(); + queue->Queue(3); + queue.reset(); task_runner.Sync(); // No more callbacks. }