From 00bba362199fbe4d462775e10d2e825a9ee772ce Mon Sep 17 00:00:00 2001 From: Chun Zhang Date: Thu, 13 Apr 2023 21:17:58 -0700 Subject: [PATCH 01/63] Migrate PreferencesRepository from location/nearby to third_party/nearby PiperOrigin-RevId: 524185819 --- internal/platform/implementation/BUILD | 2 + internal/platform/implementation/apple/BUILD | 3 + .../apple/preferences_repository.h | 40 +++++ .../apple/preferences_repository.mm | 32 ++++ internal/platform/implementation/g3/BUILD | 5 +- .../g3/preferences_repository.cc | 70 +++++++++ .../g3/preferences_repository.h | 47 ++++++ .../g3/preferences_repository_test.cc | 68 ++++++++ .../implementation/preferences_repository.h | 47 ++++++ .../platform/implementation/windows/BUILD | 3 + .../windows/preferences_repository.cc | 145 ++++++++++++++++++ .../windows/preferences_repository.h | 48 ++++++ .../windows/preferences_repository_test.cc | 142 +++++++++++++++++ 13 files changed, 651 insertions(+), 1 deletion(-) create mode 100644 internal/platform/implementation/apple/preferences_repository.h create mode 100644 internal/platform/implementation/apple/preferences_repository.mm create mode 100644 internal/platform/implementation/g3/preferences_repository.cc create mode 100644 internal/platform/implementation/g3/preferences_repository.h create mode 100644 internal/platform/implementation/g3/preferences_repository_test.cc create mode 100644 internal/platform/implementation/preferences_repository.h create mode 100644 internal/platform/implementation/windows/preferences_repository.cc create mode 100644 internal/platform/implementation/windows/preferences_repository.h create mode 100644 internal/platform/implementation/windows/preferences_repository_test.cc diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index 98f7b327..31b2a52f 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -31,6 +31,7 @@ cc_library( "log_message.h", "mutex.h", "output_file.h", + "preferences_repository.h", "scheduled_executor.h", "settable_future.h", "submittable_executor.h", @@ -53,6 +54,7 @@ cc_library( "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", + "@nlohmann_json//:json", ], ) diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index a1347496..a5d76eba 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -29,6 +29,7 @@ objc_library( "log_message.mm", "multi_thread_executor.mm", "platform.mm", + "preferences_repository.mm", "scheduled_executor.mm", "timer.mm", "utils.mm", @@ -40,6 +41,7 @@ objc_library( "device_info.h", "log_message.h", "multi_thread_executor.h", + "preferences_repository.h", "scheduled_executor.h", "single_thread_executor.h", "timer.h", @@ -67,6 +69,7 @@ objc_library( "@com_google_absl//absl/strings", "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", + "@nlohmann_json//:json", ] + select({ "//tools/cc_target_os:platform_ios": [ "//third_party/apple_frameworks:UIKit", diff --git a/internal/platform/implementation/apple/preferences_repository.h b/internal/platform/implementation/apple/preferences_repository.h new file mode 100644 index 00000000..af1430df --- /dev/null +++ b/internal/platform/implementation/apple/preferences_repository.h @@ -0,0 +1,40 @@ +// 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 PLATFORM_IMPLEMENTATION_APPLE_PREFERENCES_REPOSITORY_H_ +#define PLATFORM_IMPLEMENTATION_APPLE_PREFERENCES_REPOSITORY_H_ + +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/preferences_repository.h" + +namespace nearby::apple { + +class PreferencesRepository : public api::PreferencesRepository { + public: + explicit PreferencesRepository(absl::string_view path) + : api::PreferencesRepository(path) {} + + nlohmann::json LoadPreferences() override ABSL_LOCKS_EXCLUDED(&mutex_); + bool SavePreferences(nlohmann::json preferences) override + ABSL_LOCKS_EXCLUDED(&mutex_); + + private: + absl::Mutex mutex_; +}; + +} // namespace nearby::apple + +#endif // PLATFORM_IMPLEMENTATION_APPLE_PREFERENCES_REPOSITORY_H_ diff --git a/internal/platform/implementation/apple/preferences_repository.mm b/internal/platform/implementation/apple/preferences_repository.mm new file mode 100644 index 00000000..176afd24 --- /dev/null +++ b/internal/platform/implementation/apple/preferences_repository.mm @@ -0,0 +1,32 @@ +// 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/preferences_repository.h" + +#include "absl/synchronization/mutex.h" +#include "nlohmann/json.hpp" + +namespace nearby::apple { + +nlohmann::json PreferencesRepository::LoadPreferences() { + absl::MutexLock lock(&mutex_); + return nlohmann::json::object(); +} + +bool PreferencesRepository::SavePreferences(nlohmann::json preferences) { + absl::MutexLock lock(&mutex_); + return false; +} + +} // namespace nearby::apple \ No newline at end of file diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index 1735101a..81df8931 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -18,6 +18,7 @@ cc_library( testonly = True, srcs = [ "log_message.cc", + "preferences_repository.cc", "scheduled_executor.cc", "system_clock.cc", ], @@ -30,11 +31,12 @@ cc_library( "multi_thread_executor.h", "mutex.h", "pipe.h", + "preferences_repository.h", "scheduled_executor.h", "single_thread_executor.h", "timer.h", ], - visibility = ["//visibility:private"], + visibility = ["//location/nearby/cpp:__subpackages__"], deps = [ "//internal/platform:base", "//internal/platform:logging", @@ -52,6 +54,7 @@ cc_library( "@com_google_absl//absl/time", "@com_google_glog//:glog", "@com_google_nisaba//nisaba/port:thread_pool", + "@nlohmann_json//:json", ], alwayslink = 1, ) diff --git a/internal/platform/implementation/g3/preferences_repository.cc b/internal/platform/implementation/g3/preferences_repository.cc new file mode 100644 index 00000000..0700743c --- /dev/null +++ b/internal/platform/implementation/g3/preferences_repository.cc @@ -0,0 +1,70 @@ +// 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/implementation/g3/preferences_repository.h" + +#include // NOLINT(build/c++17) +#include + +#include "absl/synchronization/mutex.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" + +namespace nearby { +namespace g3 { +namespace { +using json = nlohmann::json; +} // namespace + +json PreferencesRepository::LoadPreferences() { + absl::MutexLock lock(&mutex_); + + // Emulate Windows implementation + try { + // settings.json is used for testing, but we should look at having + // an implementation override for G3 in PreferencesManager to override + // the path for testing. + std::filesystem::path path = + std::filesystem::temp_directory_path() / "settings.json"; + if (!std::filesystem::exists(path)) { + return value_; + } + + std::ifstream preferences_file(path.c_str()); + if (!preferences_file.good()) { + return value_; + } + json preferences = json::parse(preferences_file, nullptr, false); + preferences_file.close(); + + if (preferences.is_discarded()) { + return value_; + } + + value_ = preferences; + } catch (...) { + return value_; + } + + return value_; +} + +bool PreferencesRepository::SavePreferences(json preferences) { + absl::MutexLock lock(&mutex_); + value_ = preferences; + return true; +} + +} // namespace g3 +} // namespace nearby diff --git a/internal/platform/implementation/g3/preferences_repository.h b/internal/platform/implementation/g3/preferences_repository.h new file mode 100644 index 00000000..960c89ea --- /dev/null +++ b/internal/platform/implementation/g3/preferences_repository.h @@ -0,0 +1,47 @@ +// 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_IMPLEMENTATION_G3_PREFERENCES_REPOSITORY_H_ +#define PLATFORM_IMPLEMENTATION_G3_PREFERENCES_REPOSITORY_H_ + +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/preferences_repository.h" + +namespace nearby { +namespace g3 { + +class PreferencesRepository : public api::PreferencesRepository { + public: + explicit PreferencesRepository(absl::string_view path) + : api::PreferencesRepository(path) {} + + nlohmann::json LoadPreferences() override ABSL_LOCKS_EXCLUDED(&mutex_); + bool SavePreferences(nlohmann::json preferences) override + ABSL_LOCKS_EXCLUDED(&mutex_); + + private: + // Avoid to write in google3, just create a memory value to simulate a + // preferences storage + nlohmann::json value_ = nlohmann::json::object(); + absl::Mutex mutex_; +}; + +} // namespace g3 +} // namespace nearby + +#endif // PLATFORM_IMPLEMENTATION_G3_PREFERENCES_REPOSITORY_H_ diff --git a/internal/platform/implementation/g3/preferences_repository_test.cc b/internal/platform/implementation/g3/preferences_repository_test.cc new file mode 100644 index 00000000..b407f64f --- /dev/null +++ b/internal/platform/implementation/g3/preferences_repository_test.cc @@ -0,0 +1,68 @@ +// 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/g3/preferences_repository.h" + +#include // NOLINT(build/c++17) +#include + +#include "gtest/gtest.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" + +namespace nearby { +namespace platform { +namespace g3 { +namespace { +using json = ::nlohmann::json; +} // namespace + +TEST(Preferences, TestSaveAndGetPreferences) { + PreferencesRepository preferences_repository{ + std::filesystem::temp_directory_path().string()}; + std::string string_key = "string_value"; + std::string string_value = "hello world"; + std::string int_key = "int_value"; + json prefs = {{int_key, 345}, {string_key, string_value}}; + + EXPECT_TRUE(preferences_repository.SavePreferences(prefs)); + + auto result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result[string_key].get(), string_value); + EXPECT_EQ(result[int_key].get(), 345); +} + +TEST(Preferences, TestMultipleSaveAndGetPreferences) { + PreferencesRepository preferences_repository{ + std::filesystem::temp_directory_path().string()}; + std::string string_key = "string_value"; + std::string string_value = "hello world"; + std::string string_new_value = "again"; + std::string int_key = "int_value"; + json prefs = {{int_key, 345}, {string_key, string_value}}; + EXPECT_TRUE(preferences_repository.SavePreferences(prefs)); + + json result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result[string_key].get(), string_value); + prefs[string_key] = string_new_value; + prefs[int_key] = 456; + EXPECT_TRUE(preferences_repository.SavePreferences(prefs)); + result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result[string_key].get(), string_new_value); + EXPECT_EQ(result[int_key].get(), 456); +} + +} // namespace g3 +} // namespace platform +} // namespace nearby diff --git a/internal/platform/implementation/preferences_repository.h b/internal/platform/implementation/preferences_repository.h new file mode 100644 index 00000000..d3840ded --- /dev/null +++ b/internal/platform/implementation/preferences_repository.h @@ -0,0 +1,47 @@ +// 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 PLATFORM_IMPLEMENTATION_PREFERENCE_REPOSITORY_H_ +#define PLATFORM_IMPLEMENTATION_PREFERENCE_REPOSITORY_H_ + +#include + +#include "absl/strings/string_view.h" +#include "nlohmann/json_fwd.hpp" + +namespace nearby { +namespace api { + +// A repository for preferences. The implementations are different on different +// platforms. +// +// The data in preferences has multiple types, such as int, bool, string and +// dictionary. Using proto to describe it is a little complicated. In the +// repository, we use json as the parser for now. +class PreferencesRepository { + public: + explicit PreferencesRepository(absl::string_view path) : path_(path) {} + virtual ~PreferencesRepository() = default; + + virtual nlohmann::json LoadPreferences() = 0; + virtual bool SavePreferences(nlohmann::json preferences) = 0; + + protected: + std::string path_; +}; + +} // namespace api +} // namespace nearby + +#endif // PLATFORM_IMPLEMENTATION_PREFERENCE_REPOSITORY_H_ diff --git a/internal/platform/implementation/windows/BUILD b/internal/platform/implementation/windows/BUILD index e76c9872..38bdfc5b 100644 --- a/internal/platform/implementation/windows/BUILD +++ b/internal/platform/implementation/windows/BUILD @@ -33,6 +33,7 @@ cc_library( "log_message.h", "mutex.h", "output_file.h", + "preferences_repository.h", "scheduled_executor.h", "settable_future.h", "submittable_executor.h", @@ -148,6 +149,7 @@ cc_library( "file_path.cc", "http_loader.cc", "platform.cc", + "preferences_repository.cc", "scheduled_executor.cc", "submittable_executor.cc", "system_clock.cc", @@ -239,6 +241,7 @@ cc_test( "executor_test.cc", "file_path_test.cc", "http_loader_test.cc", + "preferences_repository_test.cc", "scheduled_executor_test.cc", "submittable_executor_test.cc", "thread_pool_test.cc", diff --git a/internal/platform/implementation/windows/preferences_repository.cc b/internal/platform/implementation/windows/preferences_repository.cc new file mode 100644 index 00000000..5c323c20 --- /dev/null +++ b/internal/platform/implementation/windows/preferences_repository.cc @@ -0,0 +1,145 @@ +// 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/preferences_repository.h" + +#include +#include // NOLINT(build/c++17) +#include +#include + +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/logging.h" + +namespace nearby { +namespace windows { +namespace { +using json = ::nlohmann::json; + +constexpr char kPreferencesFileName[] = "preferences.json"; +constexpr char kPreferencesBackupFileName[] = "preferences_bak.json"; + +} // namespace + +json PreferencesRepository::LoadPreferences() { + absl::MutexLock lock(&mutex_); + std::optional preferences = AttemptLoad(); + if (preferences.has_value()) { + return preferences.value(); + } + + NEARBY_LOGS(ERROR) << "Could not load preferences file, trying backup."; + + // In the future we should switch to using a transaction log or another + // stable method which doesn't pose a risk of losing settings + preferences = RestoreFromBackup(); + if (preferences.has_value()) { + NEARBY_LOGS(ERROR) << "Successfully recovered from backup."; + return preferences.value(); + } + + NEARBY_LOGS(ERROR) << "Failed to load preferences file from back up."; + + return json::object(); +} + +bool PreferencesRepository::SavePreferences(json preferences) { + absl::MutexLock lock(&mutex_); + try { + std::filesystem::path path = path_; + if (!std::filesystem::exists(path) && + !std::filesystem::create_directories(path)) { + NEARBY_LOGS(ERROR) << "Failed to create preferences path."; + return false; + } + + std::filesystem::path full_name = path / kPreferencesFileName; + std::filesystem::path full_name_backup = path / kPreferencesBackupFileName; + + // Create a backup without moving the bytes on disk + if (std::filesystem::exists(full_name)) { + NEARBY_LOGS(INFO) << "Making backup of preferences file."; + std::filesystem::rename(full_name, full_name_backup); + } + + std::ofstream preferences_file(full_name.c_str()); + preferences_file << preferences; + preferences_file.close(); + + // Make sure the file wasn't saved in a corrupted state + if (!AttemptLoad().has_value()) { + NEARBY_LOGS(ERROR) << "Preferences saved to disk in corrupted state. " + "Restoring from backup."; + + if (!RestoreFromBackup().has_value()) { + NEARBY_LOGS(ERROR) << "Failed to restore preferences file."; + return false; + } + } + } catch (const std::exception& e) { + NEARBY_LOGS(ERROR) << "Failed to save preferences file: " << e.what(); + return false; + } + + return true; +} + +std::optional PreferencesRepository::AttemptLoad() { + std::filesystem::path path = path_; + std::filesystem::path full_name = path / kPreferencesFileName; + if (!std::filesystem::exists(path) || !std::filesystem::exists(full_name)) { + return std::nullopt; + } + + try { + std::ifstream preferences_file(full_name.c_str()); + if (!preferences_file.good()) { + return std::nullopt; + } + + json preferences = json::parse(preferences_file, nullptr, false); + preferences_file.close(); + + if (preferences.is_discarded()) { + NEARBY_LOGS(ERROR) << "Preferences file corrupted."; + return std::nullopt; + } + + return preferences; + } catch (const std::exception& e) { + NEARBY_LOGS(ERROR) << "Exception while loading preferences: " << e.what(); + return std::nullopt; + } +} + +std::optional PreferencesRepository::RestoreFromBackup() { + std::filesystem::path path = path_; + std::filesystem::path full_name = path / kPreferencesFileName; + std::filesystem::path full_name_backup = path / kPreferencesBackupFileName; + + if (!std::filesystem::exists(full_name_backup)) { + NEARBY_LOGS(WARNING) + << "Backup requested but no backup preferences file found."; + return std::nullopt; + } + + std::filesystem::rename(full_name_backup, full_name); + + NEARBY_LOGS(INFO) << "Attempting load from backup preferences."; + return AttemptLoad(); +} + +} // namespace windows +} // namespace nearby diff --git a/internal/platform/implementation/windows/preferences_repository.h b/internal/platform/implementation/windows/preferences_repository.h new file mode 100644 index 00000000..1ed532a9 --- /dev/null +++ b/internal/platform/implementation/windows/preferences_repository.h @@ -0,0 +1,48 @@ +// 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_IMPLEMENTATION_WINDOWS_PREFERENCES_REPOSITORY_H_ +#define PLATFORM_IMPLEMENTATION_WINDOWS_PREFERENCES_REPOSITORY_H_ + +#include + +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/preferences_repository.h" + +namespace nearby { +namespace windows { + +class PreferencesRepository : public api::PreferencesRepository { + public: + explicit PreferencesRepository(absl::string_view path) + : api::PreferencesRepository(path) {} + + nlohmann::json LoadPreferences() override ABSL_LOCKS_EXCLUDED(&mutex_); + bool SavePreferences(nlohmann::json preferences) override + ABSL_LOCKS_EXCLUDED(&mutex_); + + std::optional AttemptLoad(); + std::optional RestoreFromBackup(); + + private: + absl::Mutex mutex_; +}; + +} // namespace windows +} // namespace nearby + +#endif // PLATFORM_IMPLEMENTATION_WINDOWS_PREFERENCES_REPOSITORY_H_ diff --git a/internal/platform/implementation/windows/preferences_repository_test.cc b/internal/platform/implementation/windows/preferences_repository_test.cc new file mode 100644 index 00000000..78794a00 --- /dev/null +++ b/internal/platform/implementation/windows/preferences_repository_test.cc @@ -0,0 +1,142 @@ +// 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/preferences_repository.h" + +#include // NOLINT(build/c++17) +#include +#include + +#include "gtest/gtest.h" +#include "nlohmann/json.hpp" +#include "nlohmann/json_fwd.hpp" +#include "internal/platform/implementation/device_info.h" +#include "internal/platform/implementation/platform.h" + +namespace nearby { +namespace windows { +namespace { + +using json = ::nlohmann::json; + +constexpr char kPreferencesFileName[] = "preferences.json"; +constexpr char kPreferencesBackupFileName[] = "preferences_bak.json"; +constexpr char kPreferencesPath[] = "Google/Nearby/Sharing"; + +TEST(PreferencesRepository, LoadWithBadPath) { + PreferencesRepository preferences_repository{"c:\\users\\a\\b\\c\\d\\e\\f"}; + json result = preferences_repository.LoadPreferences(); + EXPECT_TRUE(result.empty()); +} + +TEST(PreferencesRepository, SaveAndLoadPreferences) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + PreferencesRepository preferences_repository{full_path.string()}; + json data; + data["key1"] = "value1"; + data["key2"] = "value2"; + EXPECT_TRUE(preferences_repository.SavePreferences(data)); + json result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result.size(), 2); + EXPECT_EQ(result["key1"], "value1"); + EXPECT_EQ(result["key2"], "value2"); + std::filesystem::remove(full_name); +} + +TEST(PreferencesRepository, LoadFromBackup) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + std::filesystem::path full_name_backup = + full_path / kPreferencesBackupFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + if (std::filesystem::exists(full_name_backup)) { + std::filesystem::remove(full_name_backup); + } + + PreferencesRepository preferences_repository{full_path.string()}; + json data; + data["key1"] = "value1"; + data["key2"] = "value2"; + + std::ofstream backup_file(full_name_backup.c_str()); + backup_file << data; + backup_file.close(); + + std::optional result; + result = preferences_repository.AttemptLoad(); + EXPECT_FALSE(result.has_value()); + result = preferences_repository.RestoreFromBackup(); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(result.value()["key1"], "value1"); + EXPECT_EQ(result.value()["key2"], "value2"); + std::filesystem::remove(full_name); + EXPECT_FALSE(std::filesystem::exists(full_name_backup)); +} + +TEST(PreferencesRepository, RecoverFromCorruption) { + std::optional app_data_path = + api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath(); + ASSERT_TRUE(app_data_path.has_value()); + std::filesystem::path full_path = *app_data_path / kPreferencesPath; + std::filesystem::path full_name = full_path / kPreferencesFileName; + std::filesystem::path full_name_backup = + full_path / kPreferencesBackupFileName; + + if (std::filesystem::exists(full_name)) { + std::filesystem::remove(full_name); + } + + if (std::filesystem::exists(full_name_backup)) { + std::filesystem::remove(full_name_backup); + } + + PreferencesRepository preferences_repository{full_path.string()}; + json data; + data["key1"] = "value1"; + data["key2"] = "value2"; + + std::ofstream preferences_file(full_name_backup.c_str()); + preferences_file << data; + preferences_file.close(); + + std::ofstream backup_file(full_name.c_str()); + backup_file << "[BAD JSON FILE]"; + backup_file.close(); + + std::optional result = preferences_repository.LoadPreferences(); + EXPECT_EQ(result.value()["key1"], "value1"); + EXPECT_EQ(result.value()["key2"], "value2"); + std::filesystem::remove(full_name); + EXPECT_FALSE(std::filesystem::exists(full_name_backup)); +} + +} // namespace +} // namespace windows +} // namespace nearby From 6cdc9890b5f83ff731a6363a785272bd1a75f87e Mon Sep 17 00:00:00 2001 From: Janusz Sobczak Date: Fri, 14 Apr 2023 10:43:44 -0700 Subject: [PATCH 02/63] Enable cancellation flag support by default PiperOrigin-RevId: 524329836 --- internal/platform/feature_flags.h | 2 +- internal/platform/feature_flags_test.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/platform/feature_flags.h b/internal/platform/feature_flags.h index 9aae0f39..8ff66d12 100644 --- a/internal/platform/feature_flags.h +++ b/internal/platform/feature_flags.h @@ -26,7 +26,7 @@ class FeatureFlags { public: // Holds for all the feature flags. struct Flags { - bool enable_cancellation_flag = false; + bool enable_cancellation_flag = true; bool enable_async_bandwidth_upgrade = true; // If a scheduled runnable is already running, Cancel() will synchronously // wait for the task to complete. diff --git a/internal/platform/feature_flags_test.cc b/internal/platform/feature_flags_test.cc index 3d4925ef..e6e4eedd 100644 --- a/internal/platform/feature_flags_test.cc +++ b/internal/platform/feature_flags_test.cc @@ -21,23 +21,23 @@ namespace nearby { namespace { constexpr FeatureFlags::Flags kTestFeatureFlags{ - .enable_cancellation_flag = true, + .enable_cancellation_flag = false, .keep_alive_interval_millis = 5000, .keep_alive_timeout_millis = 30000}; TEST(FeatureFlagsTest, ToSetFeatureWorks) { const FeatureFlags& features = FeatureFlags::GetInstance(); - EXPECT_FALSE(features.GetFlags().enable_cancellation_flag); + EXPECT_TRUE(features.GetFlags().enable_cancellation_flag); EXPECT_EQ(5000, features.GetFlags().keep_alive_interval_millis); EXPECT_EQ(30000, features.GetFlags().keep_alive_timeout_millis); MediumEnvironment& medium_environment = MediumEnvironment::Instance(); medium_environment.SetFeatureFlags(kTestFeatureFlags); - EXPECT_TRUE(features.GetFlags().enable_cancellation_flag); + EXPECT_FALSE(features.GetFlags().enable_cancellation_flag); const FeatureFlags& another_features_ref = FeatureFlags::GetInstance(); - EXPECT_TRUE(another_features_ref.GetFlags().enable_cancellation_flag); + EXPECT_FALSE(another_features_ref.GetFlags().enable_cancellation_flag); } } // namespace From 09b3ab0882984d2e17056b9c06ec2cefaaae0cb7 Mon Sep 17 00:00:00 2001 From: Juliet Levesque Date: Fri, 14 Apr 2023 11:59:45 -0700 Subject: [PATCH 03/63] [Nearby Presence] Add DEVICE_TYPE_CHROMEOS to Metadata DeviceType PiperOrigin-RevId: 524350458 --- internal/proto/metadata.proto | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/proto/metadata.proto b/internal/proto/metadata.proto index 91fdbeb9..948b47cd 100644 --- a/internal/proto/metadata.proto +++ b/internal/proto/metadata.proto @@ -66,4 +66,8 @@ enum DeviceType { // The device is a watch. DEVICE_TYPE_WATCH = 6; + + // The device is a ChromeOS device. ChromeOS can be a laptop, desktop, or + // convertible (tablet + clamshell). + DEVICE_TYPE_CHROMEOS = 7; } From 6dac39292b84a3b4271203fbd63b850bce8d957f Mon Sep 17 00:00:00 2001 From: hai007 Date: Fri, 14 Apr 2023 13:15:59 -0700 Subject: [PATCH 04/63] Remove unneeded fastpair dependency. PiperOrigin-RevId: 524369312 --- internal/base/BUILD | 2 -- internal/platform/implementation/BUILD | 1 - internal/platform/implementation/windows/generated/BUILD | 1 - 3 files changed, 4 deletions(-) diff --git a/internal/base/BUILD b/internal/base/BUILD index a7cc6631..c49f3e13 100644 --- a/internal/base/BUILD +++ b/internal/base/BUILD @@ -14,7 +14,6 @@ cc_library( "//fastpair:__subpackages__", "//internal:__pkg__", "//internal/platform:__pkg__", - "//location/nearby/cpp/fastpair:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", ], deps = [ @@ -38,7 +37,6 @@ cc_library( visibility = [ "//fastpair:__subpackages__", "//internal:__subpackages__", - "//location/nearby/cpp/fastpair:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", ], deps = [ diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index 31b2a52f..c6ee74eb 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -119,7 +119,6 @@ cc_library( "//internal/network:__subpackages__", "//internal/platform:__pkg__", "//internal/platform/implementation:__subpackages__", - "//location/nearby/cpp/fastpair:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", ], deps = [ diff --git a/internal/platform/implementation/windows/generated/BUILD b/internal/platform/implementation/windows/generated/BUILD index 4451d2e2..da742cb1 100644 --- a/internal/platform/implementation/windows/generated/BUILD +++ b/internal/platform/implementation/windows/generated/BUILD @@ -45,7 +45,6 @@ cc_library( "//internal:__subpackages__", "//internal/platform/implementation/windows:__subpackages__", "//location/nearby/apps/better_together/windows:__subpackages__", - "//location/nearby/cpp/fastpair/internal:__subpackages__", "//location/nearby/cpp/sharing/implementation/internal:__subpackages__", ], ) From 49aa73bbddcbfa2899020b2da0365ba92caab794 Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Fri, 14 Apr 2023 16:55:08 -0700 Subject: [PATCH 05/63] Fixed bug of folder sharing PiperOrigin-RevId: 524417795 --- .../windows/bluetooth_classic_socket.cc | 17 ++++++++++++----- .../windows/bluetooth_classic_socket.h | 8 ++++---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/internal/platform/implementation/windows/bluetooth_classic_socket.cc b/internal/platform/implementation/windows/bluetooth_classic_socket.cc index 71250a57..7a89d01d 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/windows/bluetooth_classic_socket.cc @@ -156,12 +156,18 @@ BluetoothSocket::BluetoothInputStream::BluetoothInputStream( ExceptionOr BluetoothSocket::BluetoothInputStream::Read( std::int64_t size) { try { - if (size <= 0 || size > kMaxTransmitPacketSize) { + if (size <= 0) { NEARBY_LOGS(ERROR) << __func__ << ": Invalid transmit packet size: " << size; return {Exception::kIo}; } + if (size > read_buffer_.Capacity()) { + NEARBY_LOGS(WARNING) << __func__ + << ": resize receive buffer to packet size: " << size; + read_buffer_ = Buffer(size); + } + // Init the read buffer. read_buffer_.Length(0); @@ -223,10 +229,11 @@ BluetoothSocket::BluetoothOutputStream::BluetoothOutputStream( Exception BluetoothSocket::BluetoothOutputStream::Write(const ByteArray& data) { try { - if (data.size() > kMaxTransmitPacketSize) { - NEARBY_LOGS(ERROR) << __func__ << ": Transmit packet size " << data.size() - << " is too big."; - return {Exception::kIo}; + if (data.size() > write_buffer_.Capacity()) { + NEARBY_LOGS(WARNING) << __func__ + << ": resize write buffer to packet size: " + << data.size(); + write_buffer_ = Buffer(data.size()); } std::memcpy(write_buffer_.data(), data.data(), data.size()); diff --git a/internal/platform/implementation/windows/bluetooth_classic_socket.h b/internal/platform/implementation/windows/bluetooth_classic_socket.h index 786c2104..9fd92614 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_socket.h +++ b/internal/platform/implementation/windows/bluetooth_classic_socket.h @@ -101,7 +101,7 @@ class BluetoothSocket : public api::BluetoothSocket { IAsyncAction CancelIOAsync(); private: - static constexpr int kMaxTransmitPacketSize = 4096; + static constexpr int kInitialTransmitPacketSize = 4096; class BluetoothInputStream : public InputStream { public: @@ -113,7 +113,7 @@ class BluetoothSocket : public api::BluetoothSocket { private: IInputStream winrt_input_stream_{nullptr}; - Buffer read_buffer_{kMaxTransmitPacketSize}; + Buffer read_buffer_{kInitialTransmitPacketSize}; }; class BluetoothOutputStream : public OutputStream { @@ -128,11 +128,11 @@ class BluetoothSocket : public api::BluetoothSocket { private: IOutputStream winrt_output_stream_{nullptr}; - Buffer write_buffer_{kMaxTransmitPacketSize}; + Buffer write_buffer_{kInitialTransmitPacketSize}; }; bool InternalConnect(HostName connectionHostName, - winrt::hstring connectionServiceName); + winrt::hstring connectionServiceName); winrt::fire_and_forget Listener_ConnectionStatusChanged( winrt::Windows::Devices::Bluetooth::BluetoothDevice device, From e57591aede146e9da86411c3a5fbbb72d3e1c63b Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Fri, 14 Apr 2023 19:50:16 -0700 Subject: [PATCH 06/63] Revert back cl/522520410; iOS still need to broadcast all the data back. PiperOrigin-RevId: 524442774 --- internal/platform/ble_v2.cc | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/internal/platform/ble_v2.cc b/internal/platform/ble_v2.cc index 6fd759c9..584062d3 100644 --- a/internal/platform/ble_v2.cc +++ b/internal/platform/ble_v2.cc @@ -82,12 +82,9 @@ bool BleV2Medium::StartScanning(const Uuid& service_uuid, [this](api::ble_v2::BlePeripheral& peripheral, BleAdvertisementData advertisement_data) { MutexLock lock(&mutex_); - if (peripherals_.contains(&peripheral)) { - NEARBY_LOGS(INFO) - << "There is no need to callback due to peripheral impl=" - << &peripheral << ", which already exists."; - return; - } else { + if (!peripherals_.contains(&peripheral)) { + NEARBY_LOGS(INFO) << "Peripheral impl=" << &peripheral + << " is not existed; adds it to the map."; peripherals_.insert(&peripheral); } From 31f3f5300004c1d92c83244faff2487346f228ac Mon Sep 17 00:00:00 2001 From: Suet-Fei Li Date: Fri, 14 Apr 2023 20:55:12 -0700 Subject: [PATCH 07/63] Fix crypto include path for Chromium. PiperOrigin-RevId: 524452486 --- internal/crypto/BUILD | 1 + internal/crypto/random.cc | 7 ----- internal/crypto/random.h | 16 +++------- internal/crypto/random_unittest.cc | 8 +++-- internal/platform/implementation/BUILD | 2 ++ internal/platform/implementation/crypto.h | 14 +++++++++ internal/platform/task_runner_impl.cc | 4 +-- presence/data_types.h | 9 ++++++ .../implementation/base_broadcast_request.cc | 9 ++++-- presence/implementation/broadcast_manager.cc | 6 ++-- .../implementation/credential_manager_impl.cc | 30 +++++++++++++------ presence/implementation/scan_manager.cc | 4 +-- presence/presence_device.cc | 7 +++-- 13 files changed, 75 insertions(+), 42 deletions(-) diff --git a/internal/crypto/BUILD b/internal/crypto/BUILD index a9db74d2..e18aadea 100644 --- a/internal/crypto/BUILD +++ b/internal/crypto/BUILD @@ -98,6 +98,7 @@ cc_test( ], deps = [ ":crypto", + "//internal/platform/implementation:types", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/strings", "@com_google_absl//absl/types:span", diff --git a/internal/crypto/random.cc b/internal/crypto/random.cc index 07615b21..ee0ddf72 100644 --- a/internal/crypto/random.cc +++ b/internal/crypto/random.cc @@ -30,11 +30,4 @@ void RandBytes(absl::Span bytes) { RandBytes(bytes.data(), bytes.size()); } -std::string RandBytes(size_t length) { - std::string result(length, 0); - RandBytes(const_cast(result.data()), - result.size()); - return result; -} - } // namespace crypto diff --git a/internal/crypto/random.h b/internal/crypto/random.h index 213bedc8..4b70063e 100644 --- a/internal/crypto/random.h +++ b/internal/crypto/random.h @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +//*** WARNING!!! Do not add more functions and Data types to this file. *** +// This file needs to be in sync with: +// https://source.chromium.org/chromium/chromium/src/+/main:crypto/random.h + #ifndef THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RANDOM_H_ #define THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RANDOM_H_ @@ -32,18 +36,6 @@ CRYPTO_EXPORT void RandBytes(void *bytes, size_t length); // Fills |bytes| with cryptographically-secure random bits. CRYPTO_EXPORT void RandBytes(absl::Span bytes); -// Returns |length| random bytes. -CRYPTO_EXPORT std::string RandBytes(size_t length); - -// Creates an object of type T initialized with random data. -// This template should be used for simple data types: int, char, etc. -template -T RandData() { - T data; - RandBytes(&data, sizeof(data)); - return data; -} - } // namespace crypto #endif // THIRD_PARTY_NEARBY_INTERNAL_CRYPTO_RANDOM_H_ diff --git a/internal/crypto/random_unittest.cc b/internal/crypto/random_unittest.cc index 0c30222e..4cf33ffa 100644 --- a/internal/crypto/random_unittest.cc +++ b/internal/crypto/random_unittest.cc @@ -20,6 +20,7 @@ #include "gtest/gtest.h" #include "internal/crypto/nearby_base.h" +#include "internal/platform/implementation/crypto.h" // Basic functionality tests. Does NOT test the security of the random data. @@ -46,15 +47,16 @@ TEST(RandBytes, RandBytes) { TEST(RandBytes, RandomString) { constexpr size_t kSize = 30; - std::string bytes = RandBytes(kSize); + std::string bytes(kSize, 0); + RandBytes(const_cast(bytes.data()), bytes.size()); EXPECT_EQ(bytes.size(), kSize); EXPECT_TRUE(!IsTrivial(bytes)); } TEST(RandBytes, RandData) { - uint64_t x = RandData(); - uint64_t y = RandData(); + uint64_t x = nearby::RandData(); + uint64_t y = nearby::RandData(); // Once in a billion years, consecutively generated random numbers will be // the same and the test will fail. diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index c6ee74eb..66a0f5b7 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -40,6 +40,7 @@ cc_library( ], visibility = [ "//fastpair:__subpackages__", + "//internal/crypto:__pkg__", "//internal/platform:__pkg__", "//internal/platform/implementation:__subpackages__", "//internal/test:__subpackages__", @@ -49,6 +50,7 @@ cc_library( "//presence:__subpackages__", ], deps = [ + "//internal/crypto", "//internal/platform:base", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/functional:any_invocable", diff --git a/internal/platform/implementation/crypto.h b/internal/platform/implementation/crypto.h index 393f4d1f..ef53ff53 100644 --- a/internal/platform/implementation/crypto.h +++ b/internal/platform/implementation/crypto.h @@ -16,6 +16,11 @@ #define PLATFORM_API_CRYPTO_H_ #include "absl/strings/string_view.h" +#ifdef NEARBY_CHROMIUM +#include "crypto/random.h" +#else +#include "internal/crypto/random.h" +#endif #include "internal/platform/byte_array.h" namespace nearby { @@ -31,6 +36,15 @@ class Crypto { static ByteArray Sha256(absl::string_view input); }; +// Creates an object of type T initialized with random data. +// This template should be used for simple data types: int, char, etc. +template +T RandData() { + T data; + ::crypto::RandBytes(&data, sizeof(data)); + return data; +} + } // namespace nearby #endif // PLATFORM_API_CRYPTO_H_ diff --git a/internal/platform/task_runner_impl.cc b/internal/platform/task_runner_impl.cc index ac400d1f..587f5319 100644 --- a/internal/platform/task_runner_impl.cc +++ b/internal/platform/task_runner_impl.cc @@ -18,7 +18,7 @@ #include #include "absl/functional/any_invocable.h" -#include "internal/crypto/random.h" +#include "internal/platform/implementation/crypto.h" #include "internal/platform/timer_impl.h" namespace nearby { @@ -66,6 +66,6 @@ bool TaskRunnerImpl::PostDelayedTask(absl::Duration delay, return false; } -uint64_t TaskRunnerImpl::GenerateId() { return ::crypto::RandData(); } +uint64_t TaskRunnerImpl::GenerateId() { return nearby::RandData(); } } // namespace nearby diff --git a/presence/data_types.h b/presence/data_types.h index 8333e7ff..21700bb9 100644 --- a/presence/data_types.h +++ b/presence/data_types.h @@ -59,6 +59,15 @@ struct BroadcastCallback { }; }; +// Chromium uses its own crypto library instead of nearby/internal/crypto, +// in which base::span is used instead of absl::Span. See b/276368162. +#ifdef NEARBY_CHROMIUM +template +using CryptoSpan = base::span; +#else +template +using CryptoSpan = absl::Span; +#endif } // namespace presence } // namespace nearby diff --git a/presence/implementation/base_broadcast_request.cc b/presence/implementation/base_broadcast_request.cc index 2171c8f5..935d7ccc 100644 --- a/presence/implementation/base_broadcast_request.cc +++ b/presence/implementation/base_broadcast_request.cc @@ -19,7 +19,7 @@ #include "absl/status/status.h" #include "absl/strings/string_view.h" -#include "internal/crypto/random.h" +#include "internal/platform/implementation/crypto.h" #include "internal/platform/logging.h" #include "presence/broadcast_request.h" #include "presence/implementation/action_factory.h" @@ -72,9 +72,14 @@ BasePresenceRequestBuilder::operator BaseBroadcastRequest() const { .account_name = account_name_, .identity_type = identity_}, .action = action_}; + + std::string bytes(kSaltSize, 0); + crypto::RandBytes(const_cast(bytes.data()), + bytes.size()); + BaseBroadcastRequest broadcast_request{ .variant = presence, - .salt = salt_.size() == kSaltSize ? salt_ : crypto::RandBytes(kSaltSize), + .salt = salt_.size() == kSaltSize ? salt_ : bytes, .tx_power = tx_power_, .power_mode = power_mode_}; return broadcast_request; diff --git a/presence/implementation/broadcast_manager.cc b/presence/implementation/broadcast_manager.cc index 33e0edcc..5bc5ed3a 100644 --- a/presence/implementation/broadcast_manager.cc +++ b/presence/implementation/broadcast_manager.cc @@ -23,7 +23,7 @@ #include #include "absl/time/time.h" -#include "internal/crypto/random.h" +#include "internal/platform/implementation/crypto.h" #include "internal/platform/implementation/system_clock.h" #include "internal/platform/logging.h" #include "presence/implementation/advertisement_factory.h" @@ -66,7 +66,7 @@ std::string SelectSalt(LocalCredential& credential, if (!credential.consumed_salts().contains(s)) { break; } - s = crypto::RandData(); + s = nearby::RandData(); } credential.mutable_consumed_salts()->insert({s, true}); return SaltFromInt(s); @@ -235,7 +235,7 @@ void BroadcastManager::StopBroadcast(BroadcastSessionId id) { } BroadcastSessionId BroadcastManager::GenerateBroadcastSessionId() { - return ::crypto::RandData(); + return nearby::RandData(); } void BroadcastManager::BroadcastSessionState::SetAdvertisingSession( diff --git a/presence/implementation/credential_manager_impl.cc b/presence/implementation/credential_manager_impl.cc index 63e73199..67800870 100644 --- a/presence/implementation/credential_manager_impl.cc +++ b/presence/implementation/credential_manager_impl.cc @@ -25,10 +25,17 @@ #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" +#ifdef NEARBY_CHROMIUM +#include "crypto/aead.h" +#include "crypto/ec_private_key.h" +#include "crypto/hkdf.h" +#include "crypto/random.h" +#else #include "internal/crypto/aead.h" #include "internal/crypto/ec_private_key.h" #include "internal/crypto/hkdf.h" #include "internal/crypto/random.h" +#endif #include "internal/platform/base64_utils.h" #include "internal/platform/future.h" #include "internal/platform/implementation/credential_callbacks.h" @@ -36,6 +43,7 @@ #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" @@ -56,13 +64,13 @@ constexpr char kPairedKeyAliasPrefix[] = "nearby_presence_paired_key_alias_"; // Returns a random duration in [0, max_duration] range. absl::Duration RandomDuration(absl::Duration max_duration) { - uint32_t random = ::crypto::RandData(); + 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=*/bytes, + /*ikm=*/std::string(bytes), // NOLINT /*salt=*/std::string(CredentialManagerImpl::kAuthenticityKeyByteSize, 0), /*info=*/"", /*derived_key_size=*/len); } @@ -164,7 +172,9 @@ CredentialManagerImpl::CreateLocalCredential(const Metadata& metadata, private_credential.set_identity_type(identity_type); // Creates an AES key to encrypt the whole broadcast. - std::string secret_key = crypto::RandBytes(kAuthenticityKeyByteSize); + std::string secret_key(kAuthenticityKeyByteSize, 0); + crypto::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 @@ -186,7 +196,9 @@ CredentialManagerImpl::CreateLocalCredential(const Metadata& metadata, private_credential.mutable_connection_signing_key()->set_key( std::string(private_key.begin(), private_key.end())); // Create an AES key to encrypt the device metadata. - auto metadata_key = crypto::RandBytes(kBaseMetadataSize); + std::string metadata_key(kBaseMetadataSize, 0); + crypto::RandBytes(const_cast(metadata_key.data()), + metadata_key.size()); private_credential.set_metadata_encryption_key(metadata_key); // Generate the public credential @@ -260,7 +272,7 @@ std::string CredentialManagerImpl::DecryptMetadata( auto result = aead.Open(encrypted_metadata_bytes, /*nonce=*/ iv_bytes, - /*additional_data=*/absl::Span()); + /*additional_data=*/CryptoSpan()); return std::string(result.value().begin(), result.value().end()); } @@ -285,7 +297,7 @@ std::string CredentialManagerImpl::EncryptMetadata( auto encrypted = aead.Seal(metadata_bytes, /*nonce=*/ iv_bytes, - /*additional_data=*/absl::Span()); + /*additional_data=*/CryptoSpan()); return std::string(encrypted.begin(), encrypted.end()); } @@ -295,8 +307,8 @@ std::vector CredentialManagerImpl::ExtendMetadataEncryptionKey( return crypto::HkdfSha256( std::vector(metadata_encryption_key.begin(), metadata_encryption_key.end()), - /*salt=*/absl::Span(), - /*info=*/absl::Span(), kNearbyPresenceNumBytesAesGcmKeySize); + /*salt=*/CryptoSpan(), + /*info=*/CryptoSpan(), kNearbyPresenceNumBytesAesGcmKeySize); } void CredentialManagerImpl::GetLocalCredentials( @@ -354,7 +366,7 @@ SubscriberId CredentialManagerImpl::SubscribeForPublicCredentials( const CredentialSelector& credential_selector, PublicCredentialType public_credential_type, GetPublicCredentialsResultCallback callback) { - SubscriberId id = ::crypto::RandData(); + SubscriberId id = nearby::RandData(); RunOnServiceControllerThread( "add-subscriber", [this, key = SubscriberKey{credential_selector, public_credential_type}, diff --git a/presence/implementation/scan_manager.cc b/presence/implementation/scan_manager.cc index 31b98bf9..3d209e1c 100644 --- a/presence/implementation/scan_manager.cc +++ b/presence/implementation/scan_manager.cc @@ -23,7 +23,7 @@ #include "absl/status/status.h" #include "absl/types/variant.h" -#include "internal/crypto/random.h" +#include "internal/platform/implementation/crypto.h" #include "internal/platform/future.h" #include "internal/platform/implementation/ble_v2.h" #include "internal/platform/implementation/credential_callbacks.h" @@ -46,7 +46,7 @@ using ScanningCallback = ::nearby::api::ble_v2::BleMedium::ScanningCallback; ScanSessionId ScanManager::StartScan(ScanRequest scan_request, ScanCallback cb) { - ScanSessionId id = ::crypto::RandData(); + ScanSessionId id = nearby::RandData(); RunOnServiceControllerThread( "start-scan", [this, id, scan_request, scan_callback = std::move(cb)]() diff --git a/presence/presence_device.cc b/presence/presence_device.cc index 474a9d20..747eae15 100644 --- a/presence/presence_device.cc +++ b/presence/presence_device.cc @@ -17,7 +17,7 @@ #include #include -#include "internal/crypto/random.h" +#include "internal/platform/implementation/crypto.h" #include "internal/device.h" #include "internal/platform/ble_connection_info.h" #include "internal/platform/implementation/system_clock.h" @@ -28,7 +28,10 @@ namespace presence { namespace { std::string GenerateRandomEndpointId() { - return crypto::RandBytes(kEndpointIdLength); + std::string result(kEndpointIdLength, 0); + crypto::RandBytes(const_cast(result.data()), + result.size()); + return result; } } // namespace From b68431e6a8e920a2f8e8bd59b5f25a25d6a36d31 Mon Sep 17 00:00:00 2001 From: hai007 Date: Sat, 15 Apr 2023 20:29:25 -0700 Subject: [PATCH 08/63] Add IFTTT comment for linter. PiperOrigin-RevId: 524593948 --- .../flags/nearby_connections_feature_flags.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/connections/implementation/flags/nearby_connections_feature_flags.h b/connections/implementation/flags/nearby_connections_feature_flags.h index 2ef5fc8e..61409685 100644 --- a/connections/implementation/flags/nearby_connections_feature_flags.h +++ b/connections/implementation/flags/nearby_connections_feature_flags.h @@ -27,10 +27,18 @@ constexpr absl::string_view kConfigPackage = "nearby"; // The Nearby Connections features. namespace nearby_connections_feature { +// LINT.IfChanged // Disable/Enable BLE v2 in Nearby Connections SDK. constexpr auto kEnableBleV2 = flags::Flag(kConfigPackage, "45401515", false); +// LINT.ThenChange( +// //depot/google3/location/nearby/cpp/sharing/clients/windows/nearby_sharing_service_adapter_dart.h, +// //depot/google3/location/nearby/cpp/sharing/clients/windows/nearby_sharing_service_adapter_dart.cc, +// //depot/google3/location/nearby/cpp/sharing/clients/dart/platform/lib/ffi_types.dart, +// //depot/google3/location/nearby/cpp/sharing/clients/dart/platform/lib/types/models.dart +// ) + } // namespace nearby_connections_feature } // namespace config_package_nearby } // namespace connections From 2e7f7a7d90515633051fcd561e2a5707dd02adf0 Mon Sep 17 00:00:00 2001 From: Chun Zhang Date: Mon, 17 Apr 2023 11:21:45 -0700 Subject: [PATCH 09/63] Migrate PreferencesManager from location/nearby to third_party/nearby PiperOrigin-RevId: 524900136 --- internal/platform/BUILD | 3 +++ internal/platform/implementation/BUILD | 1 + internal/platform/implementation/apple/platform.mm | 7 +++++++ internal/platform/implementation/g3/BUILD | 1 + internal/platform/implementation/g3/platform.cc | 7 +++++++ internal/platform/implementation/platform.h | 4 ++++ internal/platform/implementation/windows/platform.cc | 10 ++++++++-- internal/platform/listeners.h | 5 +++++ 8 files changed, 36 insertions(+), 2 deletions(-) diff --git a/internal/platform/BUILD b/internal/platform/BUILD index 7de29f48..5cfbbbb5 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -47,8 +47,10 @@ cc_library( "//connections:__subpackages__", "//fastpair:__subpackages__", "//internal:__pkg__", + "//internal/auth:__subpackages__", "//internal/platform:__subpackages__", "//internal/platform/implementation:__subpackages__", + "//internal/preferences:__subpackages__", "//internal/weave:__pkg__", "//location/nearby/cpp:__subpackages__", "//presence:__subpackages__", @@ -348,6 +350,7 @@ cc_library( "//internal/flags:__subpackages__", "//internal/network:__subpackages__", "//internal/platform/implementation/windows:__subpackages__", + "//internal/preferences:__subpackages__", "//internal/test:__subpackages__", "//internal/weave:__pkg__", "//location/nearby/cpp:__subpackages__", diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index 66a0f5b7..f6a47890 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -43,6 +43,7 @@ cc_library( "//internal/crypto:__pkg__", "//internal/platform:__pkg__", "//internal/platform/implementation:__subpackages__", + "//internal/preferences:__subpackages__", "//internal/test:__subpackages__", "//location/nearby/analytics/cpp:__subpackages__", "//location/nearby/cpp/common:__subpackages__", diff --git a/internal/platform/implementation/apple/platform.mm b/internal/platform/implementation/apple/platform.mm index d35d6b81..f8de03e6 100644 --- a/internal/platform/implementation/apple/platform.mm +++ b/internal/platform/implementation/apple/platform.mm @@ -28,6 +28,7 @@ #import "internal/platform/implementation/apple/log_message.h" #import "internal/platform/implementation/apple/multi_thread_executor.h" #include "internal/platform/implementation/apple/mutex.h" +#include "internal/platform/implementation/apple/preferences_repository.h" #import "internal/platform/implementation/apple/scheduled_executor.h" #import "internal/platform/implementation/apple/single_thread_executor.h" #include "internal/platform/implementation/apple/timer.h" @@ -246,5 +247,11 @@ std::unique_ptr ImplementationPlatform::CreateDeviceInf return std::make_unique(); } +// TODO(b/261503919): Add implementation. +std::unique_ptr +ImplementationPlatform::CreatePreferencesRepository(absl::string_view path) { + return std::make_unique(path); +} + } // namespace api } // namespace nearby diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index 81df8931..8dc1300b 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -139,6 +139,7 @@ cc_library( "//internal/flags:__subpackages__", "//internal/network:__subpackages__", "//internal/platform:__subpackages__", + "//internal/preferences:__subpackages__", "//internal/proto/analytics:__subpackages__", "//internal/test:__subpackages__", "//internal/weave:__subpackages__", diff --git a/internal/platform/implementation/g3/platform.cc b/internal/platform/implementation/g3/platform.cc index e4056d14..f8fc4fbb 100644 --- a/internal/platform/implementation/g3/platform.cc +++ b/internal/platform/implementation/g3/platform.cc @@ -32,6 +32,7 @@ #include "internal/platform/implementation/condition_variable.h" #include "internal/platform/implementation/log_message.h" #include "internal/platform/implementation/mutex.h" +#include "internal/platform/implementation/preferences_repository.h" #include "internal/platform/implementation/scheduled_executor.h" #include "internal/platform/implementation/server_sync.h" #include "internal/platform/implementation/shared/count_down_latch.h" @@ -52,6 +53,7 @@ #include "internal/platform/implementation/g3/log_message.h" #include "internal/platform/implementation/g3/multi_thread_executor.h" #include "internal/platform/implementation/g3/mutex.h" +#include "internal/platform/implementation/g3/preferences_repository.h" #include "internal/platform/implementation/g3/scheduled_executor.h" #include "internal/platform/implementation/g3/single_thread_executor.h" #include "internal/platform/implementation/g3/timer.h" @@ -235,5 +237,10 @@ ImplementationPlatform::CreateDeviceInfo() { return std::make_unique(); } +std::unique_ptr +ImplementationPlatform::CreatePreferencesRepository(absl::string_view path) { + return std::make_unique(path); +} + } // namespace api } // namespace nearby diff --git a/internal/platform/implementation/platform.h b/internal/platform/implementation/platform.h index 862bae8f..30d0d3d2 100644 --- a/internal/platform/implementation/platform.h +++ b/internal/platform/implementation/platform.h @@ -46,6 +46,7 @@ #ifndef NO_WEBRTC #include "internal/platform/implementation/webrtc.h" #endif +#include "internal/platform/implementation/preferences_repository.h" #include "internal/platform/implementation/wifi.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/wifi_hotspot.h" @@ -148,6 +149,9 @@ 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); + + static std::unique_ptr + CreatePreferencesRepository(absl::string_view path); }; } // namespace api diff --git a/internal/platform/implementation/windows/platform.cc b/internal/platform/implementation/windows/platform.cc index 70047776..b7956fe8 100644 --- a/internal/platform/implementation/windows/platform.cc +++ b/internal/platform/implementation/windows/platform.cc @@ -53,6 +53,7 @@ #include "internal/platform/implementation/windows/listenable_future.h" #include "internal/platform/implementation/windows/log_message.h" #include "internal/platform/implementation/windows/mutex.h" +#include "internal/platform/implementation/windows/preferences_repository.h" #include "internal/platform/implementation/windows/scheduled_executor.h" #include "internal/platform/implementation/windows/server_sync.h" #include "internal/platform/implementation/windows/settable_future.h" @@ -141,7 +142,7 @@ std::string ImplementationPlatform::GetAppDataPath( FOLDERID_LocalAppData, // rfid: A reference to the KNOWNFOLDERID that // identifies the folder. 0, // dwFlags: Flags that specify special retrieval options. - NULL, // hToken: An access token that represents a particular user. + nullptr, // hToken: An access token that represents a particular user. &basePath); // ppszPath: When this method returns, contains the address // of a pointer to a null-terminated Unicode string that // specifies the path of the known folder. The calling @@ -149,7 +150,7 @@ std::string ImplementationPlatform::GetAppDataPath( // is no longer needed by calling CoTaskMemFree, whether // SHGetKnownFolderPath succeeds or not. size_t bufferSize; - wcstombs_s(&bufferSize, NULL, 0, basePath, 0); + wcstombs_s(&bufferSize, nullptr, 0, basePath, 0); std::string fullpathUTF8(bufferSize - 1, '\0'); wcstombs_s(&bufferSize, fullpathUTF8.data(), bufferSize, basePath, _TRUNCATE); CoTaskMemFree(basePath); @@ -320,5 +321,10 @@ std::unique_ptr ImplementationPlatform::CreateDeviceInfo() { return std::make_unique(); } +std::unique_ptr +ImplementationPlatform::CreatePreferencesRepository(absl::string_view path) { + return std::make_unique(path); +} + } // namespace api } // namespace nearby diff --git a/internal/platform/listeners.h b/internal/platform/listeners.h index e4ef54bd..f1143a13 100644 --- a/internal/platform/listeners.h +++ b/internal/platform/listeners.h @@ -27,6 +27,11 @@ constexpr absl::AnyInvocable DefaultCallback() { return absl::AnyInvocable{[](Args...) {}}; } +template +constexpr std::function DefaultFuncCallback() { + return [](Args...) {}; +} + } // namespace nearby #endif // PLATFORM_BASE_LISTENERS_H_ From 74def10d7c47a0dc111e1abb73af0d3a522db741 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Mon, 17 Apr 2023 12:17:56 -0700 Subject: [PATCH 10/63] Implement FastPairHandshakeLookup PiperOrigin-RevId: 524915633 --- fastpair/handshake/BUILD | 23 ++++ .../handshake/fast_pair_handshake_lookup.cc | 89 ++++++++++++ .../handshake/fast_pair_handshake_lookup.h | 86 ++++++++++++ .../fast_pair_handshake_lookup_test.cc | 128 ++++++++++++++++++ 4 files changed, 326 insertions(+) create mode 100644 fastpair/handshake/fast_pair_handshake_lookup.cc create mode 100644 fastpair/handshake/fast_pair_handshake_lookup.h create mode 100644 fastpair/handshake/fast_pair_handshake_lookup_test.cc diff --git a/fastpair/handshake/BUILD b/fastpair/handshake/BUILD index f099e941..526c8873 100644 --- a/fastpair/handshake/BUILD +++ b/fastpair/handshake/BUILD @@ -20,6 +20,7 @@ cc_library( "fast_pair_data_encryptor_impl.cc", "fast_pair_gatt_service_client_impl.cc", "fast_pair_handshake_impl.cc", + "fast_pair_handshake_lookup.cc", ], hdrs = [ "fast_pair_data_encryptor.h", @@ -28,6 +29,7 @@ cc_library( "fast_pair_gatt_service_client_impl.h", "fast_pair_handshake.h", "fast_pair_handshake_impl.h", + "fast_pair_handshake_lookup.h", ], visibility = [ "//:__subpackages__", @@ -47,9 +49,11 @@ cc_library( "//internal/platform:types", "//internal/platform:uuid", "@boringssl//:crypto", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", ], ) @@ -142,3 +146,22 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "fast_pair_handshake_lookup_test", + size = "small", + srcs = [ + "fast_pair_handshake_lookup_test.cc", + ], + shard_count = 16, + deps = [ + ":handshake", + "//fastpair/common", + "//internal/platform:test_util", + "//internal/platform:types", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/handshake/fast_pair_handshake_lookup.cc b/fastpair/handshake/fast_pair_handshake_lookup.cc new file mode 100644 index 00000000..cad7e193 --- /dev/null +++ b/fastpair/handshake/fast_pair_handshake_lookup.cc @@ -0,0 +1,89 @@ +// 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 "fastpair/handshake/fast_pair_handshake_lookup.h" + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "fastpair/handshake/fast_pair_handshake_impl.h" + +namespace nearby { +namespace fastpair { + +FastPairHandshakeLookup* FastPairHandshakeLookup::instance_ = nullptr; +absl::Mutex FastPairHandshakeLookup::mutex_(absl::kConstInit); + +// static +FastPairHandshakeLookup* FastPairHandshakeLookup::GetInstance() { + absl::MutexLock lock(&mutex_); + if (!instance_) { + instance_ = new FastPairHandshakeLookup(); + } + return instance_; +} + +FastPairHandshake* FastPairHandshakeLookup::Get(FastPairDevice* device) { + absl::MutexLock lock(&mutex_); + auto it = fast_pair_handshakes_.find(device); + return it != fast_pair_handshakes_.end() ? it->second.get() : nullptr; +} + +FastPairHandshake* FastPairHandshakeLookup::Get(absl::string_view address) { + absl::MutexLock lock(&mutex_); + for (const auto& pair : fast_pair_handshakes_) { + if (pair.first->public_address() == address || + pair.first->GetBleAddress() == address) { + return pair.second.get(); + } + } + return nullptr; +} + +bool FastPairHandshakeLookup::Erase(FastPairDevice* device) { + absl::MutexLock lock(&mutex_); + return fast_pair_handshakes_.erase(device) == 1; +} + +bool FastPairHandshakeLookup::Erase(absl::string_view address) { + absl::MutexLock lock(&mutex_); + for (const auto& pair : fast_pair_handshakes_) { + if (pair.first->public_address() == address || + pair.first->GetBleAddress() == address) { + fast_pair_handshakes_.erase(pair.first); + return true; + } + } + return false; +} + +void FastPairHandshakeLookup::Clear() { + absl::MutexLock lock(&mutex_); + fast_pair_handshakes_.clear(); +} + +FastPairHandshake* FastPairHandshakeLookup::Create( + FastPairDevice& device, OnCompleteCallback on_complete) { + absl::MutexLock lock(&mutex_); + auto it = fast_pair_handshakes_.emplace( + &device, + std::make_unique(device, std::move(on_complete))); + DCHECK(it.second); + return it.first->second.get(); +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/handshake/fast_pair_handshake_lookup.h b/fastpair/handshake/fast_pair_handshake_lookup.h new file mode 100644 index 00000000..4909fa17 --- /dev/null +++ b/fastpair/handshake/fast_pair_handshake_lookup.h @@ -0,0 +1,86 @@ +// 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_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_ + +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/synchronization/mutex.h" +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/pair_failure.h" +#include "fastpair/handshake/fast_pair_handshake.h" + +namespace nearby { +namespace fastpair { + +// This Singletonclass creates, deletes and exposes FastPairHandshake instances. +class FastPairHandshakeLookup { + public: + using OnCompleteCallback = absl::AnyInvocable failure)>; + + // This is the static method that controls the access to the singleton + // instance. On the first run, it creates a singleton object and places it + // into the static field. On subsequent runs, it returns the existing object + // stored in the static field. + static FastPairHandshakeLookup* GetInstance(); + + // Singletons should not be cloneable. + FastPairHandshakeLookup(const FastPairHandshakeLookup&) = delete; + // Singletons should not be assignable. + FastPairHandshakeLookup& operator=(const FastPairHandshakeLookup&) = delete; + + // Get an existing instance for |FastPairdevice|. + FastPairHandshake* Get(FastPairDevice* device); + + // Get an existing instance for |address|. + FastPairHandshake* Get(absl::string_view address); + + // Erases the FastPairHandshake instance for |FastPairdevice| if it exists. + bool Erase(FastPairDevice* device); + + // Erases the FastPairHandshake instance for |FastPairdevice| if it exists. + bool Erase(absl::string_view address); + + // Deletes all existing FastPairHandshake instances. + void Clear(); + + // Creates and returns a new instance for |FastPairdevice| if no instance + // already exists. + // Returns the existing instance if there is one. + FastPairHandshake* Create(FastPairDevice& device, + OnCompleteCallback on_complete); + + protected: + // Constructor/destructor of singleton object should not be public + // for which the destructor will never be called. + // and constructor will be invoked once from GetInstance() static method. + FastPairHandshakeLookup() = default; + ~FastPairHandshakeLookup() = default; + + private: + static absl::Mutex mutex_; + static FastPairHandshakeLookup* instance_ ABSL_GUARDED_BY(mutex_); + + absl::flat_hash_map> + fast_pair_handshakes_ ABSL_GUARDED_BY(mutex_); +}; +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_HANDSHAKE_FAST_PAIR_HANDSHAKE_LOOKUP_H_ diff --git a/fastpair/handshake/fast_pair_handshake_lookup_test.cc b/fastpair/handshake/fast_pair_handshake_lookup_test.cc new file mode 100644 index 00000000..d30e88ab --- /dev/null +++ b/fastpair/handshake/fast_pair_handshake_lookup_test.cc @@ -0,0 +1,128 @@ +// 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 "fastpair/handshake/fast_pair_handshake_lookup.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 "fastpair/common/fast_pair_device.h" +#include "fastpair/common/pair_failure.h" +#include "fastpair/common/protocol.h" +#include "internal/platform/count_down_latch.h" +#include "internal/platform/medium_environment.h" + +namespace nearby { +namespace fastpair { +namespace { +constexpr absl::string_view kValidModelId("718c17"); +constexpr absl::string_view kBLEAddress("ble_address"); +constexpr absl::string_view kPubliceAddress("public_address"); +class FastPairHandshakeLookupTest : public ::testing::Test { + public: + FastPairHandshakeLookupTest() { + device_ = new FastPairDevice(kValidModelId, kBLEAddress, + Protocol::kFastPairInitialPairing); + device_->set_public_address(kPubliceAddress); + } + + void CreateFastPairHandshkeInstanceForDevice(FastPairDevice& device) { + CountDownLatch latch(1); + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Create( + device, + [&](FastPairDevice& cb_device, std::optional failure) { + EXPECT_EQ(&device, &cb_device); + EXPECT_EQ(failure, PairFailure::kCreateGattConnection); + latch.CountDown(); + })); + latch.Await(); + } + + FastPairDevice* device_ = nullptr; +}; + +TEST_F(FastPairHandshakeLookupTest, CreateFastPairHandshkeInstanceForDevice) { + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(kBLEAddress)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(kPubliceAddress)); + + CreateFastPairHandshkeInstanceForDevice(*device_); + + // GetFastPairHandshakeWithDevicePtr + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + // GetFastPairHandshakeWithBLEAddress + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(kBLEAddress)); + // GetFastPairHandshakeWithPublicAddress + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(kPubliceAddress)); + // GetFastPairHandshakeWithDevicePtr + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + // GetFastPairHandshakeWithWrongAddress + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get("")); +} + +TEST_F(FastPairHandshakeLookupTest, EraseFastPairHandshakeWithDevicePtr) { + CreateFastPairHandshkeInstanceForDevice(*device_); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Erase(device_)); + // Already Erased + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(kBLEAddress)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(kPubliceAddress)); +} + +TEST_F(FastPairHandshakeLookupTest, EraseFastPairHandshakeWithBLEAddress) { + CreateFastPairHandshkeInstanceForDevice(*device_); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + // Erase Wrong Address + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase("")); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Erase(kBLEAddress)); + // Already Erased + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(device_)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(kPubliceAddress)); +} + +TEST_F(FastPairHandshakeLookupTest, EraseFastPairHandshakeWithPublicAddress) { + CreateFastPairHandshkeInstanceForDevice(*device_); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Erase(kPubliceAddress)); + // Already Erased + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(device_)); + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Erase(kBLEAddress)); +} + +TEST_F(FastPairHandshakeLookupTest, ClearAllFastPairHandshakeInstances) { + CreateFastPairHandshkeInstanceForDevice(*device_); + + EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Get(device_)); + + FastPairHandshakeLookup::GetInstance()->Clear(); + + EXPECT_FALSE(FastPairHandshakeLookup::GetInstance()->Get(device_)); +} + +} // namespace +} // namespace fastpair +} // namespace nearby From bf835451b2705c733f59ac8d8c7db2d97363ccee Mon Sep 17 00:00:00 2001 From: hai007 Date: Mon, 17 Apr 2023 15:41:57 -0700 Subject: [PATCH 11/63] Add Discovery action clicked callback. PiperOrigin-RevId: 524968900 --- fastpair/ui/BUILD | 64 +++++++++++++++++++ fastpair/ui/actions.h | 32 ++++++++++ .../ui/fast_pair/fake_fast_pair_presenter.h | 9 ++- .../fast_pair_notification_controller.cc | 18 +++++- .../fast_pair_notification_controller.h | 13 +++- .../fast_pair_notification_controller_test.cc | 23 +++++-- fastpair/ui/fast_pair/fast_pair_presenter.h | 7 +- .../ui/fast_pair/fast_pair_presenter_impl.cc | 21 +++--- .../ui/fast_pair/fast_pair_presenter_impl.h | 10 +-- .../fast_pair_presenter_impl_test.cc | 12 +++- 10 files changed, 181 insertions(+), 28 deletions(-) create mode 100644 fastpair/ui/BUILD create mode 100644 fastpair/ui/actions.h diff --git a/fastpair/ui/BUILD b/fastpair/ui/BUILD new file mode 100644 index 00000000..e8631c0f --- /dev/null +++ b/fastpair/ui/BUILD @@ -0,0 +1,64 @@ +licenses(["notice"]) + +cc_library( + name = "fast_pair_ui", + srcs = [ + "fast_pair/fast_pair_notification_controller.cc", + "fast_pair/fast_pair_presenter_impl.cc", + ], + hdrs = [ + "actions.h", + "fast_pair/fast_pair_notification_controller.h", + "fast_pair/fast_pair_presenter.h", + "fast_pair/fast_pair_presenter_impl.h", + ], + compatible_with = ["//buildenv/target:non_prod"], + visibility = [ + "//fastpair:__subpackages__", + ], + deps = [ + "//fastpair/common", + "//fastpair/repository", + "//fastpair/server_access", + "//internal/base", + "//internal/platform:logging", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "fake_fast_pair_ui", + hdrs = [ + "fast_pair/fake_fast_pair_notification_controller_observer.h", + "fast_pair/fake_fast_pair_presenter.h", + ], + visibility = [ + "//fastpair:__subpackages__", + ], + deps = [ + ":fast_pair_ui", + "//fastpair/repository", + ], +) + +cc_test( + name = "fast_pair_ui_test", + srcs = [ + "fast_pair/fast_pair_notification_controller_test.cc", + "fast_pair/fast_pair_presenter_impl_test.cc", + ], + deps = [ + ":fake_fast_pair_ui", + ":fast_pair_ui", + "//fastpair/common", + "//fastpair/proto:fastpair_cc_proto", + "//fastpair/repository", + "//fastpair/server_access:test_support", + "//internal/network:types", + "//internal/platform/implementation/g3", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/ui/actions.h b/fastpair/ui/actions.h new file mode 100644 index 00000000..658100d0 --- /dev/null +++ b/fastpair/ui/actions.h @@ -0,0 +1,32 @@ +// 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_FASTPAIR_UI_ACTIONS_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_UI_ACTIONS_H_ + +namespace nearby { +namespace fastpair { + +enum class DiscoveryAction { + kPairToDevice = 0, + kDismissedByUser = 1, + kDismissedByOs = 2, + kLearnMore = 3, + kDismissedByTimeout = 4, +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_UI_ACTIONS_H_ diff --git a/fastpair/ui/fast_pair/fake_fast_pair_presenter.h b/fastpair/ui/fast_pair/fake_fast_pair_presenter.h index f2fe938c..c5ee2038 100644 --- a/fastpair/ui/fast_pair/fake_fast_pair_presenter.h +++ b/fastpair/ui/fast_pair/fake_fast_pair_presenter.h @@ -17,6 +17,8 @@ #include +#include "fastpair/ui/actions.h" +#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" #include "fastpair/ui/fast_pair/fast_pair_presenter_impl.h" namespace nearby { @@ -24,10 +26,11 @@ namespace fastpair { class FakeFastPairPresenter : public FastPairPresenter { public: - void ShowDiscovery( - const FastPairDevice& device, - FastPairNotificationController& notification_controller) override { + void ShowDiscovery(const FastPairDevice& device, + FastPairNotificationController& notification_controller, + DiscoveryCallback callback) override { show_discovery_ = true; + callback(DiscoveryAction::kPairToDevice); } bool show_deiscovery() { return show_discovery_; } diff --git a/fastpair/ui/fast_pair/fast_pair_notification_controller.cc b/fastpair/ui/fast_pair/fast_pair_notification_controller.cc index 35f26de6..6f8ec747 100644 --- a/fastpair/ui/fast_pair/fast_pair_notification_controller.cc +++ b/fastpair/ui/fast_pair/fast_pair_notification_controller.cc @@ -14,7 +14,13 @@ #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" +#include + +#include "absl/functional/any_invocable.h" #include "fastpair/repository/device_metadata.h" +#include "fastpair/ui/actions.h" +#include "internal/platform/logging.h" + namespace nearby { namespace fastpair { void FastPairNotificationController::AddObserver(Observer* observer) { @@ -33,9 +39,19 @@ void FastPairNotificationController::NotifyShowDiscovery( } void FastPairNotificationController::ShowGuestDiscoveryNotification( - const DeviceMetadata& device) { + const DeviceMetadata& device, DiscoveryCallback callback) { + callback_ = std::move(callback); + NEARBY_LOGS(INFO) << __func__ << "Notify show guest discovery notification. "; NotifyShowDiscovery(device); } +void FastPairNotificationController::OnDiscoveryClicked( + DiscoveryAction action) { + NEARBY_LOGS(INFO) << __func__ + << "Discovery action button is clicked in the app."; + DCHECK(callback_); + callback_(action); +} + } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/fast_pair_notification_controller.h b/fastpair/ui/fast_pair/fast_pair_notification_controller.h index 7095aa17..5006c565 100644 --- a/fastpair/ui/fast_pair/fast_pair_notification_controller.h +++ b/fastpair/ui/fast_pair/fast_pair_notification_controller.h @@ -18,17 +18,19 @@ #include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "fastpair/repository/device_metadata.h" +#include "fastpair/ui/actions.h" #include "internal/base/observer_list.h" namespace nearby { namespace fastpair { -using RepeatingClosure = absl::AnyInvocable; + +using DiscoveryCallback = absl::AnyInvocable; + enum class FastPairNotificationDismissReason { kDismissedByUser, kDismissedByOs, kDismissedByTimeout, }; - // This controller creates and manages messages for each FastPair corresponding // notification event. class FastPairNotificationController { @@ -52,9 +54,14 @@ class FastPairNotificationController { void NotifyShowDiscovery(const DeviceMetadata& device); // Creates and displays corresponding notification. - void ShowGuestDiscoveryNotification(const DeviceMetadata& device_metadata); + void ShowGuestDiscoveryNotification(const DeviceMetadata& device_metadata, + DiscoveryCallback callback); + + // Triggers callback when the related action is clicked. + void OnDiscoveryClicked(DiscoveryAction action); private: + DiscoveryCallback callback_; ObserverList observers_; }; } // namespace fastpair diff --git a/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc b/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc index 997b8aa6..6142e2d2 100644 --- a/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc +++ b/fastpair/ui/fast_pair/fast_pair_notification_controller_test.cc @@ -14,15 +14,15 @@ #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include -#include #include -#include +#include +#include #include "gmock/gmock.h" #include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "fastpair/repository/device_metadata.h" +#include "fastpair/ui/actions.h" #include "fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h" namespace nearby { @@ -39,12 +39,19 @@ class FastPairNotificationControllerTest : public ::testing::Test { notification_controller_.AddObserver(¬ification_controller_obsesrver_); } - void TriggerOnUpdateDevice(DeviceMetadata& device) { - notification_controller_.ShowGuestDiscoveryNotification(device); + void TriggerOnUpdateDevice(DeviceMetadata& device, + DiscoveryCallback callback) { + notification_controller_.ShowGuestDiscoveryNotification( + device, std::move(callback)); + } + + void DiscoveryActionClicked(DiscoveryAction action) { + discovery_action_ = action; } FastPairNotificationController notification_controller_; FakeFastPairNotificationControllerObserver notification_controller_obsesrver_; + DiscoveryAction discovery_action_; }; TEST_F(FastPairNotificationControllerTest, ShowGuestDiscoveryNotification) { @@ -52,10 +59,14 @@ TEST_F(FastPairNotificationControllerTest, ShowGuestDiscoveryNotification) { response.mutable_device()->set_id(kDeviceId); response.mutable_device()->set_name(kDeviceName); DeviceMetadata device_metadata(response); - TriggerOnUpdateDevice(device_metadata); + TriggerOnUpdateDevice(device_metadata, [this](DiscoveryAction action) { + DiscoveryActionClicked(action); + }); EXPECT_TRUE(notification_controller_obsesrver_ .CheckDeviceMetadataListContainTestDevice(kDeviceName)); EXPECT_EQ(1, notification_controller_obsesrver_.on_update_device_count()); + notification_controller_.OnDiscoveryClicked(DiscoveryAction::kPairToDevice); + EXPECT_EQ(DiscoveryAction::kPairToDevice, discovery_action_); } } // namespace diff --git a/fastpair/ui/fast_pair/fast_pair_presenter.h b/fastpair/ui/fast_pair/fast_pair_presenter.h index 93313f7e..8b758531 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter.h +++ b/fastpair/ui/fast_pair/fast_pair_presenter.h @@ -15,7 +15,11 @@ #ifndef THIRD_PARTY_NEARBY_FASTPAIR_UI_FAST_PAIR_FAST_PAIR_PRESENTER_H_ #define THIRD_PARTY_NEARBY_FASTPAIR_UI_FAST_PAIR_FAST_PAIR_PRESENTER_H_ +#include + +#include "absl/functional/any_invocable.h" #include "fastpair/common/fast_pair_device.h" +#include "fastpair/ui/actions.h" #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" namespace nearby { @@ -27,7 +31,8 @@ class FastPairPresenter { // observer_list of notification_controller is updated virtual void ShowDiscovery( const FastPairDevice& device, - FastPairNotificationController& notification_controller) = 0; + FastPairNotificationController& notification_controller, + DiscoveryCallback callback) = 0; virtual ~FastPairPresenter() = default; }; diff --git a/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc b/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc index a5916cdf..78b80f71 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc +++ b/fastpair/ui/fast_pair/fast_pair_presenter_impl.cc @@ -15,10 +15,13 @@ #include "fastpair/ui/fast_pair/fast_pair_presenter_impl.h" #include +#include +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "fastpair/repository/device_metadata.h" #include "fastpair/server_access/fast_pair_repository.h" +#include "fastpair/ui/actions.h" #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" #include "internal/platform/logging.h" @@ -47,22 +50,24 @@ FastPairPresenterImpl::Factory::~Factory() = default; void FastPairPresenterImpl::ShowDiscovery( const FastPairDevice& device, - FastPairNotificationController& notification_controller) { + FastPairNotificationController& notification_controller, + DiscoveryCallback callback) { + callback_ = std::move(callback); FastPairRepository::Get()->GetDeviceMetadata( - device.GetModelId(), - [¬ification_controller, this](const DeviceMetadata& device_metadata) { + device.GetModelId(), [&device, ¬ification_controller, + this](const DeviceMetadata& device_metadata) { NEARBY_LOGS(INFO) << __func__ << "Retrieved metadata to notification controller."; - FastPairPresenterImpl::OnDiscoveryMetadataRetrieved( - device_metadata, notification_controller); + OnDiscoveryMetadataRetrieved(device, device_metadata, + notification_controller); }); } void FastPairPresenterImpl::OnDiscoveryMetadataRetrieved( - const DeviceMetadata& device_metadata, + const FastPairDevice& device, const DeviceMetadata& device_metadata, FastPairNotificationController& notification_controller) { - notification_controller.ShowGuestDiscoveryNotification(device_metadata); + notification_controller.ShowGuestDiscoveryNotification(device_metadata, + std::move(callback_)); } - } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/fast_pair_presenter_impl.h b/fastpair/ui/fast_pair/fast_pair_presenter_impl.h index 10bd71b5..c5ee2d97 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter_impl.h +++ b/fastpair/ui/fast_pair/fast_pair_presenter_impl.h @@ -19,6 +19,7 @@ #include "fastpair/common/fast_pair_device.h" #include "fastpair/repository/device_metadata.h" +#include "fastpair/ui/actions.h" #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" #include "fastpair/ui/fast_pair/fast_pair_presenter.h" @@ -45,15 +46,16 @@ class FastPairPresenterImpl : public FastPairPresenter { FastPairPresenterImpl(const FastPairPresenterImpl&) = delete; FastPairPresenterImpl& operator=(const FastPairPresenterImpl&) = delete; - void ShowDiscovery( - const FastPairDevice& device, - FastPairNotificationController& notification_controller) override; + void ShowDiscovery(const FastPairDevice& device, + FastPairNotificationController& notification_controller, + DiscoveryCallback callback) override; private: // observer_list of notification_controller is updated void OnDiscoveryMetadataRetrieved( - const DeviceMetadata& device_metadata, + const FastPairDevice& device, const DeviceMetadata& device_metadata, FastPairNotificationController& notification_controller); + DiscoveryCallback callback_; }; } // namespace fastpair } // namespace nearby diff --git a/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc b/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc index 6929643e..9c33a7b8 100644 --- a/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc +++ b/fastpair/ui/fast_pair/fast_pair_presenter_impl_test.cc @@ -22,9 +22,9 @@ #include "fastpair/common/fast_pair_device.h" #include "fastpair/proto/fastpair_rpcs.proto.h" #include "fastpair/server_access/fake_fast_pair_repository.h" +#include "fastpair/ui/actions.h" #include "fastpair/ui/fast_pair/fake_fast_pair_notification_controller_observer.h" #include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" -#include "fastpair/ui/fast_pair/fast_pair_presenter.h" namespace nearby { namespace fastpair { @@ -42,7 +42,11 @@ class FastPairPresenterImplTest : public ::testing::Test { controller_.AddObserver(¬ification_controller_observer_); } + void OnDiscoveryAction(DiscoveryAction action) { discovery_action_ = action; } + protected: + DiscoveryAction discovery_action_; + FakeFastPairRepository repository_; FastPairPresenterImpl fast_pair_presenter_; FastPairNotificationController controller_; @@ -54,8 +58,12 @@ TEST_F(FastPairPresenterImplTest, ShowDiscovery) { Protocol::kFastPairInitialPairing); EXPECT_EQ(0, notification_controller_observer_.on_update_device_count()); - fast_pair_presenter_.ShowDiscovery(device, controller_); + fast_pair_presenter_.ShowDiscovery( + device, controller_, + [this](DiscoveryAction action) { OnDiscoveryAction(action); }); EXPECT_EQ(1, notification_controller_observer_.on_update_device_count()); + controller_.OnDiscoveryClicked(DiscoveryAction::kPairToDevice); + EXPECT_EQ(DiscoveryAction::kPairToDevice, discovery_action_); } } // namespace } // namespace fastpair From c426dea3f5f7b7be10987f2e3bfe7d3f198f0389 Mon Sep 17 00:00:00 2001 From: Chun Zhang Date: Mon, 17 Apr 2023 15:57:09 -0700 Subject: [PATCH 12/63] Excludes PreferencesRepository from NEARBY_CHROMIUM PiperOrigin-RevId: 524972823 --- internal/platform/implementation/platform.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/platform/implementation/platform.h b/internal/platform/implementation/platform.h index 30d0d3d2..6860d15f 100644 --- a/internal/platform/implementation/platform.h +++ b/internal/platform/implementation/platform.h @@ -46,7 +46,9 @@ #ifndef NO_WEBRTC #include "internal/platform/implementation/webrtc.h" #endif +#ifndef NEARBY_CHROMIUM #include "internal/platform/implementation/preferences_repository.h" +#endif #include "internal/platform/implementation/wifi.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/wifi_hotspot.h" @@ -150,8 +152,10 @@ class ImplementationPlatform { // other cases will return absl Status in error. static absl::StatusOr SendRequest(const WebRequest& request); +#ifndef NEARBY_CHROMIUM static std::unique_ptr CreatePreferencesRepository(absl::string_view path); +#endif }; } // namespace api From b10a2a24ca98d5f318b49bccd3f658891c5cd374 Mon Sep 17 00:00:00 2001 From: Crisrael Lucero Date: Mon, 17 Apr 2023 15:59:48 -0700 Subject: [PATCH 13/63] Modernize emplace_back in unit tests PiperOrigin-RevId: 524973507 --- presence/implementation/action_factory_test.cc | 10 +++++----- .../implementation/advertisement_factory_test.cc | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/presence/implementation/action_factory_test.cc b/presence/implementation/action_factory_test.cc index 02b46434..5eb57076 100644 --- a/presence/implementation/action_factory_test.cc +++ b/presence/implementation/action_factory_test.cc @@ -35,7 +35,7 @@ constexpr uint32_t kFastPairBitMask = 1 << 14; TEST(ActionFactory, CreateActiveUnlockAction) { std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); Action action = ActionFactory::CreateAction(data_elements); @@ -44,10 +44,10 @@ TEST(ActionFactory, CreateActiveUnlockAction) { TEST(ActionFactory, CreateActiveIgnoresUnsupportedActions) { std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); // The action is 32 bit, so the valid range is [0-31] - data_elements.emplace_back(DataElement(ActionBit(-1))); - data_elements.emplace_back(DataElement(ActionBit(32))); + data_elements.emplace_back(ActionBit(-1)); + data_elements.emplace_back(ActionBit(32)); Action action = ActionFactory::CreateAction(data_elements); EXPECT_EQ(action.action, kActiveUnlockBitMask); @@ -71,7 +71,7 @@ TEST(ActionFactory, CreateContextTimestampAndFastPair) { std::vector data_elements; data_elements.emplace_back(DataElement::kContextTimestampFieldType, kTimestamp); - data_elements.emplace_back(DataElement(ActionBit::kFastPairAction)); + data_elements.emplace_back(ActionBit::kFastPairAction); Action action = ActionFactory::CreateAction(data_elements); diff --git a/presence/implementation/advertisement_factory_test.cc b/presence/implementation/advertisement_factory_test.cc index 1847d8aa..f87aa433 100644 --- a/presence/implementation/advertisement_factory_test.cc +++ b/presence/implementation/advertisement_factory_test.cc @@ -61,7 +61,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPrivateIdentity) { std::string salt = "AB"; constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PRIVATE; std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) @@ -85,8 +85,8 @@ TEST(AdvertisementFactory, CreateAdvertisementFromTrustedIdentity) { std::string salt = "AB"; constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_TRUSTED; std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); - data_elements.emplace_back(DataElement(ActionBit::kFitCastAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); + data_elements.emplace_back(ActionBit::kFitCastAction); Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) @@ -110,8 +110,8 @@ TEST(AdvertisementFactory, CreateAdvertisementFromProvisionedIdentity) { std::string salt = "AB"; constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PROVISIONED; std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); - data_elements.emplace_back(DataElement(ActionBit::kFitCastAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); + data_elements.emplace_back(ActionBit::kFitCastAction); Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) @@ -135,7 +135,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFromPublicIdentity) { std::string salt = "AB"; constexpr IdentityType kIdentity = IdentityType::IDENTITY_TYPE_PUBLIC; std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) @@ -155,7 +155,7 @@ TEST(AdvertisementFactory, CreateAdvertisementFailsWhenSaltIsTooShort) { std::string salt = "AB"; constexpr IdentityType kIdentity = internal::IDENTITY_TYPE_PRIVATE; std::vector data_elements; - data_elements.emplace_back(DataElement(ActionBit::kActiveUnlockAction)); + data_elements.emplace_back(ActionBit::kActiveUnlockAction); Action action = ActionFactory::CreateAction(data_elements); BaseBroadcastRequest request = BaseBroadcastRequest(BasePresenceRequestBuilder(kIdentity) From c40e0112672b28ef87b67f69cc4189a9434c3d47 Mon Sep 17 00:00:00 2001 From: hai007 Date: Tue, 18 Apr 2023 10:27:34 -0700 Subject: [PATCH 14/63] Implement Fast Pair UI broker PiperOrigin-RevId: 525184851 --- fastpair/ui/BUILD | 5 +- fastpair/ui/ui_broker.h | 50 ++++++++++++++++++++ fastpair/ui/ui_broker_impl.cc | 69 +++++++++++++++++++++++++++ fastpair/ui/ui_broker_impl.h | 52 ++++++++++++++++++++ fastpair/ui/ui_broker_impl_test.cc | 76 ++++++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 fastpair/ui/ui_broker.h create mode 100644 fastpair/ui/ui_broker_impl.cc create mode 100644 fastpair/ui/ui_broker_impl.h create mode 100644 fastpair/ui/ui_broker_impl_test.cc diff --git a/fastpair/ui/BUILD b/fastpair/ui/BUILD index e8631c0f..754f8eb9 100644 --- a/fastpair/ui/BUILD +++ b/fastpair/ui/BUILD @@ -5,12 +5,15 @@ cc_library( srcs = [ "fast_pair/fast_pair_notification_controller.cc", "fast_pair/fast_pair_presenter_impl.cc", + "ui_broker_impl.cc", ], hdrs = [ "actions.h", "fast_pair/fast_pair_notification_controller.h", "fast_pair/fast_pair_presenter.h", "fast_pair/fast_pair_presenter_impl.h", + "ui_broker.h", + "ui_broker_impl.h", ], compatible_with = ["//buildenv/target:non_prod"], visibility = [ @@ -23,7 +26,6 @@ cc_library( "//internal/base", "//internal/platform:logging", "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/log:check", "@com_google_absl//absl/strings", ], ) @@ -48,6 +50,7 @@ cc_test( srcs = [ "fast_pair/fast_pair_notification_controller_test.cc", "fast_pair/fast_pair_presenter_impl_test.cc", + "ui_broker_impl_test.cc", ], deps = [ ":fake_fast_pair_ui", diff --git a/fastpair/ui/ui_broker.h b/fastpair/ui/ui_broker.h new file mode 100644 index 00000000..046bceea --- /dev/null +++ b/fastpair/ui/ui_broker.h @@ -0,0 +1,50 @@ +// 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_FASTPAIR_UI_UI_BROKER_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_UI_UI_BROKER_H_ + +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/ui/actions.h" +#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" + +namespace nearby { +namespace fastpair { + +// The UIBroker is the entry point for the UI component in the FastPair system. +// It is responsible for brokering the 'show UI' calls to the correct Presenter +// implementation, and exposing user actions taken on that UI. +class UIBroker { + public: + class Observer { + public: + virtual ~Observer() = default; + virtual void OnDiscoveryAction(const FastPairDevice& device, + DiscoveryAction action) = 0; + }; + + virtual ~UIBroker() = default; + + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + + virtual void ShowDiscovery( + const FastPairDevice& device, + FastPairNotificationController& notification_controller) = 0; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_UI_UI_BROKER_H_ diff --git a/fastpair/ui/ui_broker_impl.cc b/fastpair/ui/ui_broker_impl.cc new file mode 100644 index 00000000..41e33c2e --- /dev/null +++ b/fastpair/ui/ui_broker_impl.cc @@ -0,0 +1,69 @@ +// 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 "fastpair/ui/ui_broker_impl.h" + +#include + +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/protocol.h" +#include "fastpair/ui/actions.h" +#include "fastpair/ui/fast_pair/fast_pair_presenter.h" +#include "fastpair/ui/fast_pair/fast_pair_presenter_impl.h" +#include "internal/platform/logging.h" + +namespace nearby { +namespace fastpair { + +UIBrokerImpl::UIBrokerImpl() + : fast_pair_presenter_(FastPairPresenterImpl::Factory::Create()) {} + +void UIBrokerImpl::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void UIBrokerImpl::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +void UIBrokerImpl::ShowDiscovery( + const FastPairDevice& device, + FastPairNotificationController& notification_controller) { + switch (device.GetProtocol()) { + case Protocol::kFastPairInitialPairing: + case Protocol::kFastPairSubsequentPairing: + fast_pair_presenter_->ShowDiscovery( + device, notification_controller, + [&device, this](DiscoveryAction action) { + NEARBY_LOGS(INFO) + << __func__ << ": Notify discovery action to all observers."; + NotifyDiscoveryAction(device, action); + }); + break; + case Protocol::kFastPairRetroactivePairing: + NEARBY_LOGS(ERROR) + << __func__ + << ": Retroactive Pairing should not show discovery Halfsheet."; + break; + } +} + +void UIBrokerImpl::NotifyDiscoveryAction(const FastPairDevice& device, + DiscoveryAction action) { + for (auto& observer : observers_.GetObservers()) + observer->OnDiscoveryAction(device, action); +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/ui/ui_broker_impl.h b/fastpair/ui/ui_broker_impl.h new file mode 100644 index 00000000..75bd7a78 --- /dev/null +++ b/fastpair/ui/ui_broker_impl.h @@ -0,0 +1,52 @@ +// 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_FASTPAIR_UI_BROKER_IMPL_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_UI_BROKER_IMPL_H_ + +#include + +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/ui/actions.h" +#include "fastpair/ui/fast_pair/fast_pair_presenter.h" +#include "fastpair/ui/ui_broker.h" +#include "internal/base/observer_list.h" + +namespace nearby { +namespace fastpair { + +class UIBrokerImpl : public UIBroker { + public: + UIBrokerImpl(); + UIBrokerImpl(const UIBrokerImpl &) = delete; + UIBrokerImpl &operator=(const UIBrokerImpl &) = delete; + + void AddObserver(Observer *observer) override; + void RemoveObserver(Observer *observer) override; + void ShowDiscovery( + const FastPairDevice &device, + FastPairNotificationController ¬ification_controller) override; + + private: + void NotifyDiscoveryAction(const FastPairDevice &device, + DiscoveryAction action); + + std::unique_ptr fast_pair_presenter_; + ObserverList observers_; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_UI_BROKER_IMPL_H_ diff --git a/fastpair/ui/ui_broker_impl_test.cc b/fastpair/ui/ui_broker_impl_test.cc new file mode 100644 index 00000000..b93a74fa --- /dev/null +++ b/fastpair/ui/ui_broker_impl_test.cc @@ -0,0 +1,76 @@ +// 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 "fastpair/ui/ui_broker_impl.h" + +#include +#include + +#include "gtest/gtest.h" +#include "fastpair/ui/actions.h" +#include "fastpair/ui/fast_pair/fake_fast_pair_presenter.h" +#include "fastpair/ui/fast_pair/fast_pair_notification_controller.h" +#include "fastpair/ui/ui_broker.h" + +namespace nearby { +namespace fastpair { +namespace { + +constexpr absl::string_view kModelId = "718C17"; +constexpr absl::string_view kAddress = "74:74:46:01:6C:21"; + +class UIBrokerImplTest : public ::testing::Test, public UIBroker::Observer { + protected: + UIBrokerImplTest() { + presenter_factory_ = std::make_unique(); + FastPairPresenterImpl::Factory::SetFactoryForTesting( + presenter_factory_.get()); + ui_broker_ = std::make_unique(); + ui_broker_->AddObserver(this); + } + + void OnDiscoveryAction(const FastPairDevice& device, + DiscoveryAction action) override { + on_discovery_action_notified_ = true; + discovery_action_ = action; + } + + std::unique_ptr ui_broker_; + FastPairNotificationController notification_controller_; + std::unique_ptr presenter_factory_; + DiscoveryAction discovery_action_; + bool on_discovery_action_notified_ = false; +}; + +TEST_F(UIBrokerImplTest, ShowDiscovery) { + FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing); + ui_broker_->ShowDiscovery(device, notification_controller_); + EXPECT_TRUE( + presenter_factory_->fake_fast_pair_presenter()->show_deiscovery()); + EXPECT_TRUE(on_discovery_action_notified_); + EXPECT_EQ(DiscoveryAction::kPairToDevice, discovery_action_); +} + +TEST_F(UIBrokerImplTest, ShowDiscoveryWithoutObserver) { + FastPairDevice device(kModelId, kAddress, Protocol::kFastPairInitialPairing); + ui_broker_->RemoveObserver(this); + ui_broker_->ShowDiscovery(device, notification_controller_); + EXPECT_TRUE( + presenter_factory_->fake_fast_pair_presenter()->show_deiscovery()); + EXPECT_FALSE(on_discovery_action_notified_); +} + +} // namespace +} // namespace fastpair +} // namespace nearby From f300012bcd8b1854fdfe3cfb3ca66986e5b85b8b Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Tue, 18 Apr 2023 17:21:20 -0700 Subject: [PATCH 15/63] Fix GATT DiscoverServiceAndCharacteristics PiperOrigin-RevId: 525295071 --- internal/platform/implementation/windows/ble_gatt_client.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/windows/ble_gatt_client.cc b/internal/platform/implementation/windows/ble_gatt_client.cc index 9bfb6b02..809dff7f 100644 --- a/internal/platform/implementation/windows/ble_gatt_client.cc +++ b/internal/platform/implementation/windows/ble_gatt_client.cc @@ -213,10 +213,11 @@ bool BleGattClient::DiscoverServiceAndCharacteristics( // found all characteristics. NEARBY_LOGS(VERBOSE) << __func__ << ": Found all characteristics."; - break; + return true; } - return true; + NEARBY_LOGS(VERBOSE) << __func__ + << ": Failed to find service and all characteristics."; } catch (std::exception exception) { NEARBY_LOGS(ERROR) << __func__ << ": Failed to get GATT services. exception: " From f1a1a7510bfb1e3d0fefc9aa58041d3ebc616a25 Mon Sep 17 00:00:00 2001 From: Hai Shang Date: Tue, 18 Apr 2023 19:20:34 -0700 Subject: [PATCH 16/63] fix include paths PiperOrigin-RevId: 525315412 --- internal/crypto/aead.cc | 2 +- internal/crypto/ec_private_key.cc | 2 +- internal/crypto/encryptor.cc | 2 +- internal/crypto/hmac.cc | 2 +- internal/crypto/nearby_base.cc | 2 +- internal/crypto/openssl_util.cc | 22 +++------------------- internal/crypto/signature_verifier.cc | 2 +- internal/crypto/symmetric_key.cc | 2 +- 8 files changed, 10 insertions(+), 26 deletions(-) diff --git a/internal/crypto/aead.cc b/internal/crypto/aead.cc index 41bedf2a..bbba65ce 100644 --- a/internal/crypto/aead.cc +++ b/internal/crypto/aead.cc @@ -22,7 +22,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else diff --git a/internal/crypto/ec_private_key.cc b/internal/crypto/ec_private_key.cc index 1281a70d..63471e02 100644 --- a/internal/crypto/ec_private_key.cc +++ b/internal/crypto/ec_private_key.cc @@ -24,7 +24,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else diff --git a/internal/crypto/encryptor.cc b/internal/crypto/encryptor.cc index dbb40cda..bc078ab2 100644 --- a/internal/crypto/encryptor.cc +++ b/internal/crypto/encryptor.cc @@ -23,7 +23,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else diff --git a/internal/crypto/hmac.cc b/internal/crypto/hmac.cc index e75c7f71..d9dfd8c6 100644 --- a/internal/crypto/hmac.cc +++ b/internal/crypto/hmac.cc @@ -20,7 +20,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else diff --git a/internal/crypto/nearby_base.cc b/internal/crypto/nearby_base.cc index 47292e24..1547ebaa 100644 --- a/internal/crypto/nearby_base.cc +++ b/internal/crypto/nearby_base.cc @@ -19,7 +19,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else diff --git a/internal/crypto/openssl_util.cc b/internal/crypto/openssl_util.cc index 98dd3b50..acac591d 100644 --- a/internal/crypto/openssl_util.cc +++ b/internal/crypto/openssl_util.cc @@ -19,7 +19,9 @@ #include -#ifdef NEARBY_SWIFTPM +#ifdef NEARBY_CHROMIUM +#include "internal/platform/logging.h" +#elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else #include "absl/log/log.h" // nogncheck @@ -30,24 +32,6 @@ namespace crypto { -namespace { - -// Callback routine for OpenSSL to print error messages. |str| is a -// NULL-terminated string of length |len| containing diagnostic information -// such as the library, function and reason for the error, the file and line -// where the error originated, plus potentially any context-specific -// information about the error. |context| contains a pointer to user-supplied -// data, which is currently unused. -// If this callback returns a value <= 0, OpenSSL will stop processing the -// error queue and return, otherwise it will continue calling this function -// until all errors have been removed from the queue. -int OpenSSLErrorCallback(const char* str, size_t len, void* context) { - LOG(INFO) << "\t" << absl::string_view(str, len); - return 1; -} - -} // namespace - void EnsureOpenSSLInit() { // CRYPTO_library_init may be safely called concurrently. CRYPTO_library_init(); diff --git a/internal/crypto/signature_verifier.cc b/internal/crypto/signature_verifier.cc index 363b0f60..8157a384 100644 --- a/internal/crypto/signature_verifier.cc +++ b/internal/crypto/signature_verifier.cc @@ -17,7 +17,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else diff --git a/internal/crypto/symmetric_key.cc b/internal/crypto/symmetric_key.cc index 7cdebcd6..a3beddfd 100644 --- a/internal/crypto/symmetric_key.cc +++ b/internal/crypto/symmetric_key.cc @@ -23,7 +23,7 @@ #include #ifdef NEARBY_CHROMIUM -#include "base/check.h" +#include "internal/platform/logging.h" #elif defined(NEARBY_SWIFTPM) #include "internal/platform/logging.h" #else From 7f227a5205d08f7ceaa9cb892909c939e9c3fbf8 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Wed, 19 Apr 2023 12:21:30 -0700 Subject: [PATCH 17/63] CredentialManager: Allow saving/getting device metadata blobs PiperOrigin-RevId: 525518359 --- .../implementation/credential_storage.h | 1 + presence/implementation/credential_manager.h | 12 +++++++++++ .../implementation/credential_manager_impl.h | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/internal/platform/implementation/credential_storage.h b/internal/platform/implementation/credential_storage.h index 5c0af512..b8fb2459 100644 --- a/internal/platform/implementation/credential_storage.h +++ b/internal/platform/implementation/credential_storage.h @@ -21,6 +21,7 @@ #include "absl/strings/string_view.h" #include "internal/platform/implementation/credential_callbacks.h" #include "internal/proto/credential.pb.h" +#include "internal/proto/local_credential.pb.h" namespace nearby { namespace api { diff --git a/presence/implementation/credential_manager.h b/presence/implementation/credential_manager.h index a758ae20..01cadc6c 100644 --- a/presence/implementation/credential_manager.h +++ b/presence/implementation/credential_manager.h @@ -95,6 +95,18 @@ class CredentialManager { virtual std::string DecryptMetadata(absl::string_view metadata_encryption_key, absl::string_view key_seed, absl::string_view metadata_string) = 0; + + // Sets the NP service's device metadata, regenerating credentials if + // `regen_credentials` is set to true. + virtual void SetLocalDeviceMetadata( + 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; + + // Gets the NP service's device metadata. + virtual ::nearby::internal::Metadata GetLocalDeviceMetadata() = 0; }; } // namespace presence diff --git a/presence/implementation/credential_manager_impl.h b/presence/implementation/credential_manager_impl.h index 673de9f8..25f96ac2 100644 --- a/presence/implementation/credential_manager_impl.h +++ b/presence/implementation/credential_manager_impl.h @@ -31,6 +31,7 @@ #include "internal/platform/runnable.h" #include "internal/platform/single_thread_executor.h" #include "internal/proto/credential.pb.h" +#include "internal/proto/metadata.proto.h" #include "presence/implementation/credential_manager.h" namespace nearby { @@ -127,6 +128,24 @@ class CredentialManagerImpl : public CredentialManager { std::vector ExtendMetadataEncryptionKey( absl::string_view metadata_encryption_key); + void SetLocalDeviceMetadata( + const 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 { + metadata_ = metadata; + if (regen_credentials) { + GenerateCredentials( + metadata, manager_app_id, identity_types, credential_life_cycle_days, + contiguous_copy_of_credentials, std::move(credentials_generated_cb)); + } + } + + ::nearby::internal::Metadata GetLocalDeviceMetadata() override { + return metadata_; + } + private: struct SubscriberKey { CredentialSelector credential_selector; @@ -185,6 +204,7 @@ class CredentialManagerImpl : public CredentialManager { ABSL_GUARDED_BY(*executor_); SingleThreadExecutor* executor_; std::unique_ptr credential_storage_ptr_; + Metadata metadata_; }; } // namespace presence From b80a710fb038b9a701952ea27fcfd48de701e9f2 Mon Sep 17 00:00:00 2001 From: hai007 Date: Wed, 19 Apr 2023 13:48:51 -0700 Subject: [PATCH 18/63] Fix data race problem caused by a simulated_clock PiperOrigin-RevId: 525540869 --- internal/platform/medium_environment.cc | 7 ++++++- internal/platform/medium_environment.h | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/platform/medium_environment.cc b/internal/platform/medium_environment.cc index 600ce8fd..ead9fcc6 100644 --- a/internal/platform/medium_environment.cc +++ b/internal/platform/medium_environment.cc @@ -50,6 +50,7 @@ void MediumEnvironment::Start(EnvironmentConfig config) { NEARBY_LOGS(INFO) << "MediumEnvironment::Start()"; config_ = std::move(config); if (config_.use_simulated_clock) { + MutexLock lock(&mutex_); simulated_clock_ = std::make_unique(); } Reset(); @@ -60,8 +61,11 @@ void MediumEnvironment::Stop() { if (enabled_.exchange(false)) { NEARBY_LOGS(INFO) << "MediumEnvironment::Stop()"; Sync(false); + if (config_.use_simulated_clock) { + MutexLock lock(&mutex_); + simulated_clock_.reset(); + } config_ = {}; - simulated_clock_.reset(); } } @@ -1205,6 +1209,7 @@ void MediumEnvironment::SetFeatureFlags(const FeatureFlags::Flags& flags) { } absl::optional MediumEnvironment::GetSimulatedClock() { + MutexLock lock(&mutex_); if (simulated_clock_) { return absl::optional(simulated_clock_.get()); } diff --git a/internal/platform/medium_environment.h b/internal/platform/medium_environment.h index 4bbd2d86..b0865e33 100644 --- a/internal/platform/medium_environment.h +++ b/internal/platform/medium_environment.h @@ -511,7 +511,7 @@ class MediumEnvironment { bool use_valid_peer_connection_ = true; absl::Duration peer_connection_latency_ = absl::ZeroDuration(); - std::unique_ptr simulated_clock_; + std::unique_ptr simulated_clock_ ABSL_GUARDED_BY(mutex_); }; } // namespace nearby From ac9d6b1c5533977bb77d4c4a45db409f6bbd58ff Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Wed, 19 Apr 2023 18:23:07 -0700 Subject: [PATCH 19/63] fixed the bssid format issue PiperOrigin-RevId: 525606245 --- internal/platform/implementation/windows/wifi_medium.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/platform/implementation/windows/wifi_medium.cc b/internal/platform/implementation/windows/wifi_medium.cc index 0ca62ec8..f35bf8e5 100644 --- a/internal/platform/implementation/windows/wifi_medium.cc +++ b/internal/platform/implementation/windows/wifi_medium.cc @@ -192,7 +192,7 @@ api::WifiInformation& WifiMedium::GetInformation() { p_connect_info->wlanAssociationAttributes.dot11Bssid), kMacAddrLen); wifi_information_.bssid = absl::StrFormat( - "%2llx:%2llx:%2llx:%2llx:%2llx:%2llx", str_tmp[0], str_tmp[1], + "%02llx:%02llx:%02llx:%02llx:%02llx:%02llx", str_tmp[0], str_tmp[1], str_tmp[2], str_tmp[3], str_tmp[4], str_tmp[5]); NEARBY_LOGS(INFO) << "wifi bssid is: " << wifi_information_.bssid; } @@ -241,7 +241,7 @@ std::string WifiMedium::InternalGetWifiIpAddress() { winrt::to_string(profile_details.GetConnectedSsid())) { NEARBY_LOGS(INFO) << "SSID of this IP matches with this WiFi interface's SSID:" - << wifi_information_.ssid << ", return this IP"; + << wifi_information_.ssid << ", return this IP: " << ipv4_s; return ipv4_s; } } From a706e95e7bb9660fe870417d4d1a11629d446f1a Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Wed, 19 Apr 2023 19:31:33 -0700 Subject: [PATCH 20/63] [Connections] Implement NC/NP Handshake & Connection Authentication, part III PiperOrigin-RevId: 525615681 --- .../implementation/proto/offline_wire_formats.proto | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/connections/implementation/proto/offline_wire_formats.proto b/connections/implementation/proto/offline_wire_formats.proto index 084c3e58..ea3a1224 100644 --- a/connections/implementation/proto/offline_wire_formats.proto +++ b/connections/implementation/proto/offline_wire_formats.proto @@ -43,6 +43,7 @@ message V1Frame { KEEP_ALIVE = 5; DISCONNECTION = 6; PAIRED_KEY_ENCRYPTION = 7; + AUTHENTICATION_MESSAGE = 8; } optional FrameType type = 1; @@ -54,6 +55,7 @@ message V1Frame { optional KeepAliveFrame keep_alive = 6; optional DisconnectionFrame disconnection = 7; optional PairedKeyEncryptionFrame paired_key_encryption = 8; + optional AuthenticationMessageFrame authentication_message = 9; } message ConnectionRequestFrame { @@ -318,6 +320,14 @@ message PairedKeyEncryptionFrame { optional bytes signed_data = 1; } +// Nearby Connections authentication frame, contains the bytes format of a +// DeviceProvider's authentication message. +message AuthenticationMessageFrame { + // An auth message generated by DeviceProvider. + // To be sent to the remote device for verification during connection setups. + optional bytes auth_message = 1; +} + message MediumMetadata { // True if local device supports 5GHz. optional bool supports_5_ghz = 1; From 576b0babfafe52823d38d1d8150e04aac60999bb Mon Sep 17 00:00:00 2001 From: Edwin Wu Date: Wed, 19 Apr 2023 19:55:59 -0700 Subject: [PATCH 21/63] [Connections] Implement NC/NP Handshake & Connection Authentication, part IV PiperOrigin-RevId: 525618680 --- .../implementation/proto/offline_wire_formats.proto | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/connections/implementation/proto/offline_wire_formats.proto b/connections/implementation/proto/offline_wire_formats.proto index ea3a1224..17ecdbaf 100644 --- a/connections/implementation/proto/offline_wire_formats.proto +++ b/connections/implementation/proto/offline_wire_formats.proto @@ -44,6 +44,7 @@ message V1Frame { DISCONNECTION = 6; PAIRED_KEY_ENCRYPTION = 7; AUTHENTICATION_MESSAGE = 8; + AUTHENTICATION_RESULT = 9; } optional FrameType type = 1; @@ -56,6 +57,7 @@ message V1Frame { optional DisconnectionFrame disconnection = 7; optional PairedKeyEncryptionFrame paired_key_encryption = 8; optional AuthenticationMessageFrame authentication_message = 9; + optional AuthenticationResultFrame authentication_result = 10; } message ConnectionRequestFrame { @@ -328,6 +330,13 @@ message AuthenticationMessageFrame { optional bytes auth_message = 1; } +// Nearby Connections authentication result frame. +message AuthenticationResultFrame { + // The authentication result. Non null if this frame is used to exchange + // authentication result. + optional int32 result = 1; +} + message MediumMetadata { // True if local device supports 5GHz. optional bool supports_5_ghz = 1; From b36385de1f40777e1a32010854c2df83c56512bf Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Fri, 21 Apr 2023 09:23:06 -0700 Subject: [PATCH 22/63] Make sure listeners_ is protected by mutex lock PiperOrigin-RevId: 526058543 --- internal/platform/cancellation_flag.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/platform/cancellation_flag.cc b/internal/platform/cancellation_flag.cc index c6b3bf5d..f9daa1ed 100644 --- a/internal/platform/cancellation_flag.cc +++ b/internal/platform/cancellation_flag.cc @@ -27,7 +27,10 @@ CancellationFlag::CancellationFlag(bool cancelled) { cancelled_ = cancelled; } -CancellationFlag::~CancellationFlag() { listeners_.clear(); } +CancellationFlag::~CancellationFlag() { + absl::MutexLock lock(mutex_.get()); + listeners_.clear(); +} void CancellationFlag::Cancel() { // Return immediately as no-op if feature flag is not enabled. From 6ee8d32b2e31c3a18e3ad57520e9fecd4b10e035 Mon Sep 17 00:00:00 2001 From: Crisrael Lucero Date: Fri, 21 Apr 2023 15:04:03 -0700 Subject: [PATCH 23/63] Change proto include header PiperOrigin-RevId: 526146014 --- presence/implementation/credential_manager_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presence/implementation/credential_manager_impl.h b/presence/implementation/credential_manager_impl.h index 25f96ac2..00779132 100644 --- a/presence/implementation/credential_manager_impl.h +++ b/presence/implementation/credential_manager_impl.h @@ -31,7 +31,7 @@ #include "internal/platform/runnable.h" #include "internal/platform/single_thread_executor.h" #include "internal/proto/credential.pb.h" -#include "internal/proto/metadata.proto.h" +#include "internal/proto/metadata.pb.h" #include "presence/implementation/credential_manager.h" namespace nearby { From e4c1f9aa240fb016c08964af11f7232d9cbce62d Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Fri, 21 Apr 2023 15:40:28 -0700 Subject: [PATCH 24/63] Fixed the issue of using CancellationFlagListener PiperOrigin-RevId: 526154394 --- .../implementation/windows/wifi_direct.h | 5 ----- .../implementation/windows/wifi_direct_medium.cc | 16 ++++++---------- .../implementation/windows/wifi_hotspot.h | 5 ----- .../windows/wifi_hotspot_medium.cc | 12 ++++-------- .../platform/implementation/windows/wifi_lan.h | 5 ----- .../implementation/windows/wifi_lan_medium.cc | 12 ++++-------- 6 files changed, 14 insertions(+), 41 deletions(-) diff --git a/internal/platform/implementation/windows/wifi_direct.h b/internal/platform/implementation/windows/wifi_direct.h index 561ed4c4..c44787ed 100644 --- a/internal/platform/implementation/windows/wifi_direct.h +++ b/internal/platform/implementation/windows/wifi_direct.h @@ -29,7 +29,6 @@ #include // Nearby connections headers -#include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/implementation/wifi_direct.h" #include "internal/platform/implementation/windows/scheduled_executor.h" @@ -314,10 +313,6 @@ class WifiDirectMedium : public api::WifiDirectMedium { // Scheduled task for connection timeout. std::shared_ptr connection_timeout_ = nullptr; - - // Listener to connect cancellation. - std::unique_ptr - connection_cancellation_listener_ = nullptr; }; } // namespace windows diff --git a/internal/platform/implementation/windows/wifi_direct_medium.cc b/internal/platform/implementation/windows/wifi_direct_medium.cc index 3f0ff532..c27595d0 100644 --- a/internal/platform/implementation/windows/wifi_direct_medium.cc +++ b/internal/platform/implementation/windows/wifi_direct_medium.cc @@ -107,6 +107,9 @@ std::unique_ptr WifiDirectMedium::ConnectToService( try { StreamSocket socket{}; + std::unique_ptr + connection_cancellation_listener = nullptr; + // setup cancel listener if (cancellation_flag != nullptr) { if (cancellation_flag->Cancelled()) { @@ -115,7 +118,7 @@ std::unique_ptr WifiDirectMedium::ConnectToService( return nullptr; } - connection_cancellation_listener_ = + connection_cancellation_listener = std::make_unique( cancellation_flag, [socket]() { NEARBY_LOGS(WARNING) @@ -132,9 +135,6 @@ std::unique_ptr WifiDirectMedium::ConnectToService( kWifiDirectClientSocketConnectTimeoutMillis); socket.ConnectAsync(host_name, service_name).get(); - if (connection_cancellation_listener_ != nullptr) { - connection_cancellation_listener_ = nullptr; - } if (connection_timeout_ != nullptr) { connection_timeout_->Cancel(); @@ -151,10 +151,6 @@ std::unique_ptr WifiDirectMedium::ConnectToService( << ":" << port << " for the " << i + 1 << " time"; } - if (connection_cancellation_listener_ != nullptr) { - connection_cancellation_listener_ = nullptr; - } - if (connection_timeout_ != nullptr) { connection_timeout_->Cancel(); connection_timeout_ = nullptr; @@ -165,8 +161,8 @@ std::unique_ptr WifiDirectMedium::ConnectToService( return nullptr; } -std::unique_ptr -WifiDirectMedium::ListenForService(int port) { +std::unique_ptr WifiDirectMedium::ListenForService( + int port) { absl::MutexLock lock(&mutex_); // check current status diff --git a/internal/platform/implementation/windows/wifi_hotspot.h b/internal/platform/implementation/windows/wifi_hotspot.h index c6253f63..162c843b 100644 --- a/internal/platform/implementation/windows/wifi_hotspot.h +++ b/internal/platform/implementation/windows/wifi_hotspot.h @@ -27,7 +27,6 @@ #include // Nearby connections headers -#include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/implementation/wifi_hotspot.h" #include "internal/platform/implementation/windows/scheduled_executor.h" #include "internal/platform/implementation/windows/submittable_executor.h" @@ -325,10 +324,6 @@ class WifiHotspotMedium : public api::WifiHotspotMedium { // Scheduled task for connection timeout. std::shared_ptr connection_timeout_ = nullptr; - - // Listener to connect cancellation. - std::unique_ptr - connection_cancellation_listener_ = nullptr; }; } // namespace windows diff --git a/internal/platform/implementation/windows/wifi_hotspot_medium.cc b/internal/platform/implementation/windows/wifi_hotspot_medium.cc index 0ec43ac6..8a3532f7 100644 --- a/internal/platform/implementation/windows/wifi_hotspot_medium.cc +++ b/internal/platform/implementation/windows/wifi_hotspot_medium.cc @@ -109,6 +109,9 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( for (int i = 0; i < kWifiHotspotMaxConnectionRetries; i++) { try { StreamSocket socket{}; + // Listener to connect cancellation. + std::unique_ptr + connection_cancellation_listener = nullptr; // setup cancel listener if (cancellation_flag != nullptr) { @@ -118,7 +121,7 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( return nullptr; } - connection_cancellation_listener_ = + connection_cancellation_listener = std::make_unique( cancellation_flag, [socket]() { NEARBY_LOGS(WARNING) @@ -137,9 +140,6 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( } socket.ConnectAsync(host_name, service_name).get(); - if (connection_cancellation_listener_ != nullptr) { - connection_cancellation_listener_ = nullptr; - } if (connection_timeout_ != nullptr) { connection_timeout_->Cancel(); @@ -166,10 +166,6 @@ std::unique_ptr WifiHotspotMedium::ConnectToService( << " time due to unknown reason."; } - if (connection_cancellation_listener_ != nullptr) { - connection_cancellation_listener_ = nullptr; - } - if (connection_timeout_ != nullptr) { connection_timeout_->Cancel(); connection_timeout_ = nullptr; diff --git a/internal/platform/implementation/windows/wifi_lan.h b/internal/platform/implementation/windows/wifi_lan.h index 1e33f0fc..dcb4e765 100644 --- a/internal/platform/implementation/windows/wifi_lan.h +++ b/internal/platform/implementation/windows/wifi_lan.h @@ -34,7 +34,6 @@ #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "absl/types/optional.h" -#include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/exception.h" #include "internal/platform/implementation/wifi_lan.h" @@ -368,10 +367,6 @@ class WifiLanMedium : public api::WifiLanMedium { // Scheduled task for connection timeout. std::shared_ptr connection_timeout_ = nullptr; - - // Listener to connect cancellation. - std::unique_ptr - connection_cancellation_listener_ = nullptr; }; } // namespace windows diff --git a/internal/platform/implementation/windows/wifi_lan_medium.cc b/internal/platform/implementation/windows/wifi_lan_medium.cc index ea2923d9..b98b164c 100644 --- a/internal/platform/implementation/windows/wifi_lan_medium.cc +++ b/internal/platform/implementation/windows/wifi_lan_medium.cc @@ -350,6 +350,9 @@ std::unique_ptr WifiLanMedium::ConnectToService( return nullptr; } + std::unique_ptr connection_cancellation_listener = + nullptr; + HostName host_name{string_to_wstring(std::string(ipv4_address))}; winrt::hstring service_name{winrt::to_hstring(port)}; @@ -363,7 +366,7 @@ std::unique_ptr WifiLanMedium::ConnectToService( return nullptr; } - connection_cancellation_listener_ = + connection_cancellation_listener = std::make_unique( cancellation_flag, [socket]() { NEARBY_LOGS(WARNING) @@ -384,9 +387,6 @@ std::unique_ptr WifiLanMedium::ConnectToService( } socket.ConnectAsync(host_name, service_name).get(); - if (connection_cancellation_listener_ != nullptr) { - connection_cancellation_listener_ = nullptr; - } if (connection_timeout_ != nullptr) { connection_timeout_->Cancel(); @@ -409,10 +409,6 @@ std::unique_ptr WifiLanMedium::ConnectToService( << ":" << port; } - if (connection_cancellation_listener_ != nullptr) { - connection_cancellation_listener_ = nullptr; - } - if (connection_timeout_ != nullptr) { connection_timeout_->Cancel(); connection_timeout_ = nullptr; From b68f5324ff7a5fb0b057da0f14dedd7467d903bc Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Mon, 24 Apr 2023 10:46:35 -0700 Subject: [PATCH 25/63] Refactor FastPairHandshake to avoid locally store fast pair device PiperOrigin-RevId: 526691078 --- fastpair/handshake/fast_pair_handshake.h | 6 +-- .../handshake/fast_pair_handshake_impl.cc | 44 ++++++++++--------- fastpair/handshake/fast_pair_handshake_impl.h | 9 ++-- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/fastpair/handshake/fast_pair_handshake.h b/fastpair/handshake/fast_pair_handshake.h index c42da161..73b1e730 100644 --- a/fastpair/handshake/fast_pair_handshake.h +++ b/fastpair/handshake/fast_pair_handshake.h @@ -49,11 +49,10 @@ class FastPairHandshake { FastPairDevice& device, std::optional failure)>; FastPairHandshake( - FastPairDevice& device, OnCompleteCallback on_complete_cb, + OnCompleteCallback on_complete_cb, std::unique_ptr data_encryptor, std::unique_ptr gatt_service_client) - : device_(&device), - on_complete_callback_(std::move(on_complete_cb)), + : on_complete_callback_(std::move(on_complete_cb)), fast_pair_data_encryptor_(std::move(data_encryptor)), fast_pair_gatt_service_client_(std::move(gatt_service_client)) {} @@ -73,7 +72,6 @@ class FastPairHandshake { protected: bool completed_successfully_ = false; - FastPairDevice* device_; OnCompleteCallback on_complete_callback_; std::unique_ptr fast_pair_data_encryptor_; std::unique_ptr fast_pair_gatt_service_client_; diff --git a/fastpair/handshake/fast_pair_handshake_impl.cc b/fastpair/handshake/fast_pair_handshake_impl.cc index a2d6a2dc..16317315 100644 --- a/fastpair/handshake/fast_pair_handshake_impl.cc +++ b/fastpair/handshake/fast_pair_handshake_impl.cc @@ -32,22 +32,22 @@ namespace fastpair { FastPairHandshakeImpl::FastPairHandshakeImpl(FastPairDevice& device, OnCompleteCallback on_complete) - : FastPairHandshake(device, std::move(on_complete), nullptr, nullptr) { + : FastPairHandshake(std::move(on_complete), nullptr, nullptr) { fast_pair_gatt_service_client_ = FastPairGattServiceClientImpl::Factory::Create(device); fast_pair_gatt_service_client_->InitializeGattConnection( - [this](std::optional failure) { - OnGattClientInitializedCallback(failure); + [&](std::optional failure) { + OnGattClientInitializedCallback(device, failure); }); } void FastPairHandshakeImpl::OnGattClientInitializedCallback( - std::optional failure) { + FastPairDevice& device, std::optional failure) { if (failure.has_value()) { NEARBY_LOGS(WARNING) << __func__ << ": Failed to init gatt client with failure = " << failure.value(); - std::move(on_complete_callback_)(*device_, failure.value()); + std::move(on_complete_callback_)(device, failure.value()); return; } @@ -55,16 +55,19 @@ void FastPairHandshakeImpl::OnGattClientInitializedCallback( << __func__ << ": Fast Pair GATT service client initialization successful."; FastPairDataEncryptorImpl::Factory::CreateAsync( - *device_, absl::bind_front( - &FastPairHandshakeImpl::OnDataEncryptorCreateAsync, this)); + device, + [&](std::unique_ptr fast_pair_data_encryptor) { + OnDataEncryptorCreateAsync(device, std::move(fast_pair_data_encryptor)); + }); } void FastPairHandshakeImpl::OnDataEncryptorCreateAsync( + FastPairDevice& device, std::unique_ptr fast_pair_data_encryptor) { if (!fast_pair_data_encryptor) { NEARBY_LOGS(WARNING) << __func__ << ": Failed to create Fast Pair Data Encryptor."; - std::move(on_complete_callback_)(*device_, + std::move(on_complete_callback_)(device, PairFailure::kDataEncryptorRetrieval); return; } @@ -74,21 +77,22 @@ void FastPairHandshakeImpl::OnDataEncryptorCreateAsync( fast_pair_gatt_service_client_->WriteRequestAsync( /*message_type=*/kKeyBasedPairingType, /*flags=*/kInitialOrSubsequentFlags, - /*provider_address=*/device_->GetBleAddress(), + /*provider_address=*/device.GetBleAddress(), /*seekers_address=*/"", *fast_pair_data_encryptor_, - [this](absl::string_view response, std::optional failure) { - OnWriteResponse(response, failure); + [&](absl::string_view response, std::optional failure) { + OnWriteResponse(device, response, failure); }); } void FastPairHandshakeImpl::OnWriteResponse( - absl::string_view response, std::optional failure) { + FastPairDevice& device, absl::string_view response, + std::optional failure) { if (failure.has_value()) { NEARBY_LOGS(WARNING) << __func__ << ": Failed during key-based pairing protocol with failure = " << failure.value(); - std::move(on_complete_callback_)(*device_, failure.value()); + std::move(on_complete_callback_)(device, failure.value()); return; } @@ -98,33 +102,33 @@ void FastPairHandshakeImpl::OnWriteResponse( NEARBY_LOGS(WARNING) << __func__ << ": Handshake failed because of incorrect response size."; std::move(on_complete_callback_)( - *device_, PairFailure::kKeybasedPairingResponseDecryptFailure); + device, PairFailure::kKeybasedPairingResponseDecryptFailure); return; } std::vector response_bytes(response.begin(), response.end()); fast_pair_data_encryptor_->ParseDecryptResponse( - response_bytes, [this](std::optional response) { - OnParseDecryptedResponse(response); + response_bytes, [&](std::optional response) { + OnParseDecryptedResponse(device, response); }); } void FastPairHandshakeImpl::OnParseDecryptedResponse( - std::optional& response) { + FastPairDevice& device, std::optional& response) { if (!response.has_value()) { NEARBY_LOGS(WARNING) << __func__ << ": Missing decrypted response from parse."; std::move(on_complete_callback_)( - *device_, PairFailure::kKeybasedPairingResponseDecryptFailure); + device, PairFailure::kKeybasedPairingResponseDecryptFailure); return; } NEARBY_LOGS(INFO) << __func__ << ": Successfully decrypted and parsed response."; - device_->set_public_address( + device.set_public_address( device::CanonicalizeBluetoothAddress(response->address_bytes)); completed_successfully_ = true; - std::move(on_complete_callback_)(*device_, absl::nullopt); + std::move(on_complete_callback_)(device, absl::nullopt); } } // namespace fastpair diff --git a/fastpair/handshake/fast_pair_handshake_impl.h b/fastpair/handshake/fast_pair_handshake_impl.h index c41bbc30..e38fc688 100644 --- a/fastpair/handshake/fast_pair_handshake_impl.h +++ b/fastpair/handshake/fast_pair_handshake_impl.h @@ -33,12 +33,15 @@ class FastPairHandshakeImpl : public FastPairHandshake { FastPairHandshakeImpl& operator=(const FastPairHandshakeImpl&) = delete; private: - void OnGattClientInitializedCallback(std::optional failure); + void OnGattClientInitializedCallback(FastPairDevice& device, + std::optional failure); void OnDataEncryptorCreateAsync( + FastPairDevice& device, std::unique_ptr fast_pair_data_encryptor); - void OnWriteResponse(absl::string_view response, + void OnWriteResponse(FastPairDevice& device, absl::string_view response, std::optional failure); - void OnParseDecryptedResponse(std::optional& response); + void OnParseDecryptedResponse(FastPairDevice& device, + std::optional& response); }; } // namespace fastpair From 70bcabb1618c64f67dc090158fad048faa5310e6 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Mon, 24 Apr 2023 12:27:10 -0700 Subject: [PATCH 26/63] update port length to 2 bytes PiperOrigin-RevId: 526722524 --- internal/platform/connection_info_test.cc | 2 +- internal/platform/wifi_lan_connection_info.h | 11 +++++++---- internal/platform/wifi_lan_connection_info_test.cc | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/internal/platform/connection_info_test.cc b/internal/platform/connection_info_test.cc index ed8f9bab..caae8034 100644 --- a/internal/platform/connection_info_test.cc +++ b/internal/platform/connection_info_test.cc @@ -36,7 +36,7 @@ constexpr char kAction = 0x0F; constexpr absl::string_view kBluetoothUuid{"test"}; // WLAN constexpr absl::string_view kIpv4Addr = "\x4C\x8B\x1D\xCE"; -constexpr absl::string_view kPort = "\x12\x34\x56\x78"; +constexpr absl::string_view kPort = "\x12\x34"; constexpr absl::string_view kBssid = "\x0A\x1B\x2C\x34\x58\x7E"; TEST(ConnectionInfoTest, TestRestoreBle) { diff --git a/internal/platform/wifi_lan_connection_info.h b/internal/platform/wifi_lan_connection_info.h index a31bf6b2..46a14a2c 100644 --- a/internal/platform/wifi_lan_connection_info.h +++ b/internal/platform/wifi_lan_connection_info.h @@ -25,10 +25,10 @@ namespace nearby { -constexpr int kIpv4AddressLength = 4; -constexpr int kIpv6AddressLength = 16; -constexpr int kPortLength = 4; -constexpr int kBssidLength = 6; +inline constexpr int kIpv4AddressLength = 4; +inline constexpr int kIpv6AddressLength = 16; +inline constexpr int kPortLength = 2; +inline constexpr int kBssidLength = 6; class WifiLanConnectionInfo : public ConnectionInfo { public: @@ -51,6 +51,9 @@ class WifiLanConnectionInfo : public ConnectionInfo { } std::string ToDataElementBytes() const override; std::string GetIpAddress() const { return ip_address_; } + // This port is expected to be in hex form, such as \xFF\xFF for a value of + // 65535, 2 bytes in length. This field will be represented in network byte + // order (aka big-endian), so \x12\x34 will correspond to port 4660 (0x1234). std::string GetPort() const { return port_; } std::string GetBssid() const { return bssid_; } char GetActions() const override { return actions_; } diff --git a/internal/platform/wifi_lan_connection_info_test.cc b/internal/platform/wifi_lan_connection_info_test.cc index 817e47ff..d35b5cdd 100644 --- a/internal/platform/wifi_lan_connection_info_test.cc +++ b/internal/platform/wifi_lan_connection_info_test.cc @@ -30,7 +30,7 @@ namespace { constexpr absl::string_view kIpv4Addr = "\x4C\x8B\x1D\xCE"; constexpr absl::string_view kIpv6Addr = "\x4C\x8B\x1D\xCE\x4C\x8B\x1D\xCE\x4C\x8B\x1D\xCE\x4C\x8B\x1D\xCE"; -constexpr absl::string_view kPort = "\x12\x34\x56\x78"; +constexpr absl::string_view kPort = "\x12\x34"; constexpr absl::string_view kBssid = "\x0A\x1B\x2C\x34\x58\x7E"; constexpr char kAction = 0x0F; From 0e9d578e429102c82bbe8b8f5620f644ca26fc1b Mon Sep 17 00:00:00 2001 From: Janusz Sobczak Date: Mon, 24 Apr 2023 14:33:56 -0700 Subject: [PATCH 27/63] Clean up fetcher test PiperOrigin-RevId: 526757011 --- .../fast_pair_metadata_fetcher_impl_test.cc | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/fastpair/repository/fast_pair_metadata_fetcher_impl_test.cc b/fastpair/repository/fast_pair_metadata_fetcher_impl_test.cc index ba76880c..43e0381b 100644 --- a/fastpair/repository/fast_pair_metadata_fetcher_impl_test.cc +++ b/fastpair/repository/fast_pair_metadata_fetcher_impl_test.cc @@ -26,7 +26,6 @@ #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "fastpair/internal/test/fast_pair_fake_http_client.h" -#include "internal/network/http_client.h" namespace nearby { namespace fastpair { @@ -41,11 +40,6 @@ constexpr char kRequestUrl[] = "https://googleapis.com/nearbysharing/test"; constexpr char kQueryParameterAlternateOutputKey[] = "alt"; constexpr char kQueryParameterAlternateOutputProto[] = "proto"; -class MockHttpClient : public network::HttpClient { - public: - ~MockHttpClient() override = default; -}; - const FastPairMetadataFetcher::QueryParameters& GetTestRequestProtoAsQueryParameters() { static const FastPairMetadataFetcher::QueryParameters* @@ -130,11 +124,9 @@ class FastPairMetadataFetcherImplTest : public ::testing::Test { void CheckFastPairRepositoryGetUnauthRequest( const FastPairMetadataFetcher::QueryParameters& request_as_query_parameters) { - FastPairFakeHttpClient* fake_http_client = - reinterpret_cast(http_client_.get()); - EXPECT_EQ(fake_http_client->GetPendingRequest().size(), 1); + EXPECT_EQ(http_client_->GetPendingRequest().size(), 1); const network::HttpRequest& request = - fake_http_client->GetPendingRequest()[0].request; + http_client_->GetPendingRequest()[0].request; CheckPlatformTypeHeader(request.GetAllHeaders()); @@ -154,16 +146,14 @@ class FastPairMetadataFetcherImplTest : public ::testing::Test { int error, std::optional response_code = std::nullopt, const std::optional& response_string = std::nullopt) { - FastPairFakeHttpClient* client = - reinterpret_cast(http_client_.get()); - client->CompleteRequest(error, response_code, response_string); + http_client_->CompleteRequest(error, response_code, response_string); EXPECT_TRUE(result_ || network_error_); } std::unique_ptr result_; std::unique_ptr network_error_; private: - std::unique_ptr http_client_; + std::unique_ptr http_client_; FastPairMetadataFetcherImpl flow_{api::DeviceInfo::OsType::kChromeOs}; }; From cb48598ccae97ba91222c004f7fa73bfd95de55c Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Mon, 24 Apr 2023 14:42:01 -0700 Subject: [PATCH 28/63] Rewrite scanner_broker_impl_test PiperOrigin-RevId: 526759429 --- fastpair/scanning/BUILD | 9 +- fastpair/scanning/scanner_broker_impl_test.cc | 216 +++++------------- 2 files changed, 61 insertions(+), 164 deletions(-) diff --git a/fastpair/scanning/BUILD b/fastpair/scanning/BUILD index bca6d0c3..aa2afbf9 100644 --- a/fastpair/scanning/BUILD +++ b/fastpair/scanning/BUILD @@ -68,14 +68,15 @@ cc_test( deps = [ ":scanner", "//fastpair/common", - "//fastpair/scanning/fastpair:scanning", - "//fastpair/scanning/fastpair:test_support", + "//fastpair/internal/ble", + "//fastpair/proto:fastpair_cc_proto", + "//fastpair/server_access:test_support", + "//internal/platform:base", "//internal/platform:test_util", - "//internal/platform/implementation:types", + "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/strings", - "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) diff --git a/fastpair/scanning/scanner_broker_impl_test.cc b/fastpair/scanning/scanner_broker_impl_test.cc index 861d0f1d..6b3bf46b 100644 --- a/fastpair/scanning/scanner_broker_impl_test.cc +++ b/fastpair/scanning/scanner_broker_impl_test.cc @@ -16,190 +16,86 @@ #include #include -#include #include "gtest/gtest.h" +#include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/protocol.h" -#include "fastpair/scanning/fastpair/fake_fast_pair_discoverable_scanner.h" -#include "fastpair/scanning/fastpair/fake_fast_pair_scanner.h" -#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" -#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h" -#include "fastpair/scanning/fastpair/fast_pair_scanner.h" -#include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h" -#include "internal/platform/implementation/system_clock.h" +#include "fastpair/internal/ble/ble.h" +#include "fastpair/proto/fastpair_rpcs.proto.h" +#include "fastpair/scanning/scanner_broker.h" +#include "fastpair/server_access/fake_fast_pair_repository.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/count_down_latch.h" +#include "internal/platform/medium_environment.h" namespace nearby { namespace fastpair { namespace { -constexpr absl::string_view kTestDeviceAddress("11:12:13:14:15:16"); -constexpr absl::string_view kValidModelId("718c17"); -constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(200); - -class FakeFastPairScannerFactory : public FastPairScannerImpl::Factory { +constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(1000); +constexpr absl::string_view kServiceID{"Fast Pair"}; +constexpr absl::string_view kModelId{"718c17"}; +constexpr absl::string_view kFastPairServiceUuid{ + "0000FE2C-0000-1000-8000-00805F9B34FB"}; +constexpr absl::string_view kPublicAntiSpoof = + "Wuyr48lD3txnUhGiMF1IfzlTwRxxe+wMB1HLzP+" + "0wVcljfT3XPoiy1fntlneziyLD5knDVAJSE+RM/zlPRP/Jg=="; +class ScannerBrokerObserver : public ScannerBroker::Observer { public: - // FastPairScannerImpl::Factory: - std::shared_ptr CreateInstance() override { - auto fake_fast_pair_scanner = std::shared_ptr(); - fake_fast_pair_scanner_ = fake_fast_pair_scanner.get(); - return fake_fast_pair_scanner; - } - - ~FakeFastPairScannerFactory() override = default; - - FakeFastPairScanner* fake_fast_pair_scanner() { - return fake_fast_pair_scanner_; - } - - private: - FakeFastPairScanner* fake_fast_pair_scanner_ = nullptr; -}; - -class FakeFastPairDiscoverableScannerFactory - : public FastPairDiscoverableScannerImpl::Factory { - public: - // FastPairDiscoverableScannerImpl::Factory: - std::unique_ptr CreateInstance( - std::shared_ptr scanner, - std::shared_ptr adapter, DeviceCallback found_callback, - DeviceCallback lost_callback) override { - create_instance_ = true; - auto fake_fast_pair_discoverable_scanner = - std::make_unique( - std::move(found_callback), std::move(lost_callback)); - fake_fast_pair_discoverable_scanner_ = - fake_fast_pair_discoverable_scanner.get(); - return fake_fast_pair_discoverable_scanner; - } - - FakeFastPairDiscoverableScanner* fake_fast_pair_discoverable_scanner() { - return fake_fast_pair_discoverable_scanner_; - } - - bool create_instance() { return create_instance_; } - - protected: - bool create_instance_ = false; - FakeFastPairDiscoverableScanner* fake_fast_pair_discoverable_scanner_ = - nullptr; -}; - -class ScannerBrokerImplTest : public testing::Test, - public ScannerBroker::Observer { - public: - void SetUp() override { - adapter_ = std::shared_ptr(); - - scanner_factory_ = std::make_unique(); - FastPairScannerImpl::Factory::SetFactoryForTesting(scanner_factory_.get()); - - discoverable_scanner_factory_ = - std::make_unique(); - FastPairDiscoverableScannerImpl::Factory::SetFactoryForTesting( - discoverable_scanner_factory_.get()); - - scanner_broker_ = std::make_unique(); - scanner_broker_->AddObserver(this); - } - - void TearDown() override { - scanner_broker_->RemoveObserver(this); - scanner_broker_.reset(); - scanner_factory_.reset(); - discoverable_scanner_factory_.reset(); - FastPairScannerImpl::Factory::SetFactoryForTesting(nullptr); - FastPairDiscoverableScannerImpl::Factory::SetFactoryForTesting(nullptr); - adapter_.reset(); - } - - void TriggerDiscoverableDeviceFound() { - FastPairDevice device(std::string(kValidModelId), - std::string(kTestDeviceAddress), - Protocol::kFastPairInitialPairing); - discoverable_scanner_factory_->fake_fast_pair_discoverable_scanner() - ->TriggerDeviceFoundCallback(device); - } - - void TriggerDiscoverableDeviceLost() { - FastPairDevice device(std::string(kValidModelId), - std::string(kTestDeviceAddress), - Protocol::kFastPairInitialPairing); - discoverable_scanner_factory_->fake_fast_pair_discoverable_scanner() - ->TriggerDeviceLostCallback(device); + explicit ScannerBrokerObserver(ScannerBroker* scanner_broker, + CountDownLatch* accept_latch, + CountDownLatch* lost_latch) { + accept_latch_ = accept_latch; + lost_latch_ = lost_latch; + scanner_broker->AddObserver(this); } void OnDeviceFound(const FastPairDevice& device) override { - device_found_ = true; + accept_latch_->CountDown(); } void OnDeviceLost(const FastPairDevice& device) override { - device_lost_ = true; + lost_latch_->CountDown(); } - protected: - bool device_found_ = false; - bool device_lost_ = false; - std::shared_ptr adapter_; - std::unique_ptr scanner_factory_; - std::unique_ptr - discoverable_scanner_factory_; - std::unique_ptr scanner_broker_; + CountDownLatch* accept_latch_ = nullptr; + CountDownLatch* lost_latch_ = nullptr; }; -TEST_F(ScannerBrokerImplTest, DiscoverableFound) { - EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); +class ScannerBrokerImplTest : public testing::Test { + protected: + MediumEnvironment& env_{MediumEnvironment::Instance()}; +}; - scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); - SystemClock::Sleep(kTaskWaitTimeout); - EXPECT_FALSE(device_found_); - EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); +TEST_F(ScannerBrokerImplTest, CanStartScanning) { + env_.Start(); + auto repository_ = std::make_unique(); + auto scanner_broker = std::make_unique(); + proto::Device metadata; + std::string decoded_key; + absl::Base64Unescape(kPublicAntiSpoof, &decoded_key); + metadata.mutable_anti_spoofing_key_pair()->set_public_key(decoded_key); + repository_->SetFakeMetadata(kModelId, metadata); - TriggerDiscoverableDeviceFound(); - EXPECT_TRUE(device_found_); + std::string service_id(kServiceID); + ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; + std::string fast_pair_service_uuid(kFastPairServiceUuid); + Ble ble; + CountDownLatch accept_latch(1); + CountDownLatch lost_latch(1); + ScannerBrokerObserver observer(scanner_broker.get(), &accept_latch, + &lost_latch); + + ble.getMedium().StartAdvertising(service_id, advertisement_bytes, + fast_pair_service_uuid); + scanner_broker->StartScanning(Protocol::kFastPairInitialPairing); + EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); + ble.getMedium().StopAdvertising(service_id); + EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); + env_.Stop(); } - -TEST_F(ScannerBrokerImplTest, DiscoverableLost) { - EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); - - scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); - SystemClock::Sleep(kTaskWaitTimeout); - EXPECT_FALSE(device_found_); - EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); - - TriggerDiscoverableDeviceLost(); - EXPECT_TRUE(device_lost_); -} - -TEST_F(ScannerBrokerImplTest, RemoveObserver) { - EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); - - scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); - SystemClock::Sleep(kTaskWaitTimeout); - EXPECT_FALSE(device_found_); - EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); - - scanner_broker_->RemoveObserver(this); - TriggerDiscoverableDeviceLost(); - EXPECT_FALSE(device_lost_); -} - -TEST_F(ScannerBrokerImplTest, StopScanning) { - EXPECT_FALSE(discoverable_scanner_factory_->create_instance()); - - scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); - SystemClock::Sleep(kTaskWaitTimeout); - EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); - - scanner_broker_->StopScanning(Protocol::kFastPairInitialPairing); - SystemClock::Sleep(kTaskWaitTimeout); - - scanner_broker_->StartScanning(Protocol::kFastPairInitialPairing); - SystemClock::Sleep(kTaskWaitTimeout); - EXPECT_TRUE(discoverable_scanner_factory_->create_instance()); -} - } // namespace } // namespace fastpair } // namespace nearby From db308775d2dfb6e1bf49d666acbf92b516effe52 Mon Sep 17 00:00:00 2001 From: hai007 Date: Mon, 24 Apr 2023 18:58:12 -0700 Subject: [PATCH 29/63] [Sharing]add wifi hotspot permission to REQUEST_SETTING_PERMISSIONS event. PiperOrigin-RevId: 526815491 --- proto/sharing_enums.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/proto/sharing_enums.proto b/proto/sharing_enums.proto index e001bba6..442bc4f0 100644 --- a/proto/sharing_enums.proto +++ b/proto/sharing_enums.proto @@ -513,6 +513,7 @@ enum PermissionRequestType { PERMISSION_WIFI = 2; PERMISSION_BLUETOOTH = 3; PERMISSION_LOCATION = 4; + PERMISSION_WIFI_HOTSPOT = 5; } enum SharingUseCase { From c9cb329cdd70d4e656ad05e2ad319e5cd9cbb528 Mon Sep 17 00:00:00 2001 From: hai007 Date: Tue, 25 Apr 2023 00:09:20 -0700 Subject: [PATCH 30/63] Automated visibility attribute cleanup. PiperOrigin-RevId: 526877413 --- fastpair/repository/BUILD | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fastpair/repository/BUILD b/fastpair/repository/BUILD index 5467d57b..6bfb3386 100644 --- a/fastpair/repository/BUILD +++ b/fastpair/repository/BUILD @@ -16,10 +16,7 @@ cc_library( copts = [ "-Ithird_party", ], - visibility = [ - "//fastpair:__subpackages__", - "//location/nearby/cpp/sharing:__subpackages__", - ], + visibility = ["//fastpair:__subpackages__"], deps = [ "//fastpair/common", "//fastpair/proto:fastpair_cc_proto", From 10faeb88c7b6d129ba22cdb02cbada8a7024eb0a Mon Sep 17 00:00:00 2001 From: Nick Bourdakos Date: Tue, 25 Apr 2023 12:56:05 -0400 Subject: [PATCH 31/63] Add usage descriptions to iOS sample app --- .../Example/iOS Example.xcodeproj/project.pbxproj | 8 ++++++++ .../NearbyConnections/Example/iOS-Example-Info.plist | 10 ++++++++++ third_party/absl | 2 +- third_party/depot_tools | 2 +- .../google-toolbox-for-mac/google-toolbox-for-mac | 2 +- third_party/gtest | 2 +- third_party/mbedtls | 2 +- third_party/protobuf | 2 +- 8 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 connections/swift/NearbyConnections/Example/iOS-Example-Info.plist diff --git a/connections/swift/NearbyConnections/Example/iOS Example.xcodeproj/project.pbxproj b/connections/swift/NearbyConnections/Example/iOS Example.xcodeproj/project.pbxproj index aaab107c..88e1bf7c 100644 --- a/connections/swift/NearbyConnections/Example/iOS Example.xcodeproj/project.pbxproj +++ b/connections/swift/NearbyConnections/Example/iOS Example.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 23252B5729D739E400BB0370 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 23252B5929D739E500BB0370 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 23252B5C29D739E500BB0370 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 236C727829F83A1F00E54333 /* iOS-Example-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "iOS-Example-Info.plist"; sourceTree = SOURCE_ROOT; }; 23D1FD2329D8A73200620802 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; 23D1FD2529D8A9FF00620802 /* DiscoveredEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveredEndpoint.swift; sourceTree = ""; }; 23D1FD2729D8AA2200620802 /* ConnectionRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionRequest.swift; sourceTree = ""; }; @@ -78,6 +79,7 @@ 23252B5429D739E400BB0370 /* iOS Example */ = { isa = PBXGroup; children = ( + 236C727829F83A1F00E54333 /* iOS-Example-Info.plist */, 23F6A71429D7B0AB00558F56 /* Model */, 23252B5529D739E400BB0370 /* HelloConnectionsApp.swift */, 23252B5729D739E400BB0370 /* ContentView.swift */, @@ -345,6 +347,9 @@ DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "iOS-Example-Info.plist"; + INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "This app demonstrates Nearby Connections. Supply a value for this string to explain how the user benefits when they allow the app to use Bluetooth."; + INFOPLIST_KEY_NSLocalNetworkUsageDescription = "This app demonstrates Nearby Connections. Supply a value for this string to explain how the user benefits when they allow the app to use Local Network."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -374,6 +379,9 @@ DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "iOS-Example-Info.plist"; + INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "This app demonstrates Nearby Connections. Supply a value for this string to explain how the user benefits when they allow the app to use Bluetooth."; + INFOPLIST_KEY_NSLocalNetworkUsageDescription = "This app demonstrates Nearby Connections. Supply a value for this string to explain how the user benefits when they allow the app to use Local Network."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/connections/swift/NearbyConnections/Example/iOS-Example-Info.plist b/connections/swift/NearbyConnections/Example/iOS-Example-Info.plist new file mode 100644 index 00000000..7954f507 --- /dev/null +++ b/connections/swift/NearbyConnections/Example/iOS-Example-Info.plist @@ -0,0 +1,10 @@ + + + + + NSBonjourServices + + _307BEAB11028._tcp + + + diff --git a/third_party/absl b/third_party/absl index 29273402..9336be04 160000 --- a/third_party/absl +++ b/third_party/absl @@ -1 +1 @@ -Subproject commit 2927340217c37328319b5869285a6dcdbc13e7a7 +Subproject commit 9336be04a242237cd41a525bedfcf3be1bb55377 diff --git a/third_party/depot_tools b/third_party/depot_tools index 95a28c5a..e1197f06 160000 --- a/third_party/depot_tools +++ b/third_party/depot_tools @@ -1 +1 @@ -Subproject commit 95a28c5a14cf0c7040794e10e9404b270784010c +Subproject commit e1197f06a8f45c0328d341b30e337d3a4b609716 diff --git a/third_party/google-toolbox-for-mac/google-toolbox-for-mac b/third_party/google-toolbox-for-mac/google-toolbox-for-mac index 1b2da5e6..33941504 160000 --- a/third_party/google-toolbox-for-mac/google-toolbox-for-mac +++ b/third_party/google-toolbox-for-mac/google-toolbox-for-mac @@ -1 +1 @@ -Subproject commit 1b2da5e6e6b5edb1fa1427cc77e23f04069c04ad +Subproject commit 339415048005a9eba957357a02459a977a2e3007 diff --git a/third_party/gtest b/third_party/gtest index 8fa9461c..d61d4d8e 160000 --- a/third_party/gtest +++ b/third_party/gtest @@ -1 +1 @@ -Subproject commit 8fa9461cc28e053d66f17132808d287ae51575e2 +Subproject commit d61d4d8e64c08a662055e82904bbf90e108a704f diff --git a/third_party/mbedtls b/third_party/mbedtls index 6a327a5f..3e0418fe 160000 --- a/third_party/mbedtls +++ b/third_party/mbedtls @@ -1 +1 @@ -Subproject commit 6a327a5fdc2786cb50b4dbe5e3a75884a1f8435a +Subproject commit 3e0418fe502b2a2194e118d362efdfc0e558be73 diff --git a/third_party/protobuf b/third_party/protobuf index 53515ead..4812107b 160000 --- a/third_party/protobuf +++ b/third_party/protobuf @@ -1 +1 @@ -Subproject commit 53515eadce8d732bc0b2d0f0c8ec20ddd55ef86b +Subproject commit 4812107b9d0fb9fdcca933766c237c38f2150379 From a826f2d6272804e3f8a808663d4e4fbe92fd4262 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Tue, 25 Apr 2023 15:13:10 -0700 Subject: [PATCH 32/63] Add Pair failure info for fast pair pairing PiperOrigin-RevId: 527087848 --- fastpair/common/BUILD | 14 ++++++ fastpair/common/pair_failure.cc | 9 ++++ fastpair/common/pair_failure.h | 8 +++- fastpair/common/pair_failure_test.cc | 68 ++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 fastpair/common/pair_failure_test.cc diff --git a/fastpair/common/BUILD b/fastpair/common/BUILD index b7258241..96e95efc 100644 --- a/fastpair/common/BUILD +++ b/fastpair/common/BUILD @@ -39,3 +39,17 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "pair_failure_test", + size = "small", + srcs = [ + "pair_failure_test.cc", + ], + shard_count = 16, + deps = [ + ":common", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/common/pair_failure.cc b/fastpair/common/pair_failure.cc index bd32d6a6..53373f21 100644 --- a/fastpair/common/pair_failure.cc +++ b/fastpair/common/pair_failure.cc @@ -90,6 +90,15 @@ std::ostream& operator<<(std::ostream& stream, PairFailure failure) { stream << "[Potential pairing device lost between GATT connection attempts]"; break; + case PairFailure::kDeviceLostMidPairing: + stream << "[Potential pairing device lost during pairing.]"; + break; + case PairFailure::kPairingAndConnect: + stream << "[Failed to pair with discovered device.]"; + break; + case PairFailure::kPairingTimeout: + stream << "[Potential pairing failed with timeout.]"; + break; } return stream; diff --git a/fastpair/common/pair_failure.h b/fastpair/common/pair_failure.h index c69b7bb6..c2b360fa 100644 --- a/fastpair/common/pair_failure.h +++ b/fastpair/common/pair_failure.h @@ -68,7 +68,13 @@ enum class PairFailure { kPasskeyMismatch = 19, // Potential pairing device lost between GATT connection attempts. kPairingDeviceLostBetweenGattConnectionAttempts = 20, - kMaxValue = kPairingDeviceLostBetweenGattConnectionAttempts, + // Potential pairing device lost during pairing. + kDeviceLostMidPairing = 21, + // Failed to pair and connect with discovered device. + kPairingAndConnect = 22, + // Potential pairing timeout. + kPairingTimeout = 23, + kMaxValue = kPairingTimeout, }; std::ostream& operator<<(std::ostream& stream, PairFailure failure); diff --git a/fastpair/common/pair_failure_test.cc b/fastpair/common/pair_failure_test.cc new file mode 100644 index 00000000..eea3da05 --- /dev/null +++ b/fastpair/common/pair_failure_test.cc @@ -0,0 +1,68 @@ +// 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 "fastpair/common/pair_failure.h" + +#include "gtest/gtest.h" + +namespace nearby { +namespace fastpair { +namespace { + +TEST(PairFailureTest, PairFailureValue) { + EXPECT_EQ(static_cast(PairFailure::kCreateGattConnection), 0); + EXPECT_EQ(static_cast(PairFailure::kGattServiceDiscovery), 1); + EXPECT_EQ(static_cast(PairFailure::kGattServiceDiscoveryTimeout), 2); + EXPECT_EQ(static_cast(PairFailure::kDataEncryptorRetrieval), 3); + EXPECT_EQ( + static_cast(PairFailure::kKeyBasedPairingCharacteristicDiscovery), + 4); + EXPECT_EQ(static_cast(PairFailure::kPasskeyCharacteristicDiscovery), 5); + EXPECT_EQ(static_cast(PairFailure::kAccountKeyCharacteristicDiscovery), + 6); + EXPECT_EQ( + static_cast(PairFailure::kKeyBasedPairingCharacteristicSubscription), + 7); + EXPECT_EQ(static_cast(PairFailure::kPasskeyCharacteristicSubscription), + 8); + EXPECT_EQ(static_cast( + PairFailure::kKeyBasedPairingCharacteristicSubscriptionTimeout), + 9); + EXPECT_EQ( + static_cast(PairFailure::kPasskeyCharacteristicSubscriptionTimeout), + 10); + EXPECT_EQ(static_cast(PairFailure::kKeyBasedPairingCharacteristicWrite), + 11); + EXPECT_EQ(static_cast(PairFailure::kPasskeyPairingCharacteristicWrite), + 12); + EXPECT_EQ(static_cast(PairFailure::kKeyBasedPairingResponseTimeout), 13); + EXPECT_EQ(static_cast(PairFailure::kPasskeyResponseTimeout), 14); + EXPECT_EQ( + static_cast(PairFailure::kKeybasedPairingResponseDecryptFailure), + 15); + EXPECT_EQ( + static_cast(PairFailure::kIncorrectKeyBasedPairingResponseType), 16); + EXPECT_EQ(static_cast(PairFailure::kPasskeyDecryptFailure), 17); + EXPECT_EQ(static_cast(PairFailure::kIncorrectPasskeyResponseType), 18); + EXPECT_EQ(static_cast(PairFailure::kPasskeyMismatch), 19); + EXPECT_EQ(static_cast( + PairFailure::kPairingDeviceLostBetweenGattConnectionAttempts), + 20); + EXPECT_EQ(static_cast(PairFailure::kDeviceLostMidPairing), 21); + EXPECT_EQ(static_cast(PairFailure::kPairingAndConnect), 22); + EXPECT_EQ(static_cast(PairFailure::kPairingTimeout), 23); +} +} // namespace +} // namespace fastpair +} // namespace nearby From 102679b630eba87fe3218730c676394fa1f5dc12 Mon Sep 17 00:00:00 2001 From: hai007 Date: Tue, 25 Apr 2023 20:24:41 -0700 Subject: [PATCH 33/63] Automated visibility attribute cleanup. PiperOrigin-RevId: 527138508 --- internal/platform/implementation/BUILD | 3 --- 1 file changed, 3 deletions(-) diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index f6a47890..11f72960 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -81,7 +81,6 @@ cc_library( copts = ["-DNO_WEBRTC"], visibility = [ "//connections/implementation:__subpackages__", - "//internal:__pkg__", "//internal/network:__subpackages__", "//internal/platform:__pkg__", "//internal/platform/implementation:__subpackages__", @@ -116,8 +115,6 @@ cc_library( defines = ["NO_WEBRTC"], visibility = [ "//connections/implementation:__subpackages__", - "//fastpair:__subpackages__", - "//internal:__pkg__", "//internal:__subpackages__", "//internal/network:__subpackages__", "//internal/platform:__pkg__", From fa54c26fcd3bf298fd20eff3ee5b76ace6d51225 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Wed, 26 Apr 2023 07:15:13 -0700 Subject: [PATCH 34/63] Plumb CredentialManager::SetLocalDeviceMetadata through to PresenceService PiperOrigin-RevId: 527257552 --- presence/implementation/service_controller.h | 8 ++++++++ .../implementation/service_controller_impl.cc | 13 +++++++++++++ .../implementation/service_controller_impl.h | 9 +++++++++ presence/presence_service.h | 18 ++++++++++++++++++ presence/presence_service_test.cc | 19 +++++++++++++++++++ 5 files changed, 67 insertions(+) diff --git a/presence/implementation/service_controller.h b/presence/implementation/service_controller.h index 34185cdc..ead85a23 100644 --- a/presence/implementation/service_controller.h +++ b/presence/implementation/service_controller.h @@ -16,6 +16,7 @@ #define THIRD_PARTY_NEARBY_PRESENCE_IMPLEMENTATION_SERVICE_CONTROLLER_H_ #include +#include #include "absl/status/statusor.h" #include "presence/broadcast_request.h" @@ -40,6 +41,13 @@ class ServiceController { 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 ::nearby::internal::Metadata GetLocalDeviceMetadata() = 0; }; } // namespace presence diff --git a/presence/implementation/service_controller_impl.cc b/presence/implementation/service_controller_impl.cc index c49e035f..efeed31d 100644 --- a/presence/implementation/service_controller_impl.cc +++ b/presence/implementation/service_controller_impl.cc @@ -15,6 +15,7 @@ #include "presence/implementation/service_controller_impl.h" #include +#include #include "absl/status/statusor.h" #include "presence/data_types.h" @@ -40,5 +41,17 @@ void ServiceControllerImpl::StopBroadcast(BroadcastSessionId id) { broadcast_manager_.StopBroadcast(id); } +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) { + credential_manager_.SetLocalDeviceMetadata( + metadata, regen_credentials, manager_app_id, identity_types, + credential_life_cycle_days, contiguous_copy_of_credentials, + std::move(credentials_generated_cb)); +} + } // namespace presence } // namespace nearby diff --git a/presence/implementation/service_controller_impl.h b/presence/implementation/service_controller_impl.h index e36ff749..48ea2624 100644 --- a/presence/implementation/service_controller_impl.h +++ b/presence/implementation/service_controller_impl.h @@ -46,6 +46,15 @@ class ServiceControllerImpl : public ServiceController { 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; + ::nearby::internal::Metadata GetLocalDeviceMetadata() override { + return credential_manager_.GetLocalDeviceMetadata(); + } SingleThreadExecutor& GetBackgroundExecutor() { return executor_; } diff --git a/presence/presence_service.h b/presence/presence_service.h index 972e6487..651776e8 100644 --- a/presence/presence_service.h +++ b/presence/presence_service.h @@ -16,6 +16,8 @@ #define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_SERVICE_H_ #include +#include +#include #include "internal/platform/borrowable.h" #include "presence/data_types.h" @@ -46,6 +48,22 @@ class PresenceService { void StopBroadcast(BroadcastSessionId session_id); + 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) { + service_controller_->UpdateLocalDeviceMetadata( + metadata, regen_credentials, manager_app_id, identity_types, + credential_life_cycle_days, contiguous_copy_of_credentials, + std::move(credentials_generated_cb)); + } + + ::nearby::internal::Metadata GetLocalDeviceMetadata() { + return service_controller_->GetLocalDeviceMetadata(); + } + private: std::unique_ptr service_controller_; ::nearby::Lender lender_{this}; diff --git a/presence/presence_service_test.cc b/presence/presence_service_test.cc index 190301b8..b80035ca 100644 --- a/presence/presence_service_test.cc +++ b/presence/presence_service_test.cc @@ -24,11 +24,22 @@ namespace nearby { namespace presence { namespace { +using Metadata = ::nearby::internal::Metadata; + class PresenceServiceTest : public testing::Test { protected: nearby::MediumEnvironment& env_{nearby::MediumEnvironment::Instance()}; }; +Metadata CreateTestMetadata(absl::string_view account_name) { + Metadata metadata; + metadata.set_account_name(account_name); + metadata.set_device_name("NP test device"); + metadata.set_device_profile_url("test_image.test.com"); + metadata.set_bluetooth_mac_address("\xFF\xFF\xFF\xFF\xFF\xFF"); + return metadata; +} + TEST_F(PresenceServiceTest, DefaultConstructorWorks) { PresenceService presence_service; } @@ -59,6 +70,14 @@ TEST_F(PresenceServiceTest, StartThenStopScan) { env_.Stop(); } +TEST_F(PresenceServiceTest, UpdatingLocalMetadataWorks) { + PresenceService presence_service; + presence_service.UpdateLocalDeviceMetadata(CreateTestMetadata("Test account"), + false, "Test app", {}, 3, 1, {}); + EXPECT_EQ(presence_service.GetLocalDeviceMetadata().SerializeAsString(), + CreateTestMetadata("Test account").SerializeAsString()); +} + } // namespace } // namespace presence } // namespace nearby From 164a3d9b10b173d5ce36e107357342f1fde64fcb Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Wed, 26 Apr 2023 11:17:55 -0700 Subject: [PATCH 35/63] Maintain discovered device PiperOrigin-RevId: 527321179 --- fastpair/scanning/fastpair/BUILD | 1 + .../fast_pair_discoverable_scanner_impl.cc | 43 +++++++++++-------- .../fast_pair_discoverable_scanner_impl.h | 9 ++-- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/fastpair/scanning/fastpair/BUILD b/fastpair/scanning/fastpair/BUILD index a6e18638..a1c758a6 100644 --- a/fastpair/scanning/fastpair/BUILD +++ b/fastpair/scanning/fastpair/BUILD @@ -45,6 +45,7 @@ cc_library( "@com_google_absl//absl/functional:any_invocable", "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", ], ) diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc index 8ab560cf..cc3daaa1 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc @@ -25,6 +25,7 @@ #include "absl/functional/bind_front.h" #include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" #include "fastpair/common/constant.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/protocol.h" @@ -108,8 +109,10 @@ void FastPairDiscoverableScannerImpl::OnDeviceFound( << ": Device doesn't have any Fast Pair Service Data."; return; } - - model_id_parse_attempts_[peripheral.GetName()] = 1; + { + absl::MutexLock lock(&mutex_); + model_id_parse_attempts_[peripheral.GetName()] = 1; + } NEARBY_LOGS(INFO) << __func__ << ": Attempting to get model ID"; std::vector service_data; std::move(std::begin(fast_pair_service_data), @@ -125,18 +128,20 @@ void FastPairDiscoverableScannerImpl::OnDeviceFound( void FastPairDiscoverableScannerImpl::OnModelIdRetrieved( const std::string& address, const std::optional model_id) { - auto it = model_id_parse_attempts_.find(address); + { + absl::MutexLock lock(&mutex_); + auto it = model_id_parse_attempts_.find(address); - // If there's no entry in the map, the device was lost while parsing. - if (it == model_id_parse_attempts_.end()) { - NEARBY_LOGS(WARNING) - << __func__ - << ": Returning early because device as lost while parsing."; - return; + // If there's no entry in the map, the device was lost while parsing. + if (it == model_id_parse_attempts_.end()) { + NEARBY_LOGS(WARNING) + << __func__ + << ": Returning early because device as lost while parsing."; + return; + } + + model_id_parse_attempts_.erase(it); } - - model_id_parse_attempts_.erase(it); - if (!model_id.has_value()) { NEARBY_LOGS(INFO) << __func__ << ": Returning early because no model id was parsed."; @@ -182,9 +187,11 @@ void FastPairDiscoverableScannerImpl::OnDeviceMetadataRetrieved( "Ignoring this advertisement"; return; } - - FastPairDevice device(model_id, address, Protocol::kFastPairInitialPairing); - NotifyDeviceFound(device); + absl::MutexLock lock(&mutex_); + notified_devices_.insert_or_assign( + address, std::make_unique( + model_id, address, Protocol::kFastPairInitialPairing)); + NotifyDeviceFound(*notified_devices_[address]); } void FastPairDiscoverableScannerImpl::NotifyDeviceFound( @@ -192,23 +199,21 @@ void FastPairDiscoverableScannerImpl::NotifyDeviceFound( NEARBY_LOGS(VERBOSE) << "Notify Device found:" << "BluetoothAddress = " << device.GetBleAddress() << ", Model id = " << device.GetModelId(); - notified_devices_[device.GetBleAddress()] = &device; found_callback_(device); } void FastPairDiscoverableScannerImpl::OnDeviceLost( const BlePeripheral& peripheral) { NEARBY_LOGS(INFO) << __func__ << ": Running lost callback"; - + absl::MutexLock lock(&mutex_); model_id_parse_attempts_.erase(peripheral.GetName()); auto it = notified_devices_.find(peripheral.GetName()); // Don't invoke callback if we didn't notify this device. if (it == notified_devices_.end()) return; - FastPairDevice* notified_device = it->second; + lost_callback_(*it->second); notified_devices_.erase(it); - lost_callback_(*notified_device); } } // namespace fastpair diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h index 6fec1981..2b798242 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h @@ -20,6 +20,7 @@ #include #include +#include "absl/synchronization/mutex.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/repository/device_metadata.h" #include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" @@ -74,13 +75,15 @@ class FastPairDiscoverableScannerImpl : public FastPairDiscoverableScanner, const std::string model_id, DeviceMetadata& device_metadata); void NotifyDeviceFound(FastPairDevice& device); - + absl::Mutex mutex_; std::shared_ptr scanner_; std::shared_ptr adapter_; DeviceCallback found_callback_; DeviceCallback lost_callback_; - absl::flat_hash_map notified_devices_; - absl::flat_hash_map model_id_parse_attempts_; + absl::flat_hash_map> + notified_devices_ ABSL_GUARDED_BY(mutex_); + absl::flat_hash_map model_id_parse_attempts_ + ABSL_GUARDED_BY(mutex_); ObserverList observer_list_; }; From a605baf3266f9872717b60b0243a657b8e68ef68 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Wed, 26 Apr 2023 11:21:03 -0700 Subject: [PATCH 36/63] UnlockMutex before run callback PiperOrigin-RevId: 527322194 --- .../implementation/windows/ble_gatt_client.cc | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/internal/platform/implementation/windows/ble_gatt_client.cc b/internal/platform/implementation/windows/ble_gatt_client.cc index 809dff7f..0ba470ff 100644 --- a/internal/platform/implementation/windows/ble_gatt_client.cc +++ b/internal/platform/implementation/windows/ble_gatt_client.cc @@ -26,9 +26,12 @@ #include #include +#include "absl/functional/any_invocable.h" #include "absl/strings/escaping.h" #include "absl/strings/str_format.h" #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/byte_array.h" #include "internal/platform/implementation/ble_v2.h" @@ -624,10 +627,30 @@ void BleGattClient::OnCharacteristicValueChanged( } NEARBY_LOGS(VERBOSE) << __func__ << ": Got characteristic value length= " << data.size(); - absl::MutexLock lock(&mutex_); - DCHECK( - native_characteristic_map_[characteristic].on_characteristic_changed_cb); - native_characteristic_map_[characteristic].on_characteristic_changed_cb(data); + + absl::AnyInvocable + on_characteristic_changed_cb; + { + absl::MutexLock lock(&mutex_); + if (!native_characteristic_map_.contains(characteristic) || + !native_characteristic_map_[characteristic] + .on_characteristic_changed_cb) { + NEARBY_LOGS(INFO) << __func__ + << ": No registered callback for characteristic."; + return; + } + on_characteristic_changed_cb = + std::move(native_characteristic_map_[characteristic] + .on_characteristic_changed_cb); + } + + on_characteristic_changed_cb(std::move(data)); + + { + absl::MutexLock lock(&mutex_); + native_characteristic_map_[characteristic].on_characteristic_changed_cb = + std::move(on_characteristic_changed_cb); + } } } // namespace windows From 5b602e3033306fe44da6ed957e0befcbb407403c Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Wed, 26 Apr 2023 11:43:03 -0700 Subject: [PATCH 37/63] use std::optional instead of absl::optional PiperOrigin-RevId: 527329165 --- fastpair/handshake/BUILD | 4 +++- .../fake_fast_pair_gatt_service_client.h | 8 ++++--- .../fast_pair_gatt_service_client_impl.cc | 9 +++++-- ...fast_pair_gatt_service_client_impl_test.cc | 24 ++++++++++--------- .../handshake/fast_pair_handshake_lookup.cc | 1 + 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/fastpair/handshake/BUILD b/fastpair/handshake/BUILD index 526c8873..2b6b079e 100644 --- a/fastpair/handshake/BUILD +++ b/fastpair/handshake/BUILD @@ -43,7 +43,6 @@ cc_library( "//fastpair/repository", "//fastpair/server_access", "//internal/base:bluetooth_address", - "//internal/platform:base", "//internal/platform:comm", "//internal/platform:logging", "//internal/platform:types", @@ -54,6 +53,8 @@ cc_library( "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/strings", "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], ) @@ -120,6 +121,7 @@ cc_test( "//internal/platform/implementation/g3", # build_cleaner: keep "//internal/test", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/status", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", diff --git a/fastpair/handshake/fake_fast_pair_gatt_service_client.h b/fastpair/handshake/fake_fast_pair_gatt_service_client.h index 2274034e..019e2e0d 100644 --- a/fastpair/handshake/fake_fast_pair_gatt_service_client.h +++ b/fastpair/handshake/fake_fast_pair_gatt_service_client.h @@ -43,26 +43,28 @@ class FakeFastPairGattServiceClient : public FastPairGattServiceClient { WriteResponseCallback write_response_callback) override { key_based_write_response_callback_ = std::move(write_response_callback); } + void WritePasskeyAsync( uint8_t message_type, uint32_t passkey, const FastPairDataEncryptor& fast_pair_data_encryptor, WriteResponseCallback write_response_callback) override { passkey_write_response_callback_ = std::move(write_response_callback); } + void RunOnGattClientInitializedCallback( - std::optional failure = absl::nullopt) { + std::optional failure = std::nullopt) { std::move(on_initialized_callback_)(failure); } void RunWriteResponseCallback( absl::string_view value, - std::optional failure = absl::nullopt) { + std::optional failure = std::nullopt) { std::move(key_based_write_response_callback_)(value, failure); } void RunWritePasskeyCallback( absl::string_view value, - std::optional failure = absl::nullopt) { + std::optional failure = std::nullopt) { std::move(passkey_write_response_callback_)(value, failure); } diff --git a/fastpair/handshake/fast_pair_gatt_service_client_impl.cc b/fastpair/handshake/fast_pair_gatt_service_client_impl.cc index bb0685f5..4c0e2d04 100644 --- a/fastpair/handshake/fast_pair_gatt_service_client_impl.cc +++ b/fastpair/handshake/fast_pair_gatt_service_client_impl.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -27,7 +28,11 @@ #include "absl/functional/any_invocable.h" #include "absl/functional/bind_front.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/span.h" #include "fastpair/common/constant.h" +#include "fastpair/common/fast_pair_device.h" +#include "fastpair/common/pair_failure.h" #include "fastpair/handshake/fast_pair_data_encryptor.h" #include "fastpair/handshake/fast_pair_gatt_service_client.h" #include "internal/base/bluetooth_address.h" @@ -168,7 +173,7 @@ void FastPairGattServiceClientImpl::GetFastPairGattCharacteristics() { } is_initialized_ = true; - std::move(on_gatt_initialized_callback_)(absl::nullopt); + std::move(on_gatt_initialized_callback_)(std::nullopt); } std::optional @@ -340,7 +345,7 @@ void FastPairGattServiceClientImpl::WritePasskeyAsync( // Subscribe the notification once the passkey characteristic's value changed if (SubscribePasskeyCharacteristic()) { is_passkey_notification_subscribed_ = true; - // Write passkey confonirmation request to the passkey characteristic + // Write passkey confirmation request to the passkey characteristic WritePasskeyCharacteristic( std::string(data_to_write_vec.begin(), data_to_write_vec.end())); } diff --git a/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc b/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc index 07f36962..f6750688 100644 --- a/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc +++ b/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc @@ -15,17 +15,21 @@ #include "fastpair/handshake/fast_pair_gatt_service_client_impl.h" #include +#include #include #include #include #include "gtest/gtest.h" +#include "absl/status/status.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "fastpair/common/constant.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/pair_failure.h" +#include "fastpair/common/protocol.h" #include "fastpair/handshake/fake_fast_pair_data_encryptor.h" +#include "fastpair/handshake/fast_pair_gatt_service_client.h" #include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/byte_array.h" @@ -188,18 +192,16 @@ class FastPairGattServiceClientTest : public testing::Test { passkey_characteristic_.value(), false, {}); } - absl::optional GetInitializedCallbackResult() { + std::optional GetInitializedCallbackResult() { return initalized_failure_; } void WriteTestCallback(absl::string_view response, - absl::optional failure) { + std::optional failure) { write_failure_ = failure; } - absl::optional GetWriteCallbackResult() { - return write_failure_; - } + std::optional GetWriteCallbackResult() { return write_failure_; } void WriteRequestToKeyBased() { gatt_client_->WriteRequestAsync( @@ -240,8 +242,8 @@ class FastPairGattServiceClientTest : public testing::Test { private: std::optional key_based_characteristic_; std::optional passkey_characteristic_; - absl::optional initalized_failure_; - absl::optional write_failure_; + std::optional initalized_failure_; + std::optional write_failure_; Property properties_ = Property::kWrite | Property::kNotify; Permission permissions_ = Permission::kWrite; }; @@ -277,7 +279,7 @@ TEST_F(FastPairGattServiceClientTest, SuccessfulWriteKeyBaseCharacteristics) { InitializeFastPairGattServiceClient(); WriteRequestToKeyBased(); EXPECT_EQ(TriggerKeyBasedGattChanged(), absl::OkStatus()); - EXPECT_EQ(GetWriteCallbackResult(), absl::nullopt); + EXPECT_EQ(GetWriteCallbackResult(), std::nullopt); } TEST_F(FastPairGattServiceClientTest, SuccessfulWritePasskeyCharacteristics) { @@ -285,7 +287,7 @@ TEST_F(FastPairGattServiceClientTest, SuccessfulWritePasskeyCharacteristics) { InitializeFastPairGattServiceClient(); WriteRequestToPasskey(); EXPECT_EQ(TriggerPasskeyGattChanged(), absl::OkStatus()); - EXPECT_EQ(GetWriteCallbackResult(), absl::nullopt); + EXPECT_EQ(GetWriteCallbackResult(), std::nullopt); } TEST_F(FastPairGattServiceClientTest, FailedSubscribeKeybaseCharacteristic) { @@ -297,7 +299,7 @@ TEST_F(FastPairGattServiceClientTest, FailedSubscribeKeybaseCharacteristic) { PairFailure::kKeyBasedPairingCharacteristicSubscription); WriteRequestToPasskey(); EXPECT_EQ(TriggerPasskeyGattChanged(), absl::OkStatus()); - EXPECT_EQ(GetWriteCallbackResult(), absl::nullopt); + EXPECT_EQ(GetWriteCallbackResult(), std::nullopt); } TEST_F(FastPairGattServiceClientTest, FailedSubscribePasskeyCharacteristic) { @@ -306,7 +308,7 @@ TEST_F(FastPairGattServiceClientTest, FailedSubscribePasskeyCharacteristic) { RemoveDiscoveredPasskeyCharacteristic(); WriteRequestToKeyBased(); EXPECT_EQ(TriggerKeyBasedGattChanged(), absl::OkStatus()); - EXPECT_EQ(GetWriteCallbackResult(), absl::nullopt); + EXPECT_EQ(GetWriteCallbackResult(), std::nullopt); WriteRequestToPasskey(); EXPECT_EQ(GetWriteCallbackResult(), PairFailure::kPasskeyCharacteristicSubscription); diff --git a/fastpair/handshake/fast_pair_handshake_lookup.cc b/fastpair/handshake/fast_pair_handshake_lookup.cc index cad7e193..a137280d 100644 --- a/fastpair/handshake/fast_pair_handshake_lookup.cc +++ b/fastpair/handshake/fast_pair_handshake_lookup.cc @@ -20,6 +20,7 @@ #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "fastpair/handshake/fast_pair_handshake_impl.h" +#include "internal/platform/logging.h" namespace nearby { namespace fastpair { From a4be31137ff9defa3923ba31a2c831c489b5e8f2 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Wed, 26 Apr 2023 12:36:26 -0700 Subject: [PATCH 38/63] Enable manually set log level for fast pair windows PiperOrigin-RevId: 527343929 --- fastpair/dart/windows/BUILD | 2 ++ fastpair/dart/windows/fast_pair_wrapper_adapter.cc | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fastpair/dart/windows/BUILD b/fastpair/dart/windows/BUILD index 53d9d1b9..b289626c 100644 --- a/fastpair/dart/windows/BUILD +++ b/fastpair/dart/windows/BUILD @@ -27,6 +27,7 @@ lexan.cc_windows_dll( "-Ithird_party", ], defines = [ + "LOG_SEVERITY_VERBOSE", "_WIN32_WINNT=_WIN32_WINNT_WIN10", ], tags = ["windows-dll"], @@ -57,6 +58,7 @@ lexan.cc_windows_dll( "-Ithird_party", ], defines = [ + "LOG_SEVERITY_VERBOSE", "_WIN32_WINNT=_WIN32_WINNT_WIN10", ], tags = ["windows-dll"], diff --git a/fastpair/dart/windows/fast_pair_wrapper_adapter.cc b/fastpair/dart/windows/fast_pair_wrapper_adapter.cc index c6c3197d..41788d45 100644 --- a/fastpair/dart/windows/fast_pair_wrapper_adapter.cc +++ b/fastpair/dart/windows/fast_pair_wrapper_adapter.cc @@ -24,6 +24,11 @@ namespace windows { static FastPairWrapper *pWrapper_ = nullptr; void *InitFastPairWrapper() { +#if defined(NEARBY_LOG_SEVERITY) + // Direct override of logging level. + NEARBY_LOG_SET_SEVERITY(NEARBY_LOG_SEVERITY); +#endif // LOG_SEVERITY_VERBOSE; + FastPairWrapperImpl *pWrapper = new FastPairWrapperImpl(); pWrapper_ = pWrapper; return pWrapper; @@ -36,7 +41,7 @@ void CloseFastPairWrapper(FastPairWrapper *pWrapper) { } void __stdcall StartScan(FastPairWrapper *pWrapper) { - NEARBY_LOGS(INFO) << "StartScan is called"; + NEARBY_LOGS(VERBOSE) << "StartScan is called"; if (pWrapper_ == nullptr) { NEARBY_LOGS(INFO) << "The pWrapper is a null pointer."; return; From 698ca77f2a326f8733f7d5618fe7da957ab894c6 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Wed, 26 Apr 2023 14:51:41 -0700 Subject: [PATCH 39/63] Mutex guard FakeClock PiperOrigin-RevId: 527382176 --- internal/test/fake_clock.cc | 7 +++++-- internal/test/fake_clock.h | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/test/fake_clock.cc b/internal/test/fake_clock.cc index 418863b6..57c6b29d 100644 --- a/internal/test/fake_clock.cc +++ b/internal/test/fake_clock.cc @@ -21,7 +21,10 @@ namespace nearby { -absl::Time FakeClock::Now() const { return now_; } +absl::Time FakeClock::Now() const { + absl::MutexLock lock(&mutex_); + return now_; +} void FakeClock::AddObserver(absl::string_view name, std::function observer) { @@ -36,9 +39,9 @@ void FakeClock::RemoveObserver(absl::string_view name) { void FakeClock::FastForward(absl::Duration duration) { std::vector timer_callback_ids; - now_ += duration; { absl::MutexLock lock(&mutex_); + now_ += duration; for (const auto& observer : observers_) { timer_callback_ids.push_back(observer.first); } diff --git a/internal/test/fake_clock.h b/internal/test/fake_clock.h index dc64aae0..7cef161a 100644 --- a/internal/test/fake_clock.h +++ b/internal/test/fake_clock.h @@ -45,8 +45,8 @@ class FakeClock : public Clock { int GetObserversCount() ABSL_LOCKS_EXCLUDED(mutex_); private: - absl::Time now_; mutable absl::Mutex mutex_; + absl::Time now_ ABSL_GUARDED_BY(mutex_); absl::flat_hash_map> observers_ ABSL_GUARDED_BY(mutex_); }; From 83739b3185720d0b2957cf4e3e5e4049d8229482 Mon Sep 17 00:00:00 2001 From: Johnson Lu Date: Thu, 27 Apr 2023 01:04:18 -0700 Subject: [PATCH 40/63] [Connections] Switch to use P2P IPv6 address PiperOrigin-RevId: 527502244 --- connections/implementation/proto/offline_wire_formats.proto | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/connections/implementation/proto/offline_wire_formats.proto b/connections/implementation/proto/offline_wire_formats.proto index 17ecdbaf..4fe839d5 100644 --- a/connections/implementation/proto/offline_wire_formats.proto +++ b/connections/implementation/proto/offline_wire_formats.proto @@ -255,6 +255,10 @@ message BandwidthUpgradeNegotiationFrame { optional int32 port = 3; optional int32 frequency = 4; optional string gateway = 5 [default = "0.0.0.0"]; + // IPv6 link-local address, network order (128bits). + // The GO should listen on both IPv4 and IPv6 addresses. + // https://en.wikipedia.org/wiki/Link-local_address#IPv6 + optional bytes ip_v6_address = 6; } // Accompanies Medium.WEB_RTC From 4b27e8c446318ae90772c3e88399151b15c02f03 Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Thu, 27 Apr 2023 12:46:15 -0700 Subject: [PATCH 41/63] Fixed crash during BT connection PiperOrigin-RevId: 527656444 --- .../implementation/windows/bluetooth_classic_medium.cc | 1 - .../implementation/windows/bluetooth_classic_socket.cc | 6 ------ .../implementation/windows/bluetooth_classic_socket.h | 2 -- 3 files changed, 9 deletions(-) diff --git a/internal/platform/implementation/windows/bluetooth_classic_medium.cc b/internal/platform/implementation/windows/bluetooth_classic_medium.cc index 2a14c61e..563df49c 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/windows/bluetooth_classic_medium.cc @@ -310,7 +310,6 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( } nearby::CancellationFlagListener cancellation_flag_listener( cancellation_flag, [&rfcomm_socket]() { - rfcomm_socket->CancelIOAsync().get(); rfcomm_socket->Close(); }); diff --git a/internal/platform/implementation/windows/bluetooth_classic_socket.cc b/internal/platform/implementation/windows/bluetooth_classic_socket.cc index 7a89d01d..5eedb94b 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_socket.cc +++ b/internal/platform/implementation/windows/bluetooth_classic_socket.cc @@ -195,12 +195,6 @@ ExceptionOr BluetoothSocket::BluetoothInputStream::Read( } } -IAsyncAction BluetoothSocket::CancelIOAsync() { - // Cancels pending reads and writes over a StreamSocket object. - // https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocket.cancelioasync?view=winrt-20348 - return windows_socket_.CancelIOAsync(); -} - Exception BluetoothSocket::BluetoothInputStream::Close() { NEARBY_LOGS(INFO) << __func__ << ": Close bluetooth input stream."; diff --git a/internal/platform/implementation/windows/bluetooth_classic_socket.h b/internal/platform/implementation/windows/bluetooth_classic_socket.h index 9fd92614..19e2de3b 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_socket.h +++ b/internal/platform/implementation/windows/bluetooth_classic_socket.h @@ -98,8 +98,6 @@ class BluetoothSocket : public api::BluetoothSocket { bool Connect(HostName connectionHostName, winrt::hstring connectionServiceName); - IAsyncAction CancelIOAsync(); - private: static constexpr int kInitialTransmitPacketSize = 4096; From b0985c70b401708c8d7c80298b5311d84a2f7387 Mon Sep 17 00:00:00 2001 From: Eiden Kim Date: Thu, 27 Apr 2023 13:54:54 -0700 Subject: [PATCH 42/63] Update iOS unit test min version to have IOS_MINIMUM_OS PiperOrigin-RevId: 527675057 --- connections/clients/ios/BUILD | 5 +++-- connections/swift/NearbyConnections/BUILD | 5 +++-- connections/swift/NearbyCoreAdapter/BUILD | 5 +++-- .../implementation/apple/Mediums/Ble/Sockets/BUILD | 10 ++++++---- internal/platform/implementation/apple/Tests/BUILD | 10 ++++++---- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/connections/clients/ios/BUILD b/connections/clients/ios/BUILD index 14476ab4..b6c76a51 100644 --- a/connections/clients/ios/BUILD +++ b/connections/clients/ios/BUILD @@ -1,4 +1,4 @@ -# Copyright 2020 Google LLC +# Copyright 2020-2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") +load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -71,7 +72,7 @@ swift_library( ios_unit_test( name = "BuildTests", - minimum_os_version = "13.0", + minimum_os_version = IOS_MINIMUM_OS, runner = "//testing/utp/ios:IOS_13", deps = [ ":BuildTestsLib", diff --git a/connections/swift/NearbyConnections/BUILD b/connections/swift/NearbyConnections/BUILD index d696a6fd..a46ce495 100644 --- a/connections/swift/NearbyConnections/BUILD +++ b/connections/swift/NearbyConnections/BUILD @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# 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. @@ -14,6 +14,7 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") +load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -41,7 +42,7 @@ swift_library( ios_unit_test( name = "Tests", - minimum_os_version = "13.0", + minimum_os_version = IOS_MINIMUM_OS, runner = "//testing/utp/ios:IOS_13", deps = [ ":TestsLib", diff --git a/connections/swift/NearbyCoreAdapter/BUILD b/connections/swift/NearbyCoreAdapter/BUILD index 212c6fd0..0a83da89 100644 --- a/connections/swift/NearbyCoreAdapter/BUILD +++ b/connections/swift/NearbyCoreAdapter/BUILD @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# 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. @@ -14,6 +14,7 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") +load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -52,7 +53,7 @@ swift_library( ios_unit_test( name = "Tests", - minimum_os_version = "13.0", + minimum_os_version = IOS_MINIMUM_OS, runner = "//testing/utp/ios:IOS_13", deps = [ ":TestsLib", diff --git a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD index aef86932..c6cebf08 100644 --- a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD +++ b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD @@ -1,6 +1,4 @@ -load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test") - -# Copyright 2020 Google LLC +# Copyright 2020-2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +11,10 @@ load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_exp # 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("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test") +load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") + licenses(["notice"]) package( @@ -86,6 +88,6 @@ objc_library( swift_explicit_module_build_test( name = "swift_explicit_module_build_test", ignore_headerless_targets = True, - minimum_os_version = "13.0", + minimum_os_version = IOS_MINIMUM_OS, platform_type = "ios", ) diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index 3607c383..e14c3d40 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -1,6 +1,4 @@ -load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") - -# Copyright 2020 Google LLC +# Copyright 2020-2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +11,10 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") # 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("//tools/build_defs/apple:ios.bzl", "ios_unit_test") +load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") + licenses(["notice"]) package(default_visibility = ["//visibility:public"]) @@ -39,7 +41,7 @@ objc_library( ios_unit_test( name = "PlatformTests", - minimum_os_version = "13.0", + minimum_os_version = IOS_MINIMUM_OS, runner = "//testing/utp/ios:IOS_13", deps = [ ":PlatformTestslib", From 5dfe7094c3aafc760f3cefd92b6e01813430cfa5 Mon Sep 17 00:00:00 2001 From: hai007 Date: Thu, 27 Apr 2023 18:07:39 -0700 Subject: [PATCH 43/63] Update unit test minimum IOS version to 13.7 PiperOrigin-RevId: 527738714 --- connections/clients/ios/BUILD | 5 ++--- connections/swift/NearbyConnections/BUILD | 5 ++--- connections/swift/NearbyCoreAdapter/BUILD | 5 ++--- .../platform/implementation/apple/Mediums/Ble/Sockets/BUILD | 3 +-- internal/platform/implementation/apple/Tests/BUILD | 5 ++--- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/connections/clients/ios/BUILD b/connections/clients/ios/BUILD index b6c76a51..4cfda8db 100644 --- a/connections/clients/ios/BUILD +++ b/connections/clients/ios/BUILD @@ -16,7 +16,6 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") -load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -72,8 +71,8 @@ swift_library( ios_unit_test( name = "BuildTests", - minimum_os_version = IOS_MINIMUM_OS, - runner = "//testing/utp/ios:IOS_13", + minimum_os_version = "15.0", + runner = "//testing/utp/ios:IOS_LATEST", deps = [ ":BuildTestsLib", ], diff --git a/connections/swift/NearbyConnections/BUILD b/connections/swift/NearbyConnections/BUILD index a46ce495..88c3f7fe 100644 --- a/connections/swift/NearbyConnections/BUILD +++ b/connections/swift/NearbyConnections/BUILD @@ -14,7 +14,6 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") -load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -42,8 +41,8 @@ swift_library( ios_unit_test( name = "Tests", - minimum_os_version = IOS_MINIMUM_OS, - runner = "//testing/utp/ios:IOS_13", + minimum_os_version = "15.0", + runner = "//testing/utp/ios:IOS_LATEST", deps = [ ":TestsLib", ], diff --git a/connections/swift/NearbyCoreAdapter/BUILD b/connections/swift/NearbyCoreAdapter/BUILD index 0a83da89..560f1c9a 100644 --- a/connections/swift/NearbyCoreAdapter/BUILD +++ b/connections/swift/NearbyCoreAdapter/BUILD @@ -14,7 +14,6 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") -load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -53,8 +52,8 @@ swift_library( ios_unit_test( name = "Tests", - minimum_os_version = IOS_MINIMUM_OS, - runner = "//testing/utp/ios:IOS_13", + minimum_os_version = "15.0", + runner = "//testing/utp/ios:IOS_LATEST", deps = [ ":TestsLib", ], diff --git a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD index c6cebf08..021d194e 100644 --- a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD +++ b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD @@ -13,7 +13,6 @@ # limitations under the License. load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test") -load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -88,6 +87,6 @@ objc_library( swift_explicit_module_build_test( name = "swift_explicit_module_build_test", ignore_headerless_targets = True, - minimum_os_version = IOS_MINIMUM_OS, + minimum_os_version = "15.0", platform_type = "ios", ) diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index e14c3d40..5a1fdf52 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -13,7 +13,6 @@ # limitations under the License. load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") -load("//googlemac/iPhone/OTPAuth:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -41,8 +40,8 @@ objc_library( ios_unit_test( name = "PlatformTests", - minimum_os_version = IOS_MINIMUM_OS, - runner = "//testing/utp/ios:IOS_13", + minimum_os_version = "15.0", + runner = "//testing/utp/ios:IOS_LATEST", deps = [ ":PlatformTestslib", ], From d7be59c741e6020e5bd7e16828a11889479010b6 Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Thu, 27 Apr 2023 18:55:54 -0700 Subject: [PATCH 44/63] Enable cancellation flag support by default PiperOrigin-RevId: 527746766 --- internal/platform/feature_flags.h | 2 +- internal/platform/feature_flags_test.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/platform/feature_flags.h b/internal/platform/feature_flags.h index 8ff66d12..9aae0f39 100644 --- a/internal/platform/feature_flags.h +++ b/internal/platform/feature_flags.h @@ -26,7 +26,7 @@ class FeatureFlags { public: // Holds for all the feature flags. struct Flags { - bool enable_cancellation_flag = true; + bool enable_cancellation_flag = false; bool enable_async_bandwidth_upgrade = true; // If a scheduled runnable is already running, Cancel() will synchronously // wait for the task to complete. diff --git a/internal/platform/feature_flags_test.cc b/internal/platform/feature_flags_test.cc index e6e4eedd..3d4925ef 100644 --- a/internal/platform/feature_flags_test.cc +++ b/internal/platform/feature_flags_test.cc @@ -21,23 +21,23 @@ namespace nearby { namespace { constexpr FeatureFlags::Flags kTestFeatureFlags{ - .enable_cancellation_flag = false, + .enable_cancellation_flag = true, .keep_alive_interval_millis = 5000, .keep_alive_timeout_millis = 30000}; TEST(FeatureFlagsTest, ToSetFeatureWorks) { const FeatureFlags& features = FeatureFlags::GetInstance(); - EXPECT_TRUE(features.GetFlags().enable_cancellation_flag); + EXPECT_FALSE(features.GetFlags().enable_cancellation_flag); EXPECT_EQ(5000, features.GetFlags().keep_alive_interval_millis); EXPECT_EQ(30000, features.GetFlags().keep_alive_timeout_millis); MediumEnvironment& medium_environment = MediumEnvironment::Instance(); medium_environment.SetFeatureFlags(kTestFeatureFlags); - EXPECT_FALSE(features.GetFlags().enable_cancellation_flag); + EXPECT_TRUE(features.GetFlags().enable_cancellation_flag); const FeatureFlags& another_features_ref = FeatureFlags::GetInstance(); - EXPECT_FALSE(another_features_ref.GetFlags().enable_cancellation_flag); + EXPECT_TRUE(another_features_ref.GetFlags().enable_cancellation_flag); } } // namespace From 5edd8e25ca7a5d9fe8f43f0a56284155850c31d5 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Thu, 27 Apr 2023 19:00:15 -0700 Subject: [PATCH 45/63] Introduce v3 NC API callbacks PiperOrigin-RevId: 527747390 --- Package.swift | 5 +- connections/BUILD | 7 +- connections/core.h | 279 ++++++++++++++++-- connections/implementation/BUILD | 2 +- connections/implementation/client_proxy.h | 2 +- connections/v3/BUILD | 18 ++ connections/v3/bandwidth_info.h | 54 ++++ connections/v3/connection_listening_options.h | 47 +++ connections/v3/connection_resolution.h | 32 ++ connections/v3/listeners.h | 133 +++++++++ internal/base/BUILD | 2 +- internal/{ => interop}/BUILD | 1 + internal/{ => interop}/device.h | 0 .../interop}/device_provider.h | 16 +- internal/platform/BUILD | 6 +- presence/BUILD | 2 +- presence/presence_device.cc | 2 +- presence/presence_device.h | 2 +- 18 files changed, 563 insertions(+), 47 deletions(-) create mode 100644 connections/v3/BUILD create mode 100644 connections/v3/bandwidth_info.h create mode 100644 connections/v3/connection_listening_options.h create mode 100644 connections/v3/connection_resolution.h create mode 100644 connections/v3/listeners.h rename internal/{ => interop}/BUILD (92%) rename internal/{ => interop}/device.h (100%) rename {connections => internal/interop}/device_provider.h (80%) diff --git a/Package.swift b/Package.swift index 45725c95..4dcdd9a5 100644 --- a/Package.swift +++ b/Package.swift @@ -245,7 +245,7 @@ let package = Package( .target( name: "json", path: "third_party/json", - exclude:[ + exclude: [ "json/LICENSES", "json/cmake", "json/docs", @@ -430,10 +430,11 @@ let package = Package( "connections/implementation/mediums/BUILD", "connections/implementation/BUILD", "connections/implementation/fuzzers", + "connections/v3/BUILD", "connections/BUILD", - "internal/BUILD", "internal/crypto/BUILD", "internal/crypto/BUILD.gn", + "internal/interop/BUILD", "internal/weave/BUILD", "internal/platform/flags/BUILD", "internal/platform/implementation/shared/BUILD", diff --git a/connections/BUILD b/connections/BUILD index e2351f8f..1912dc89 100644 --- a/connections/BUILD +++ b/connections/BUILD @@ -30,8 +30,9 @@ cc_library( deps = [ ":core_types", "//connections/implementation:internal", - "//internal:device", + "//connections/v3:v3_types", "//internal/analytics:event_logger", + "//internal/interop:device", "//internal/platform:base", "//internal/platform:logging", "//internal/platform:types", @@ -54,7 +55,6 @@ cc_library( hdrs = [ "advertising_options.h", "connection_options.h", - "device_provider.h", "discovery_options.h", "listeners.h", "medium_selector.h", @@ -74,7 +74,6 @@ cc_library( "//location/nearby/testing:__subpackages__", ], deps = [ - "//internal:device", "//internal/platform:base", "//internal/platform:types", "//internal/platform:util", @@ -99,7 +98,7 @@ cc_test( ":core", ":core_types", "//connections/implementation:internal_test", - "//internal:device", + "//internal/interop:device", "//internal/platform:base", "//internal/platform:logging", "//internal/platform:types", diff --git a/connections/core.h b/connections/core.h index a444f653..714ebbc8 100644 --- a/connections/core.h +++ b/connections/core.h @@ -20,14 +20,18 @@ #include "absl/strings/string_view.h" #include "absl/types/span.h" -#include "connections/device_provider.h" +#include "connections/connection_options.h" #include "connections/implementation/client_proxy.h" #include "connections/implementation/service_controller.h" #include "connections/implementation/service_controller_router.h" #include "connections/listeners.h" #include "connections/params.h" +#include "connections/payload.h" +#include "connections/v3/connection_listening_options.h" +#include "connections/v3/listeners.h" #include "internal/analytics/event_logger.h" -#include "internal/device.h" +#include "internal/interop/device.h" +#include "internal/interop/device_provider.h" namespace nearby { namespace connections { @@ -246,33 +250,264 @@ class Core { std::string Dump(); - //******************************* V2 ******************************* - void RequestConnectionV2(const NearbyDevice& device, - const ConnectionRequestInfo& info, - ConnectionOptions& connection_options, - ResultCallback callback); + //******************************* V3 ******************************* + // NOTE: Do NOT mix with the V1 APIs above, this might result in undefined + // behavior! - void AcceptConnectionV2(const NearbyDevice& device, - const PayloadListener& listener, + // Starts advertising an endpoint for a local app. + // + // service_id - An identifier to advertise your app to other endpoints. + // This can be an arbitrary string, so long as it uniquely + // identifies your service. A good default is to use your + // app's package name. + // advertising_options - The options for advertising. + // local_device - The local device for use when advertising when a + // `DeviceProvider` has not been registered. + // callback - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if advertising started successfully. + // Status::STATUS_ALREADY_ADVERTISING if the app is already advertising. + // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently + // connected to remote endpoints; call StopAllEndpoints first. + void StartAdvertisingV3(absl::string_view service_id, + const AdvertisingOptions& advertising_options, + const NearbyDevice& local_device, ResultCallback callback); - void RejectConnectionV2(const NearbyDevice& device, ResultCallback callback); + // Starts advertising an endpoint for a local app. + // Should only be used when DeviceProvider has been registered with this + // Nearby Connections instance. Otherwise, use the + // StartAdvertisingV3(service_id, advertising_options, local_device, callback) + // function above. + // + // service_id - An identifier to advertise your app to other endpoints. + // This can be an arbitrary string, so long as it uniquely + // identifies your service. A good default is to use your + // app's package name. + // advertising_options - The options for advertising. + // callback - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if advertising started successfully. + // Status::STATUS_ALREADY_ADVERTISING if the app is already advertising. + // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently + // connected to remote endpoints; call StopAllEndpoints first. + void StartAdvertisingV3(absl::string_view service_id, + const AdvertisingOptions& advertising_options, + ResultCallback callback); - // Span is being used here as we will not be modifying this block of memory. - // We also do not need to own this block of memory, so we can use Span. - // We are using NearbyDevice* so as to not lose attributes when using a - // vector-like structure of NearbyDevice, as object information is stripped if - // using NearbyDevice or NearbyDevice&. - void SendPayloadV2(absl::Span devices, - const Payload& payload, ResultCallback callback); + // Stops advertising a local endpoint. Should be called after calling + // StartAdvertising, as soon as the application no longer needs to advertise + // itself or goes inactive. Payloads can still be sent to connected + // endpoints after advertising ends. + // + // result_cb - to access the status of the operation when available. + void StopAdvertisingV3(ResultCallback result_cb); - void DisconnectFromDeviceV2(const NearbyDevice& device, - ResultCallback callback); + // Starts discovery for remote endpoints with the specified service ID. + // + // service_id - The ID for the service to be discovered, as specified in + // the corresponding call to StartAdvertising. + // discovery_options - The options for discovery. + // listener_cb - A callback notified when a remote endpoint is discovered. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if discovery started successfully. + // Status::STATUS_ALREADY_DISCOVERING if the app is already + // discovering the specified service. + // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently + // connected to remote endpoints; call StopAllEndpoints first. + void StartDiscoveryV3(absl::string_view service_id, + const DiscoveryOptions& discovery_options, + v3::DiscoveryListener listener_cb, + ResultCallback callback); - void InitiateBandwidthUpgradeV2(const NearbyDevice& device, - ResultCallback callback); + // Stops discovery for remote endpoints, after a previous call to + // StartDiscovery, when the client no longer needs to discover endpoints or + // goes inactive. Payloads can still be sent to connected endpoints after + // discovery ends. + // + // result_cb - to access the status of the operation when available. + void StopDiscoveryV3(ResultCallback result_cb); - void RegisterDeviceProvider(const NearbyDeviceProvider& provider); + // Starts listening for incoming connections. + // + // listener_cb - The connection listener to broadcast any updates. + // options - The options for listening for a connection. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if listening started successfully. + // Status::STATUS_ALREADY_LISTENING if the app is already listening. + // Status::STATUS_ALREADY_ADVERTISING if the app is already advertising. + // Status::STATUS_OUT_OF_ORDER_API_CALL if the app is currently connected + // to remote endpoints; call StopAllEndpoints first. + void StartListeningForIncomingConnections( + const v3::ConnectionListeningOptions& options, + v3::ConnectionListener listener_cb, ResultCallback result_cb); + + // Stops listening for incoming connections. Should be called after + // calling StartListeningForIncomingConnections. + void StopListeningForIncomingConnections(); + + // Sends a request to connect to a remote endpoint. + // + // local_device - The local device information which will be shown on the + // remote endpoint. Used only when a DeviceProvider is not + // registered. + // remote_device - The remote device to which a connection request will be + // sent. Should match the value provided in a call to + // DiscoveryListener::endpoint_found_cb() + // connection_options - Connection options for the new connection if both + // sides accept. + // connection_cb - The callback to be notified on connection events. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if the connection request was sent. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already + // has a connection to the specified endpoint. + // Status::STATUS_RADIO_ERROR if we failed to connect because of an + // issue with Bluetooth/WiFi. + // Status::STATUS_ERROR if we failed to connect for any other reason. + void RequestConnectionV3(const NearbyDevice& local_device, + const NearbyDevice& remote_device, + const ConnectionOptions& connection_options, + v3::ConnectionListener connection_cb, + ResultCallback result_cb); + + // Sends a request to connect to a remote endpoint. + // + // remote_device - The remote device to which a connection request will be + // sent. Should match the value provided in a call to + // DiscoveryListener::endpoint_found_cb() + // connection_options - Connection options for the new connection if both + // sides accept. + // connection_cb - The callback to be notified on connection events. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if the connection request was sent. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already + // has a connection to the specified endpoint. + // Status::STATUS_RADIO_ERROR if we failed to connect because of an + // issue with Bluetooth/WiFi. + // Status::STATUS_ERROR if we failed to connect for any other reason. + void RequestConnectionV3(const NearbyDevice& remote_device, + const ConnectionOptions& connection_options, + v3::ConnectionListener connection_cb, + ResultCallback result_cb); + + // Accepts a connection to a remote endpoint. This method must be called + // before Payloads can be exchanged with the remote endpoint. + // + // remote_device - The remote device. Should match the value provided in a + // call to ConnectionListener::OnConnectionInitiated. + // + // listener_cb - A callback for payloads exchanged with the remote endpoint. + // + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if the connection request was accepted. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT if the app already. + // has a connection to the specified endpoint. + // Status::STATUS_ENDPOINT_UNKNOWN if the app doesn't currently have a + // pending connection to the remote device. + void AcceptConnectionV3(const NearbyDevice& remote_device, + v3::PayloadListener listener_cb, + ResultCallback result_cb); + + // Rejects a connection to a remote endpoint. + // + // remote_device - The device for the remote endpoint. Should match the + // value provided in a call to + // v3::ConnectionListener::OnConnectionInitiated(). + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK} if the connection request was rejected. + // Status::STATUS_ALREADY_CONNECTED_TO_ENDPOINT} if the app already + // has a connection to the specified endpoint. + void RejectConnectionV3(const NearbyDevice& remote_device, + ResultCallback result_cb); + + // Sends a Payload to a remote device. Payloads can only be sent to remote + // devices once a notice of connection acceptance has been delivered via + // v3::ConnectionListener::OnConnectionResult(). + // + // remote_device - The remote device to which the payload should be sent. + // payload - The Payload to be sent. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OUT_OF_ORDER_API_CALL if the device has not first + // performed advertisement or discovery (to set the Strategy. + // Status::STATUS_ENDPOINT_UNKNOWN if there's no active (or pending) + // connection to the remote endpoint. + // Status::STATUS_OK if none of the above errors occurred. Note that this + // indicates that Nearby Connections will attempt to send the Payload, + // but not that the send has successfully completed yet. Errors might + // still occur during transmission (and at different times for + // different endpoints), and will be delivered via + // PayloadCallback#onPayloadTransferUpdate. + void SendPayloadV3(const NearbyDevice& remote_device, const Payload& payload, + ResultCallback result_cb); + + // Cancels a Payload currently in-flight to or from remote endpoint(s). + // + // remote_device - The remote device with which the payload is being + // exchanged. + // payload_id - The identifier for the Payload to be canceled. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK if none of the above errors occurred. + void CancelPayloadV3(const NearbyDevice& remote_device, int64_t payload_id, + ResultCallback result_cb); + + // Disconnects from a remote endpoint. {@link Payload}s can no longer be sent + // to or received from the endpoint after this method is called. + // + // remote_device - The remote device to disconnect from. + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK - finished successfully. + void DisconnectFromDeviceV3(const NearbyDevice& remote_device, + ResultCallback result_cb); + + // Disconnects from, and removes all traces, of all connected and/or + // discovered endpoints. This call is expected to be preceded by a call to + // StopAdvertising() or StopDiscovery() as needed. After calling + // StopAllDevices(), no further operations with remote endpoints will be + // possible until a new call to one of StartAdvertising() or StartDiscovery(). + // + // result_cb - To access the status of the operation when available. + void StopAllDevicesV3(ResultCallback result_cb); + + // Sends a request to initiate connection bandwidth upgrade. + // + // remote_device - The identifier for the remote device which will be + // switching to a higher connection data rate and possibly + // different wireless protocol. On success, calls + // ConnectionListener::bandwidth_changed_cb(). + // result_cb - to access the status of the operation when available. + // Possible status codes include: + // Status::STATUS_OK - finished successfully. + void InitiateBandwidthUpgradeV3(const NearbyDevice& remote_device, + ResultCallback result_cb); + + // Updates AdvertisingOptions. It compares the old AdvertisingOptions and the + // new AdvertisingOptions to start/stop each advertising medium. + // + // advertising_options - The new advertising options a client wishes to use. + // result_cb - to access the status of the operation when available. + void UpdateAdvertisingOptionsV3(const AdvertisingOptions& advertising_options, + ResultCallback result_cb); + + // Updates DiscoveryOptions. It compares the old DiscoveryOptions and the new + // DiscoveryOptions to start/stop each discovery medium. + // + // discovery_options - The new discovery options a client wishes to use. + // result_cb - to access the status of the operation when available. + void UpdateDiscoveryOptionsV3(const DiscoveryOptions& discovery_options, + ResultCallback result_cb); + + // Registers a DeviceProvider to provide functionality for Nearby Connections + // to interact with the DeviceProvider for retrieving the local device. + void RegisterDeviceProvider(NearbyDeviceProvider&& provider); private: ClientProxy client_; diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 8b4fe91c..9cb96f4d 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -137,9 +137,9 @@ cc_library( "//connections/implementation/mediums:utils", "//connections/implementation/mediums/webrtc", "//connections/implementation/proto:offline_wire_formats_cc_proto", - "//internal:device", "//internal/analytics:event_logger", "//internal/flags:nearby_flags", + "//internal/interop:device", "//internal/platform:base", "//internal/platform:cancellation_flag", "//internal/platform:comm", diff --git a/connections/implementation/client_proxy.h b/connections/implementation/client_proxy.h index d11e395e..53457101 100644 --- a/connections/implementation/client_proxy.h +++ b/connections/implementation/client_proxy.h @@ -30,7 +30,7 @@ #include "connections/status.h" #include "connections/strategy.h" #include "internal/analytics/event_logger.h" -#include "internal/device.h" +#include "internal/interop/device.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancelable_alarm.h" #include "internal/platform/cancellation_flag.h" diff --git a/connections/v3/BUILD b/connections/v3/BUILD new file mode 100644 index 00000000..0c768dda --- /dev/null +++ b/connections/v3/BUILD @@ -0,0 +1,18 @@ +cc_library( + name = "v3_types", + hdrs = [ + "bandwidth_info.h", + "connection_listening_options.h", + "connection_resolution.h", + "listeners.h", + ], + visibility = [ + "//connections:__subpackages__", + ], + deps = [ + "//connections:core_types", + "//internal/interop:device", + "//proto:connections_enums_cc_proto", + "@com_google_absl//absl/functional:any_invocable", + ], +) diff --git a/connections/v3/bandwidth_info.h b/connections/v3/bandwidth_info.h new file mode 100644 index 00000000..1ed9fb18 --- /dev/null +++ b/connections/v3/bandwidth_info.h @@ -0,0 +1,54 @@ +// 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_CONNECTIONS_V3_BANDWIDTH_INFO_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_V3_BANDWIDTH_INFO_H_ + +#include "proto/connections_enums.pb.h" + +namespace nearby { +namespace connections { +namespace v3 { + +// Represents the connection quality. +enum class Quality { + // Unknown connection quality. Recommended to wait for one of kMedium or + // kHigh. + kUnknown = 0, + // The connection quality is poor (5KBps) and is not suitable for + // sending files. It's recommended you wait until the connection + // quality improves. + kLow = 1, + // The connection quality is ok (60~200KBps) and is suitable for + // sending small files. For large files, it's recommended you wait + // until the connection quality improves. + kMedium = 2, + // The connection quality is good or great (1MBps~60MBps) and files + // can readily be sent. The connection quality cannot improve further + // but may still be impacted by environment or hardware limitations. + kHigh = 3, +}; + +// Used to indicate the new connection quality when upgrading to a new medium +// e.g. BT -> WiFi direct. +struct BandwidthInfo { + Quality quality; + ::location::nearby::proto::connections::Medium medium; +}; + +} // namespace v3 +} // namespace connections +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_V3_BANDWIDTH_INFO_H_ diff --git a/connections/v3/connection_listening_options.h b/connections/v3/connection_listening_options.h new file mode 100644 index 00000000..5f3961ba --- /dev/null +++ b/connections/v3/connection_listening_options.h @@ -0,0 +1,47 @@ +// 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_CONNECTIONS_V3_CONNECTION_LISTENING_OPTIONS_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_V3_CONNECTION_LISTENING_OPTIONS_H_ + +#include + +#include "connections/strategy.h" +#include "internal/interop/device.h" +#include "proto/connections_enums.pb.h" + +namespace nearby { +namespace connections { +namespace v3 { + +struct ConnectionListeningOptions { + Strategy strategy; + bool allow_bluetooth_radio_toggling = true; + bool allow_wifi_radio_toggling = true; + bool enable_ble_listening = false; + bool enable_bluetooth_listening = true; + bool enable_wlan_listening = true; + bool auto_upgrade_bandwidth = true; + bool enforce_topology_constraints = true; + std::vector upgrade_mediums; + std::vector<::location::nearby::proto::connections::Medium> listening_mediums; + nearby::NearbyDevice::Type listening_endpoint_type = + NearbyDevice::Type::kConnectionsDevice; +}; + +} // namespace v3 +} // namespace connections +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_V3_CONNECTION_LISTENING_OPTIONS_H_ diff --git a/connections/v3/connection_resolution.h b/connections/v3/connection_resolution.h new file mode 100644 index 00000000..18b361c5 --- /dev/null +++ b/connections/v3/connection_resolution.h @@ -0,0 +1,32 @@ +// 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_CONNECTIONS_V3_CONNECTION_RESOLUTION_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_V3_CONNECTION_RESOLUTION_H_ + +#include "connections/status.h" + +namespace nearby { +namespace connections { +namespace v3 { + +struct ConnectionResult { + nearby::connections::Status status; +}; + +} // namespace v3 +} // namespace connections +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_V3_CONNECTION_RESOLUTION_H_ diff --git a/connections/v3/listeners.h b/connections/v3/listeners.h new file mode 100644 index 00000000..10d44509 --- /dev/null +++ b/connections/v3/listeners.h @@ -0,0 +1,133 @@ +// 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_CONNECTIONS_V3_LISTENERS_H_ +#define THIRD_PARTY_NEARBY_CONNECTIONS_V3_LISTENERS_H_ + +#include "absl/functional/any_invocable.h" +#include "connections/listeners.h" +#include "connections/v3/bandwidth_info.h" +#include "connections/v3/connection_resolution.h" +#include "internal/interop/device.h" + +namespace nearby { +namespace connections { +namespace v3 { + +struct ConnectionListener { + // A basic encrypted channel has been created between you and the endpoint. + // Both sides are now asked if they wish to accept or reject the connection + // before any data can be sent over this channel. + // + // This is your chance, before you accept the connection, to confirm that you + // connected to the correct device. Both devices are given an identical token; + // it's up to you to decide how to verify it before proceeding. Typically this + // involves showing the token on both devices and having the users manually + // compare and confirm; however, this is only required if you desire a secure + // connection between the devices. + // + // Whichever route you decide to take (including not authenticating the other + // device), call Core::AcceptConnection() when you're ready to talk, or + // Core::RejectConnection() to close the connection. + // + // remote_device - The identifier for the remote endpoint. + // info - Other relevant information about the connection. + absl::AnyInvocable + initiated_cb = [](const NearbyDevice&, const ConnectionResponseInfo&) {}; + + // Called when both sides have accepted or either side has rejected the + // connection. If the {@link ConnectionResolution}'s status is {@link + // ConnectionsStatusCodes#SUCCESS}, both sides have accepted the + // connection and may now send {@link Payload}s to each other. + // Otherwise, the connection was rejected. + + // remote_device - The identifier for the remote endpoint. + // resolution - The resolution of the connection (accepted or rejected). + absl::AnyInvocable + result_cb = [](const NearbyDevice&, ConnectionResult) {}; + + // Called when a remote endpoint is disconnected or has become unreachable. + // At this point service (re-)discovery may start again. + // + // remote_device - The identifier for the remote endpoint. + absl::AnyInvocable disconnected_cb = + [](const NearbyDevice&) {}; + + // Called when the connection's available bandwidth has changed. + // + // remote_device - The identifier for the remote endpoint. + // bandwidth_info - Bandwidth info about the new medium that was upgraded to. + absl::AnyInvocable + bandwidth_changed_cb = [](const NearbyDevice&, BandwidthInfo) {}; +}; + +struct DiscoveryListener { + // Called when a remote endpoint is discovered. + // + // remote_device - The remote device that was discovered. + // service_id - The ID of the service advertised by the remote endpoint. + absl::AnyInvocable + endpoint_found_cb = [](const NearbyDevice&, const absl::string_view) {}; + + // Called when a remote endpoint is no longer discoverable; only called for + // endpoints that previously had been passed to {@link + // #onEndpointFound(String, DiscoveredEndpointInfo)}. + // + // remote_device - The ID of the remote endpoint that was lost. + absl::AnyInvocable endpoint_lost_cb = + [](const NearbyDevice&) {}; + + // Called when a remote endpoint is found with an updated distance. + // + // arguments: + // remote_device - The ID of the remote endpoint that was lost. + // info - The distance info, encoded as enum value. + absl::AnyInvocable + endpoint_distance_changed_cb = [](const NearbyDevice&, DistanceInfo) {}; +}; + +struct PayloadListener { + // Called when a Payload is received from a remote endpoint. Depending + // on the type of the Payload, all of the data may or may not have been + // received at the time of this call. Use OnPayloadProgress() to + // get updates on the status of the data received. + // + // remote_device - The identifier for the remote endpoint that sent the + // payload. + // payload - The Payload object received. + absl::AnyInvocable + payload_received_cb = [](const NearbyDevice&, Payload) {}; + + // Called with progress information about an active Payload transfer, either + // incoming or outgoing. + // + // remote_device - The identifier for the remote endpoint that is sending or + // receiving this payload. + // info - The PayloadProgressInfo structure describing the status of + // the transfer. + absl::AnyInvocable + payload_progress_cb = + [](const NearbyDevice&, const PayloadProgressInfo&) {}; +}; + +} // namespace v3 +} // namespace connections +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_CONNECTIONS_V3_LISTENERS_H_ diff --git a/internal/base/BUILD b/internal/base/BUILD index c49f3e13..9e6b2da9 100644 --- a/internal/base/BUILD +++ b/internal/base/BUILD @@ -12,7 +12,7 @@ cc_library( ], visibility = [ "//fastpair:__subpackages__", - "//internal:__pkg__", + "//internal/interop:__pkg__", "//internal/platform:__pkg__", "//location/nearby/cpp/sharing:__subpackages__", ], diff --git a/internal/BUILD b/internal/interop/BUILD similarity index 92% rename from internal/BUILD rename to internal/interop/BUILD index 7d724792..9836cef4 100644 --- a/internal/BUILD +++ b/internal/interop/BUILD @@ -2,6 +2,7 @@ cc_library( name = "device", hdrs = [ "device.h", + "device_provider.h", ], visibility = [ "//connections:__subpackages__", diff --git a/internal/device.h b/internal/interop/device.h similarity index 100% rename from internal/device.h rename to internal/interop/device.h diff --git a/connections/device_provider.h b/internal/interop/device_provider.h similarity index 80% rename from connections/device_provider.h rename to internal/interop/device_provider.h index f46915ed..a622601d 100644 --- a/connections/device_provider.h +++ b/internal/interop/device_provider.h @@ -15,22 +15,18 @@ #ifndef THIRD_PARTY_NEARBY_CONNECTIONS_DEVICE_PROVIDER_H_ #define THIRD_PARTY_NEARBY_CONNECTIONS_DEVICE_PROVIDER_H_ -#include - -#include "internal/device.h" +#include "internal/interop/device.h" namespace nearby { -namespace connections { - -using ::nearby::NearbyDevice; +// The base device provider class for use with the Nearby Connections V3 APIs. +// This class currently provides a function to get the local device for whatever +// client implements it. class NearbyDeviceProvider { virtual ~NearbyDeviceProvider() = default; - virtual NearbyDevice* GetLocalDevice() = 0; - virtual std::string GetServiceId() = 0; -}; -} // namespace connections + virtual NearbyDevice* GetLocalDevice() = 0; +}; } // namespace nearby #endif // THIRD_PARTY_NEARBY_CONNECTIONS_DEVICE_PROVIDER_H_ diff --git a/internal/platform/BUILD b/internal/platform/BUILD index 5cfbbbb5..aa8ab327 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -46,8 +46,8 @@ cc_library( visibility = [ "//connections:__subpackages__", "//fastpair:__subpackages__", - "//internal:__pkg__", "//internal/auth:__subpackages__", + "//internal/interop:__pkg__", "//internal/platform:__subpackages__", "//internal/platform/implementation:__subpackages__", "//internal/preferences:__subpackages__", @@ -101,7 +101,7 @@ cc_library( visibility = [ "//connections:__subpackages__", "//fastpair:__subpackages__", - "//internal:__pkg__", + "//internal/interop:__pkg__", "//internal/network:__subpackages__", "//internal/platform:__subpackages__", "//internal/proto/analytics:__subpackages__", @@ -151,7 +151,7 @@ cc_library( "wifi_lan_connection_info.h", ], visibility = [ - "//internal:__pkg__", + "//internal/interop:__pkg__", "//presence:__subpackages__", ], deps = [ diff --git a/presence/BUILD b/presence/BUILD index 8b417166..55b534a4 100644 --- a/presence/BUILD +++ b/presence/BUILD @@ -60,8 +60,8 @@ cc_library( "scan_request_builder.h", ], deps = [ - "//internal:device", "//internal/crypto", + "//internal/interop:device", "//internal/platform:connection_info", "//internal/platform:logging", "//internal/platform/implementation:types", diff --git a/presence/presence_device.cc b/presence/presence_device.cc index 747eae15..2f9229a8 100644 --- a/presence/presence_device.cc +++ b/presence/presence_device.cc @@ -18,7 +18,7 @@ #include #include "internal/platform/implementation/crypto.h" -#include "internal/device.h" +#include "internal/interop/device.h" #include "internal/platform/ble_connection_info.h" #include "internal/platform/implementation/system_clock.h" #include "presence/device_motion.h" diff --git a/presence/presence_device.h b/presence/presence_device.h index 94fd14eb..b4455c2a 100644 --- a/presence/presence_device.h +++ b/presence/presence_device.h @@ -21,7 +21,7 @@ #include "absl/time/time.h" #include "absl/types/variant.h" -#include "internal/device.h" +#include "internal/interop/device.h" #include "internal/proto/metadata.pb.h" #include "presence/data_element.h" #include "presence/device_motion.h" From aea5b223d33bfa7d467e694b62eda4ad7d796a15 Mon Sep 17 00:00:00 2001 From: Eiden Kim Date: Thu, 27 Apr 2023 19:50:40 -0700 Subject: [PATCH 46/63] Create min iOS and test runner under third_party/nearby for common test target. PiperOrigin-RevId: 527754820 --- connections/clients/ios/BUILD | 5 +++-- connections/swift/NearbyConnections/BUILD | 5 +++-- connections/swift/NearbyCoreAdapter/BUILD | 5 +++-- .../platform/implementation/apple/Mediums/Ble/Sockets/BUILD | 3 ++- internal/platform/implementation/apple/Tests/BUILD | 5 +++-- minimum_os.bzl | 4 ++++ 6 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 minimum_os.bzl diff --git a/connections/clients/ios/BUILD b/connections/clients/ios/BUILD index 4cfda8db..b30e5c98 100644 --- a/connections/clients/ios/BUILD +++ b/connections/clients/ios/BUILD @@ -16,6 +16,7 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS", "IOS_MINIMUM_TEST_RUNNER") licenses(["notice"]) @@ -71,8 +72,8 @@ swift_library( ios_unit_test( name = "BuildTests", - minimum_os_version = "15.0", - runner = "//testing/utp/ios:IOS_LATEST", + minimum_os_version = IOS_MINIMUM_OS, + runner = IOS_MINIMUM_TEST_RUNNER, deps = [ ":BuildTestsLib", ], diff --git a/connections/swift/NearbyConnections/BUILD b/connections/swift/NearbyConnections/BUILD index 88c3f7fe..d828eebf 100644 --- a/connections/swift/NearbyConnections/BUILD +++ b/connections/swift/NearbyConnections/BUILD @@ -14,6 +14,7 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS", "IOS_MINIMUM_TEST_RUNNER") licenses(["notice"]) @@ -41,8 +42,8 @@ swift_library( ios_unit_test( name = "Tests", - minimum_os_version = "15.0", - runner = "//testing/utp/ios:IOS_LATEST", + minimum_os_version = IOS_MINIMUM_OS, + runner = IOS_MINIMUM_TEST_RUNNER, deps = [ ":TestsLib", ], diff --git a/connections/swift/NearbyCoreAdapter/BUILD b/connections/swift/NearbyCoreAdapter/BUILD index 560f1c9a..5aebee41 100644 --- a/connections/swift/NearbyCoreAdapter/BUILD +++ b/connections/swift/NearbyCoreAdapter/BUILD @@ -14,6 +14,7 @@ load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") load("//tools/build_defs/swift:swift_library.bzl", "swift_library") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS", "IOS_MINIMUM_TEST_RUNNER") licenses(["notice"]) @@ -52,8 +53,8 @@ swift_library( ios_unit_test( name = "Tests", - minimum_os_version = "15.0", - runner = "//testing/utp/ios:IOS_LATEST", + minimum_os_version = IOS_MINIMUM_OS, + runner = IOS_MINIMUM_TEST_RUNNER, deps = [ ":TestsLib", ], diff --git a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD index 021d194e..169c2f67 100644 --- a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD +++ b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD @@ -13,6 +13,7 @@ # limitations under the License. load("//tools/build_defs/swift:swift_explicit_module_build_test.bzl", "swift_explicit_module_build_test") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) @@ -87,6 +88,6 @@ objc_library( swift_explicit_module_build_test( name = "swift_explicit_module_build_test", ignore_headerless_targets = True, - minimum_os_version = "15.0", + minimum_os_version = IOS_MINIMUM_OS, platform_type = "ios", ) diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index 5a1fdf52..21c91daf 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -13,6 +13,7 @@ # limitations under the License. load("//tools/build_defs/apple:ios.bzl", "ios_unit_test") +load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS", "IOS_MINIMUM_TEST_RUNNER") licenses(["notice"]) @@ -40,8 +41,8 @@ objc_library( ios_unit_test( name = "PlatformTests", - minimum_os_version = "15.0", - runner = "//testing/utp/ios:IOS_LATEST", + minimum_os_version = IOS_MINIMUM_OS, + runner = IOS_MINIMUM_TEST_RUNNER, deps = [ ":PlatformTestslib", ], diff --git a/minimum_os.bzl b/minimum_os.bzl new file mode 100644 index 00000000..c51a86e2 --- /dev/null +++ b/minimum_os.bzl @@ -0,0 +1,4 @@ +"""Minimum OS version definitions and related test setup""" + +IOS_MINIMUM_OS = "13.7" +IOS_MINIMUM_TEST_RUNNER = "//testing/utp/ios:IPHONE_6S_13_7" From 37000006c224476104276bf74038d60967593814 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Thu, 27 Apr 2023 20:35:03 -0700 Subject: [PATCH 47/63] Fix callback scope issue PiperOrigin-RevId: 527764249 --- fastpair/handshake/fast_pair_data_encryptor_impl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fastpair/handshake/fast_pair_data_encryptor_impl.cc b/fastpair/handshake/fast_pair_data_encryptor_impl.cc index 6f9eba7a..17c5d745 100644 --- a/fastpair/handshake/fast_pair_data_encryptor_impl.cc +++ b/fastpair/handshake/fast_pair_data_encryptor_impl.cc @@ -88,7 +88,8 @@ void FastPairDataEncryptorImpl::Factory::CreateAsyncWithKeyExchange( NEARBY_LOGS(INFO) << __func__ << ": Attempting to get device metadata."; FastPairRepository::Get()->GetDeviceMetadata( device.GetModelId(), - [&on_get_instance_callback](DeviceMetadata& metadata) { + [on_get_instance_callback = std::move(on_get_instance_callback)]( + DeviceMetadata& metadata) mutable { FastPairDataEncryptorImpl::Factory::DeviceMetadataRetrieved( std::move(on_get_instance_callback), metadata); }); From 05cd950539ac475210e23a5806d3eb40338efa47 Mon Sep 17 00:00:00 2001 From: Janusz Sobczak Date: Fri, 28 Apr 2023 12:37:16 -0700 Subject: [PATCH 48/63] Add read,write callbacks to characteristics During Fast pair handshake, the seeker writes to GATT characteristics, the provider reads the value and sends the response. We need callbacks for reading and writing GATT characteristics to test the handshake. Static GATT DB entries are not sufficient. PiperOrigin-RevId: 527958868 --- internal/platform/ble_v2.cc | 23 ++++++++++++++++++++ internal/platform/ble_v2.h | 26 +++++++++++++++++------ internal/platform/implementation/ble_v2.h | 22 +++++++++++++++++++ 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/internal/platform/ble_v2.cc b/internal/platform/ble_v2.cc index 584062d3..d6b5bff5 100644 --- a/internal/platform/ble_v2.cc +++ b/internal/platform/ble_v2.cc @@ -26,9 +26,15 @@ namespace nearby { +namespace { using ::nearby::api::ble_v2::BleAdvertisementData; using ::nearby::api::ble_v2::GattCharacteristic; using ::nearby::api::ble_v2::TxPowerLevel; +using ReadValueCallback = + ::nearby::api::ble_v2::ServerGattConnectionCallback::ReadValueCallback; +using WriteValueCallback = + ::nearby::api::ble_v2::ServerGattConnectionCallback::WriteValueCallback; +} // namespace bool BleV2Medium::StartAdvertising( const BleAdvertisementData& advertising_data, @@ -205,6 +211,23 @@ std::unique_ptr BleV2Medium::StartGattServer( server_gatt_connection_callback_ .characteristic_unsubscription_cb(characteristic); }, + .on_characteristic_read_cb = + [this](const api::ble_v2::BlePeripheral& remote_device, + const GattCharacteristic& characteristic, int offset, + ReadValueCallback callback) { + MutexLock lock(&mutex_); + server_gatt_connection_callback_.on_characteristic_read_cb( + remote_device, characteristic, offset, std::move(callback)); + }, + .on_characteristic_write_cb = + [this](const api::ble_v2::BlePeripheral& remote_device, + const GattCharacteristic& characteristic, int offset, + absl::string_view data, WriteValueCallback callback) { + MutexLock lock(&mutex_); + server_gatt_connection_callback_.on_characteristic_write_cb( + remote_device, characteristic, offset, data, + std::move(callback)); + }, }); return std::make_unique(std::move(api_gatt_server)); } diff --git a/internal/platform/ble_v2.h b/internal/platform/ble_v2.h index 8feca81c..dfdcb1ef 100644 --- a/internal/platform/ble_v2.h +++ b/internal/platform/ble_v2.h @@ -276,14 +276,28 @@ class BleV2Medium final { const api::ble_v2::BleAdvertisementData&>(); }; struct ServerGattConnectionCallback { - absl::AnyInvocable + using BlePeripheral = api::ble_v2::BlePeripheral; + using GattCharacteristic = api::ble_v2::GattCharacteristic; + using ReadValueCallback = + api::ble_v2::ServerGattConnectionCallback::ReadValueCallback; + using WriteValueCallback = + api::ble_v2::ServerGattConnectionCallback::WriteValueCallback; + + absl::AnyInvocable characteristic_subscription_cb = - nearby::DefaultCallback(); - absl::AnyInvocable + nearby::DefaultCallback(); + absl::AnyInvocable characteristic_unsubscription_cb = - nearby::DefaultCallback(); + nearby::DefaultCallback(); + absl::AnyInvocable + on_characteristic_read_cb; + absl::AnyInvocable + on_characteristic_write_cb; }; // TODO(b/231318879): Remove this wrapper callback and use impl callback if // there is only disconnect function here in the end. diff --git a/internal/platform/implementation/ble_v2.h b/internal/platform/implementation/ble_v2.h index b2aaefea..8dd5ad50 100644 --- a/internal/platform/implementation/ble_v2.h +++ b/internal/platform/implementation/ble_v2.h @@ -27,6 +27,7 @@ #include "absl/container/flat_hash_map.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/byte_array.h" #include "internal/platform/cancellation_flag.h" @@ -284,6 +285,9 @@ struct ClientGattConnectionCallback { // Callback for asynchronous events on the server side of a GATT connection. struct ServerGattConnectionCallback { + using ReadValueCallback = + absl::AnyInvocable data)>; + using WriteValueCallback = absl::AnyInvocable; // Called when a remote peripheral connected to us and subscribed to one of // our characteristics. absl::AnyInvocable @@ -293,6 +297,24 @@ struct ServerGattConnectionCallback { // characteristics. absl::AnyInvocable characteristic_unsubscription_cb; + + // Called when a gatt client is reading from the characteristic. + // Must call `callback` with the read result. + // When a characteristic has a static value set with + // `GattServer::UpdateCharacteristic()`, then reading from the characteristic + // yields that static value. The read callback is not called. + // Otherwise, the gatt server calls the read callback to get the value. + absl::AnyInvocable + on_characteristic_read_cb; + + // Called when a gatt client is writing to the characteristic. + // Must call `callback` with the write result. + absl::AnyInvocable + on_characteristic_write_cb; }; // A BLE GATT client socket for requesting GATT socket. From 10174f8a47fd998bdf0219badb1ee7a89aab6718 Mon Sep 17 00:00:00 2001 From: hai007 Date: Fri, 28 Apr 2023 17:15:50 -0700 Subject: [PATCH 49/63] Fix data overflow problem PiperOrigin-RevId: 528023236 --- connections/implementation/p2p_cluster_pcp_handler_test.cc | 3 ++- .../implementation/p2p_point_to_point_pcp_handler_test.cc | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/connections/implementation/p2p_cluster_pcp_handler_test.cc b/connections/implementation/p2p_cluster_pcp_handler_test.cc index 1b93c9cb..3de5438f 100644 --- a/connections/implementation/p2p_cluster_pcp_handler_test.cc +++ b/connections/implementation/p2p_cluster_pcp_handler_test.cc @@ -268,11 +268,12 @@ TEST_P(P2pClusterPcpHandlerTest, CanConnect) { const std::string kBssid = "34:36:3B:C7:8C:71"; const std::int32_t kFreq = 5200; - constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37}; + constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37, 0}; connection_options_.connection_info.supports_5_ghz = true; connection_options_.connection_info.bssid = kBssid; connection_options_.connection_info.ap_frequency = kFreq; + connection_options_.connection_info.ip_address.resize(4); connection_options_.connection_info.ip_address = std::string(kIp4Bytes); client_b_.AddCancellationFlag(discovered.endpoint_id); diff --git a/connections/implementation/p2p_point_to_point_pcp_handler_test.cc b/connections/implementation/p2p_point_to_point_pcp_handler_test.cc index 5eab2d1c..65d16f09 100644 --- a/connections/implementation/p2p_point_to_point_pcp_handler_test.cc +++ b/connections/implementation/p2p_point_to_point_pcp_handler_test.cc @@ -207,11 +207,12 @@ TEST_P(P2pPointToPointPcpHandlerTest, CanConnect) { const std::string kBssid = "34:36:3B:C7:8C:71"; const std::int32_t kFreq = 5200; - constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37}; + constexpr char kIp4Bytes[] = {(char)192, (char)168, (char)1, (char)37, 0}; connection_options_.connection_info.supports_5_ghz = true; connection_options_.connection_info.bssid = kBssid; connection_options_.connection_info.ap_frequency = kFreq; + connection_options_.connection_info.ip_address.resize(4); connection_options_.connection_info.ip_address = std::string(kIp4Bytes); client_b_.AddCancellationFlag(discovered.endpoint_id); From 46e4b3eca7cfca75fbbbf85d88a2f8e939978edd Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Fri, 28 Apr 2023 22:24:01 -0700 Subject: [PATCH 50/63] Fixed a data race bug in test codes PiperOrigin-RevId: 528074883 --- internal/test/fake_clock.cc | 5 +++++ internal/test/fake_clock.h | 1 + 2 files changed, 6 insertions(+) diff --git a/internal/test/fake_clock.cc b/internal/test/fake_clock.cc index 57c6b29d..3f464ea6 100644 --- a/internal/test/fake_clock.cc +++ b/internal/test/fake_clock.cc @@ -21,6 +21,11 @@ namespace nearby { +FakeClock::~FakeClock() { + absl::MutexLock lock(&mutex_); + observers_.clear(); +} + absl::Time FakeClock::Now() const { absl::MutexLock lock(&mutex_); return now_; diff --git a/internal/test/fake_clock.h b/internal/test/fake_clock.h index 7cef161a..8c077e18 100644 --- a/internal/test/fake_clock.h +++ b/internal/test/fake_clock.h @@ -33,6 +33,7 @@ class FakeClock : public Clock { FakeClock() { now_ = absl::Now(); } FakeClock(FakeClock&&) = default; FakeClock& operator=(FakeClock&&) = default; + ~FakeClock() override ABSL_LOCKS_EXCLUDED(mutex_); absl::Time Now() const override; From e46bfb52d0fabad2e1604e688c8afdb0e5787a64 Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Mon, 1 May 2023 10:35:34 -0700 Subject: [PATCH 51/63] Define BluetoothPairing API for Nearby Platform Library and add implementation on Windows platform PiperOrigin-RevId: 528510444 --- internal/platform/bluetooth_classic.h | 42 +++ .../implementation/bluetooth_classic.h | 110 ++++++ .../implementation/g3/bluetooth_classic.cc | 6 + .../implementation/g3/bluetooth_classic.h | 5 + .../windows/bluetooth_classic_medium.cc | 35 +- .../windows/bluetooth_classic_medium.h | 5 + .../windows/bluetooth_pairing.cc | 344 ++++++++++++++---- .../windows/bluetooth_pairing.h | 35 +- 8 files changed, 508 insertions(+), 74 deletions(-) diff --git a/internal/platform/bluetooth_classic.h b/internal/platform/bluetooth_classic.h index 319d14f5..eee85f8c 100644 --- a/internal/platform/bluetooth_classic.h +++ b/internal/platform/bluetooth_classic.h @@ -16,7 +16,9 @@ #define PLATFORM_PUBLIC_BLUETOOTH_CLASSIC_H_ #include +#include #include +#include #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" @@ -126,6 +128,36 @@ class BluetoothServerSocket final { std::shared_ptr impl_; }; +// Opaque wrapper for a BluetoothPairing. +class BluetoothPairing final { + public: + explicit BluetoothPairing( + std::unique_ptr bluetooth_pairing) + : impl_(std::move(bluetooth_pairing)) {} + + bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) { + return impl_->InitiatePairing(std::move(pairing_cb)); + } + + bool FinishPairing(std::optional pin_code) { + return impl_->FinishPairing(pin_code); + } + + bool CancelPairing() { return impl_->CancelPairing(); } + + bool Unpair() { return impl_->Unpair(); } + + bool IsPaired() { return impl_->IsPaired(); } + + // Returns reference to platform implementation. + // This is used to communicate with platform code, and for debugging + // purposes. + api::BluetoothPairing* GetImpl() { return impl_.get(); } + + private: + std::unique_ptr impl_; +}; + // Container of operations that can be performed over the Bluetooth Classic // medium. class BluetoothClassicMedium final @@ -147,6 +179,7 @@ class BluetoothClassicMedium final absl::AnyInvocable device_lost_cb = DefaultCallback(); }; + struct DeviceDiscoveryInfo { BluetoothDevice device; }; @@ -239,6 +272,15 @@ class BluetoothClassicMedium final impl_->ListenForService(service_name, service_uuid)); } + // Return a Bluetooth pairing instance to handle the pairing process with the + // remote device. + std::unique_ptr CreatePairing( + BluetoothDevice& remote_device) { + std::unique_ptr bluetooth_pairing = + impl_->CreatePairing(remote_device.GetImpl()); + return std::make_unique(std::move(bluetooth_pairing)); + } + bool IsValid() const { return impl_ != nullptr; } api::BluetoothClassicMedium& GetImpl() { return *impl_; } diff --git a/internal/platform/implementation/bluetooth_classic.h b/internal/platform/implementation/bluetooth_classic.h index 7f8f9cf3..ae8da9f7 100644 --- a/internal/platform/implementation/bluetooth_classic.h +++ b/internal/platform/implementation/bluetooth_classic.h @@ -16,8 +16,11 @@ #define PLATFORM_API_BLUETOOTH_CLASSIC_H_ #include +#include #include +#include "absl/functional/any_invocable.h" +#include "absl/strings/string_view.h" #include "internal/platform/byte_array.h" #include "internal/platform/cancellation_flag.h" #include "internal/platform/exception.h" @@ -89,6 +92,105 @@ class BluetoothServerSocket { virtual Exception Close() = 0; }; +// https://developer.android.com/reference/com/google/android/things/bluetooth/PairingParams +// +// Encapsulates the data for a particular pairing attempt. +// The caller can use it to determine the pairing approach and choose a suitable +// way to obtain user consent to conclude the pairing process. +struct PairingParams { + // Pairing type for this pairing attempt. + // The Pairing type is based on the User Interface capabilities of both + // the pairing devices, and determines the process of pairing. + // `kConstent`: the user is expected to consent to the pairing process. + // `kDisplayPasskey`: the user is notified of a pairing passkey. + // `kDisplayPin`: same as kDisplayPasskey, but different pairing key format. + // `kConfirmPasskey`: the user must confirm pairing after verifying a passkey. + // `kRequestPin`: the user is supposed to enter a pin to confirm pairing. + enum class PairingType { + kUnknown = 0, + kConsent = 1, + kDisplayPasskey = 2, + kDisplayPin = 3, + kConfirmPasskey = 4, + kRequestPin = 5, + kLast, + }; + PairingType pairing_type; + + // Pairing pin to notify the user for the pairing process. + // If not relevant to the current pairing process, it's empty. + std::string passkey; +}; + +// https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothPairingCallback +// +// This callback is invoked during the Bluetooth pairing process and +// contains all the relevant pairing information required for pairing. +struct BluetoothPairingCallback { + // https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothPairingCallback.PairingError + enum class PairingError { + kUnknown = 0, + kAuthCanceled = 1, /* failed because we canceled the pairing process. */ + kAuthFailed = 2, /* failed with pins did not match, or no response. */ + kAuthRejected = 3, /* failed with the remote device rejected pairing. */ + kAuthTimeout = 4, /* failed with authentication timeout. */ + kFailed = 5, /* failed with no explicit reason. */ + kRepeatedAttempts = 6, /* failed with many repeated attempts. */ + kLast, + }; + + // Invoked when successfully paired with a device. + absl::AnyInvocable on_paired_cb = DefaultCallback<>(); + + // Invoked when pairing with a device is canceled or fails. + absl::AnyInvocable + on_pairing_error_cb = + DefaultCallback(); + + // Invoked when the pairing process has been initiated with a remote + // Bluetooth device. + absl::AnyInvocable + on_pairing_initiated_cb = DefaultCallback(); +}; + +// This class is responsible for handling Bluetooth pairing with a remote +// BluetoothDevice. +// DCHECK_CALLED_ON_VALID_SEQUENCE +class BluetoothPairing { + public: + virtual ~BluetoothPairing() = default; + + // https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#initiatepairing + // https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#registerpairingcallback + // + // Initiate Bluetooth pairing process with a remote device. + // Register a BluetoothPairingCallback to listen for Bluetooth pairing events + // Such as incoming pairing request, devices paired etc. + virtual bool InitiatePairing(BluetoothPairingCallback pairing_cb) = 0; + + // https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#finishpairing + // + // Invoke this function to finish the pairing process with the remote device. + // Should be called only after receiving a callback from onPairingInitiated. + // Pin is needed for PairingType::kRequestPin + virtual bool FinishPairing(std::optional pin_code) = 0; + + // https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#cancelpairing + // + // Cancel an ongoing pairing process with a remote device. + virtual bool CancelPairing() = 0; + + // https://developer.android.com/reference/com/google/android/things/bluetooth/BluetoothConnectionManager#unpair + // + // Destroys the existing pairing/bond with the remote device. + virtual bool Unpair() = 0; + + // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getBondState() + // + // Get the pairing state of the remote device. + virtual bool IsPaired() = 0; +}; + // Container of operations that can be performed over the Bluetooth Classic // medium. class BluetoothClassicMedium { @@ -174,6 +276,14 @@ class BluetoothClassicMedium { virtual std::unique_ptr ListenForService( const std::string& service_name, const std::string& service_uuid) = 0; + // https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createBond() + // + // Start the bonding (pairing) process with the remote device. + // Return a Bluetooth pairing instance to handle the pairing process with the + // remote device. + virtual std::unique_ptr CreatePairing( + BluetoothDevice& remote_device) = 0; + virtual BluetoothDevice* GetRemoteDevice(const std::string& mac_address) = 0; virtual void AddObserver(Observer* observer) = 0; diff --git a/internal/platform/implementation/g3/bluetooth_classic.cc b/internal/platform/implementation/g3/bluetooth_classic.cc index b8544aba..b7732b5e 100644 --- a/internal/platform/implementation/g3/bluetooth_classic.cc +++ b/internal/platform/implementation/g3/bluetooth_classic.cc @@ -271,6 +271,12 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name, return socket; } +std::unique_ptr BluetoothClassicMedium::CreatePairing( + api::BluetoothDevice& remote_device) { + // TODO(b/279964840): Add g3 implementation for BluetoothPairing. + return nullptr; +} + api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice( const std::string& mac_address) { auto& env = MediumEnvironment::Instance(); diff --git a/internal/platform/implementation/g3/bluetooth_classic.h b/internal/platform/implementation/g3/bluetooth_classic.h index 1db7af17..966615cd 100644 --- a/internal/platform/implementation/g3/bluetooth_classic.h +++ b/internal/platform/implementation/g3/bluetooth_classic.h @@ -233,6 +233,11 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { const std::string& service_name, const std::string& service_uuid) override ABSL_LOCKS_EXCLUDED(mutex_); + // Return a Bluetooth pairing instance to handle the pairing process with the + // remote device. + std::unique_ptr CreatePairing( + api::BluetoothDevice& remote_device) override; + api::BluetoothDevice* GetRemoteDevice( const std::string& mac_address) override; diff --git a/internal/platform/implementation/windows/bluetooth_classic_medium.cc b/internal/platform/implementation/windows/bluetooth_classic_medium.cc index 563df49c..6f914208 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_medium.cc +++ b/internal/platform/implementation/windows/bluetooth_classic_medium.cc @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -29,10 +30,12 @@ #include "internal/platform/cancellation_flag.h" #include "internal/platform/cancellation_flag_listener.h" #include "internal/platform/exception.h" +#include "internal/platform/implementation/bluetooth_classic.h" #include "internal/platform/implementation/windows/bluetooth_adapter.h" #include "internal/platform/implementation/windows/bluetooth_classic_device.h" #include "internal/platform/implementation/windows/bluetooth_classic_server_socket.h" #include "internal/platform/implementation/windows/bluetooth_classic_socket.h" +#include "internal/platform/implementation/windows/bluetooth_pairing.h" #include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h" #include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.h" #include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Enumeration.h" @@ -45,7 +48,6 @@ namespace nearby { namespace windows { namespace { - using winrt::Windows::Foundation::IInspectable; using winrt::Windows::Foundation::Collections::IMapView; @@ -336,6 +338,37 @@ std::unique_ptr BluetoothClassicMedium::ConnectToService( } } +std::unique_ptr BluetoothClassicMedium::CreatePairing( + api::BluetoothDevice& remote_device) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Start to createPairing with device: " + << remote_device.GetMacAddress(); + try { + winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device = + winrt::Windows::Devices::Bluetooth::BluetoothDevice:: + FromBluetoothAddressAsync( + mac_address_string_to_uint64(remote_device.GetMacAddress())) + .get(); + winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing + custom_pairing = + bluetooth_device.DeviceInformation().Pairing().Custom(); + if (custom_pairing) { + return std::make_unique(bluetooth_device, + custom_pairing); + } + NEARBY_LOGS(VERBOSE) << __func__ + << ": Failed to get DeviceInformationCustomPairing."; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ << " : Failed to create pairing. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to create pairing. WinRT exception: " + << error.code() << ": " + << winrt::to_string(error.message()); + } + return nullptr; +} + bool BluetoothClassicMedium::HaveAccess(winrt::hstring device_id) { if (device_id.empty()) { return false; diff --git a/internal/platform/implementation/windows/bluetooth_classic_medium.h b/internal/platform/implementation/windows/bluetooth_classic_medium.h index 40d1f933..bfaa00a6 100644 --- a/internal/platform/implementation/windows/bluetooth_classic_medium.h +++ b/internal/platform/implementation/windows/bluetooth_classic_medium.h @@ -146,6 +146,11 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium { api::BluetoothDevice* GetRemoteDevice( const std::string& mac_address) override; + // Return a Bluetooth pairing instance to handle the pairing process with the + // remote device. + std::unique_ptr CreatePairing( + api::BluetoothDevice& remote_device) override; + void AddObserver(Observer* observer) override { // TODO(b/269521993): Implement. } diff --git a/internal/platform/implementation/windows/bluetooth_pairing.cc b/internal/platform/implementation/windows/bluetooth_pairing.cc index f038fa4d..f43d1193 100644 --- a/internal/platform/implementation/windows/bluetooth_pairing.cc +++ b/internal/platform/implementation/windows/bluetooth_pairing.cc @@ -14,7 +14,20 @@ #include "internal/platform/implementation/windows/bluetooth_pairing.h" +#include + +#include +#include +#include +#include + +#include "absl/log/check.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "internal/platform/implementation/windows/generated/winrt/impl/Windows.Devices.Enumeration.0.h" #include "internal/platform/logging.h" +#include "winrt/Windows.Devices.Bluetooth.h" #include "winrt/Windows.Devices.Enumeration.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/base.h" @@ -23,93 +36,294 @@ namespace nearby { namespace windows { namespace { +using ::winrt::Windows::Devices::Bluetooth::BluetoothDevice; using ::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing; using ::winrt::Windows::Devices::Enumeration::DevicePairingKinds; using ::winrt::Windows::Devices::Enumeration::DevicePairingProtectionLevel; using ::winrt::Windows::Devices::Enumeration::DevicePairingRequestedEventArgs; using ::winrt::Windows::Devices::Enumeration::DevicePairingResult; using ::winrt::Windows::Devices::Enumeration::DevicePairingResultStatus; +using ::winrt::Windows::Devices::Enumeration::DeviceUnpairingResult; +using ::winrt::Windows::Devices::Enumeration::DeviceUnpairingResultStatus; using ::winrt::Windows::Foundation::IAsyncOperation; +using PairingError = ::nearby::api::BluetoothPairingCallback::PairingError; +using PairingType = ::nearby::api::PairingParams::PairingType; } // namespace BluetoothPairing::BluetoothPairing( - DeviceInformationCustomPairing& custom_pairing) - : custom_pairing_(custom_pairing) {} + BluetoothDevice bluetooth_device, + DeviceInformationCustomPairing custom_pairing) + : bluetooth_device_(bluetooth_device), custom_pairing_(custom_pairing) { + NEARBY_LOGS(VERBOSE) << __func__ + << ": BluetoothPairing is created for device."; +} -BluetoothPairing::~BluetoothPairing() = default; - -void BluetoothPairing::StartPairing() { - NEARBY_LOGS(VERBOSE) << "Bluetooth_pairing start pairing"; - pairing_requested_token_ = custom_pairing_.PairingRequested( - {this, &BluetoothPairing::OnPairingRequested}); - IAsyncOperation pairing_operation = - custom_pairing_.PairAsync(DevicePairingKinds::ConfirmOnly | - DevicePairingKinds::ProvidePin | - DevicePairingKinds::ConfirmPinMatch, - DevicePairingProtectionLevel::None); - DevicePairingResult pairing_result = pairing_operation.get(); - if (pairing_result != nullptr) { - OnPair(pairing_result); +BluetoothPairing::~BluetoothPairing() { + if (pairing_requested_token_) { + custom_pairing_.PairingRequested( + std::exchange(pairing_requested_token_, {})); } + CancelPairing(); + NEARBY_LOGS(VERBOSE) << __func__ + << ": BluetoothPairing is destroyed for device."; +} + +bool BluetoothPairing::InitiatePairing( + api::BluetoothPairingCallback pairing_cb) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Start to initiate pairing process."; + try { + pairing_requested_token_ = custom_pairing_.PairingRequested( + {this, &BluetoothPairing::OnPairingRequested}); + if (!pairing_requested_token_) { + NEARBY_LOGS(VERBOSE) << __func__ + << " Failed to registered pairing callback."; + return false; + } + pairing_callback_ = std::move(pairing_cb); + DevicePairingResult pairing_result = + custom_pairing_ + .PairAsync(DevicePairingKinds::ConfirmOnly | + DevicePairingKinds::ProvidePin | + DevicePairingKinds::ConfirmPinMatch | + DevicePairingKinds::DisplayPin, + DevicePairingProtectionLevel::None) + .get(); + OnPair(pairing_result); + return true; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to initiate pairing. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to initiate pairing. WinRT exception: " + << error.code() << ": " + << winrt::to_string(error.message()); + } + return false; +} + +bool BluetoothPairing::FinishPairing( + std::optional pin_code) { + NEARBY_LOGS(VERBOSE) << __func__ << "Start to finish pairing."; + try { + if (!pairing_requested_) { + NEARBY_LOGS(VERBOSE) << __func__ << "No pairing requested."; + return false; + } + if (!pairing_deferral_) { + NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process."; + return false; + } + if (expecting_pin_code_) { + if (!pin_code.has_value()) { + NEARBY_LOGS(INFO) << __func__ << " Failed to get pin code"; + return false; + } + expecting_pin_code_ = false; + auto pin_hstring = winrt::to_hstring(std::string(pin_code.value())); + pairing_requested_.Accept(pin_hstring); + } else { + pairing_requested_.Accept(); + } + pairing_deferral_.Complete(); + NEARBY_LOGS(VERBOSE) << "Successfully finished pairing."; + return true; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ << ": Failed to finish pairing. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to finish pairing. WinRT exception: " + << error.code() << ": " + << winrt::to_string(error.message()); + } + return false; +} + +bool BluetoothPairing::CancelPairing() { + NEARBY_LOGS(VERBOSE) << __func__ + << "Start to cancel ongoing pairing process."; + try { + if (!pairing_deferral_) { + NEARBY_LOGS(VERBOSE) << __func__ << "No ongoing pairing process."; + return true; + } + // There is no way to explicitly cancel an in-progress pairing on Windows as + // DevicePairingRequestedEventArgs has no Cancel() method. + // Our approach is to complete the deferral, without accepting, + // which results in a RejectedByHandler result status. + // |was_cancelled_| is set so that OnPair(), which is called when the + // deferral is completed, will know that cancellation was the actual result. + was_cancelled_ = true; + pairing_deferral_.Complete(); + NEARBY_LOGS(VERBOSE) << __func__ << "Canceled ongoing pairing process."; + return true; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ << ": Failed to cancel ongoing pairing " + << "process. exception: " << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to cancel ongoing pairing process. " + << "WinRT exception: " << error.code() << ": " + << winrt::to_string(error.message()); + } + return false; +} + +bool BluetoothPairing::Unpair() { + NEARBY_LOGS(VERBOSE) << __func__ << ": Start to unpair with remote device."; + try { + if (!IsPaired()) { + NEARBY_LOGS(VERBOSE) << __func__ << " : Remote device Was not paired."; + return true; + } + DeviceUnpairingResult unpairing_result = + bluetooth_device_.DeviceInformation().Pairing().UnpairAsync().get(); + if (unpairing_result.Status() == DeviceUnpairingResultStatus::Unpaired) { + NEARBY_LOGS(VERBOSE) << __func__ << ": Unpaired with remote device."; + return true; + } + NEARBY_LOGS(VERBOSE) << __func__ + << ": Failed to unpaired with remote device."; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to unpaired with device. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to unpaired with device. WinRT exception: " + << error.code() << ": " + << winrt::to_string(error.message()); + } + return false; +} + +bool BluetoothPairing::IsPaired() { + try { + bool is_paired = bluetooth_device_.DeviceInformation().Pairing().IsPaired(); + NEARBY_LOGS(INFO) << __func__ << (is_paired ? "True" : "False"); + return is_paired; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ << ": Failed to get IsPaired. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to get IsPaired. WinRT exception: " + << error.code() << ": " + << winrt::to_string(error.message()); + } + return false; } void BluetoothPairing::OnPairingRequested( DeviceInformationCustomPairing custom_pairing, DevicePairingRequestedEventArgs pairing_requested) { - NEARBY_LOGS(INFO) << "BluetoothPairing::OnPairingRequested()"; - DevicePairingKinds pairing_kind = pairing_requested.PairingKind(); - switch (pairing_kind) { - case DevicePairingKinds::ProvidePin: - NEARBY_LOGS(INFO) << "DevicePairingKind: RequestPinCode."; - pairing_requested.Accept(); - return; - case DevicePairingKinds::ConfirmOnly: - NEARBY_LOGS(INFO) << "DevicePairingKind: ConfirmOnly."; - pairing_requested.Accept(); - break; - case DevicePairingKinds::ConfirmPinMatch: - NEARBY_LOGS(INFO) << "DevicePairingKind: Confirm Pin Match: " - << pairing_requested.Pin().c_str(); - pairing_requested.Accept(); - break; - default: - NEARBY_LOGS(INFO) << "Unsupported DevicePairingKind = " - << static_cast(pairing_kind); - break; + NEARBY_LOGS(VERBOSE) << __func__ << "Requested to pair."; + try { + DevicePairingKinds pairing_kind = pairing_requested.PairingKind(); + pairing_requested_ = pairing_requested; + pairing_deferral_ = pairing_requested.GetDeferral(); + api::PairingParams params; + switch (pairing_kind) { + case DevicePairingKinds::ProvidePin: + NEARBY_LOGS(INFO) << __func__ << "DevicePairingKind: RequestPinCode."; + expecting_pin_code_ = true; + params.pairing_type = PairingType::kRequestPin; + pairing_callback_.on_pairing_initiated_cb(params); + return; + case DevicePairingKinds::ConfirmOnly: + NEARBY_LOGS(INFO) << __func__ << "DevicePairingKind: ConfirmOnly."; + params.pairing_type = PairingType::kConsent; + pairing_callback_.on_pairing_initiated_cb(params); + return; + case DevicePairingKinds::ConfirmPinMatch: + NEARBY_LOGS(INFO) << __func__ + << "DevicePairingKind: Confirm Pin Match."; + params.pairing_type = PairingType::kConfirmPasskey; + params.passkey = winrt::to_string(pairing_requested.Pin()); + pairing_callback_.on_pairing_initiated_cb(params); + return; + default: + params.pairing_type = PairingType::kUnknown; + NEARBY_LOGS(INFO) << __func__ << "Unsupported DevicePairingKind:" + << static_cast(pairing_kind); + break; + } + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to request to pair with device. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) + << __func__ + << ": Failed to request to pair with device. WinRT exception: " + << error.code() << ": " << winrt::to_string(error.message()); } + pairing_callback_.on_pairing_error_cb(PairingError::kFailed); } void BluetoothPairing::OnPair(DevicePairingResult& pairing_result) { - DevicePairingResultStatus status = pairing_result.Status(); - - switch (status) { - case DevicePairingResultStatus::AlreadyPaired: - case DevicePairingResultStatus::Paired: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Paired."; - return; - case DevicePairingResultStatus::PairingCanceled: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Pairing Canceled."; - return; - case DevicePairingResultStatus::AuthenticationFailure: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Authentication Failure."; - return; - case DevicePairingResultStatus::ConnectionRejected: - case DevicePairingResultStatus::RejectedByHandler: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Authentication Rejected."; - return; - case DevicePairingResultStatus::AuthenticationTimeout: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Authentication Timeout."; - return; - case DevicePairingResultStatus::Failed: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Failed."; - return; - case DevicePairingResultStatus::OperationAlreadyInProgress: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Operatio In Progress."; - return; - default: - NEARBY_LOGS(ERROR) << "Pairing Result Status: Failed."; - return; + try { + DevicePairingResultStatus status = pairing_result.Status(); + NEARBY_LOGS(INFO) << __func__ + << "Pairing Result Status: " << static_cast(status); + if (was_cancelled_ && + status == DevicePairingResultStatus::RejectedByHandler) { + // See comment in CancelPairing() for explanation of why was_cancelled_ + // is used. + status = DevicePairingResultStatus::PairingCanceled; + } + switch (status) { + case DevicePairingResultStatus::AlreadyPaired: + case DevicePairingResultStatus::Paired: + NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Paired."; + pairing_callback_.on_paired_cb(); + return; + case DevicePairingResultStatus::PairingCanceled: + NEARBY_LOGS(ERROR) << __func__ + << "Pairing Result Status: Pairing Canceled."; + pairing_callback_.on_pairing_error_cb(PairingError::kAuthCanceled); + return; + case DevicePairingResultStatus::AuthenticationFailure: + NEARBY_LOGS(ERROR) << __func__ + << "Pairing Result Status: Authentication Failure."; + pairing_callback_.on_pairing_error_cb(PairingError::kAuthFailed); + return; + case DevicePairingResultStatus::ConnectionRejected: + case DevicePairingResultStatus::RejectedByHandler: + NEARBY_LOGS(ERROR) << __func__ + << "Pairing Result Status: Authentication Rejected."; + pairing_callback_.on_pairing_error_cb(PairingError::kAuthRejected); + return; + case DevicePairingResultStatus::AuthenticationTimeout: + NEARBY_LOGS(ERROR) << __func__ + << "Pairing Result Status: Authentication Timeout."; + pairing_callback_.on_pairing_error_cb(PairingError::kAuthTimeout); + return; + case DevicePairingResultStatus::Failed: + NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Failed."; + pairing_callback_.on_pairing_error_cb(PairingError::kFailed); + return; + case DevicePairingResultStatus::OperationAlreadyInProgress: + NEARBY_LOGS(ERROR) << __func__ + << "Pairing Result Status: Operation In Progress."; + pairing_callback_.on_pairing_error_cb(PairingError::kRepeatedAttempts); + return; + default: + break; + } + NEARBY_LOGS(ERROR) << __func__ << "Pairing Result Status: Failed."; + } catch (std::exception exception) { + NEARBY_LOGS(ERROR) << __func__ + << ": Failed to get Pairing Result Status. exception: " + << exception.what(); + } catch (const winrt::hresult_error& error) { + NEARBY_LOGS(ERROR) << __func__ << ": Failed to get Pairing Result Status." + << " WinRT exception: " << error.code() << ": " + << winrt::to_string(error.message()); } + pairing_callback_.on_pairing_error_cb(PairingError::kFailed); } } // namespace windows diff --git a/internal/platform/implementation/windows/bluetooth_pairing.h b/internal/platform/implementation/windows/bluetooth_pairing.h index 05cf5c75..4ffd8d04 100644 --- a/internal/platform/implementation/windows/bluetooth_pairing.h +++ b/internal/platform/implementation/windows/bluetooth_pairing.h @@ -15,27 +15,35 @@ #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLUETOOTH_PAIRING_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_BLUETOOTH_PAIRING_H_ -#include +#include -#include +#include +#include "absl/strings/string_view.h" +#include "internal/platform/implementation/bluetooth_classic.h" +#include "winrt/Windows.Devices.Bluetooth.h" #include "winrt/Windows.Devices.Enumeration.h" +#include "winrt/Windows.Foundation.Collections.h" +#include "winrt/base.h" namespace nearby { namespace windows { -class BluetoothPairing { +class BluetoothPairing : public api::BluetoothPairing { public: explicit BluetoothPairing( - ::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing& + ::winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device, + ::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing custom_pairing); BluetoothPairing(const BluetoothPairing&) = default; BluetoothPairing& operator=(const BluetoothPairing&) = default; + ~BluetoothPairing() override; - ~BluetoothPairing(); - - // Initiates the pairing procedure. - void StartPairing(); + bool InitiatePairing(api::BluetoothPairingCallback pairing_cb) override; + bool FinishPairing(std::optional pin_code) override; + bool CancelPairing() override; + bool Unpair() override; + bool IsPaired() override; private: void OnPairingRequested( @@ -48,9 +56,20 @@ class BluetoothPairing { pairing_result); // WinRT objects + ::winrt::Windows::Devices::Bluetooth::BluetoothDevice bluetooth_device_; ::winrt::Windows::Devices::Enumeration::DeviceInformationCustomPairing custom_pairing_; + ::winrt::event_token pairing_requested_token_; + ::winrt::Windows::Devices::Enumeration::DevicePairingRequestedEventArgs + pairing_requested_ = nullptr; + ::winrt::Windows::Foundation::Deferral pairing_deferral_ = nullptr; + api::BluetoothPairingCallback pairing_callback_; + + // Boolean indicating whether the device is currently pairing and expecting a + // PIN Code to be returned. + bool expecting_pin_code_ = false; + bool was_cancelled_ = false; }; } // namespace windows From 9f6e7f6b846899fad8f5541a67962c4a75f7e08d Mon Sep 17 00:00:00 2001 From: Qin Wang Date: Mon, 1 May 2023 10:40:28 -0700 Subject: [PATCH 52/63] Refactor Bluetooth Mediums PiperOrigin-RevId: 528511969 --- fastpair/dart/fast_pair_wrapper_impl.cc | 3 +- fastpair/dart/fast_pair_wrapper_impl_test.cc | 4 +- fastpair/handshake/BUILD | 6 +- .../fast_pair_gatt_service_client_impl.cc | 18 +- .../fast_pair_gatt_service_client_impl.h | 9 +- ...fast_pair_gatt_service_client_impl_test.cc | 5 +- .../handshake/fast_pair_handshake_impl.cc | 3 +- fastpair/handshake/fast_pair_handshake_impl.h | 4 +- .../fast_pair_handshake_impl_test.cc | 18 +- .../handshake/fast_pair_handshake_lookup.cc | 6 +- .../handshake/fast_pair_handshake_lookup.h | 3 +- .../fast_pair_handshake_lookup_test.cc | 7 +- fastpair/internal/{ble => mediums}/BUILD | 56 ++++++- fastpair/internal/{ble => mediums}/ble.cc | 89 +--------- fastpair/internal/{ble => mediums}/ble.h | 87 ++-------- .../internal/{ble => mediums}/ble_test.cc | 81 ++------- fastpair/internal/mediums/ble_v2.cc | 69 ++++++++ fastpair/internal/mediums/ble_v2.h | 56 +++++++ fastpair/internal/mediums/ble_v2_test.cc | 46 ++++++ fastpair/internal/mediums/bluetooth_radio.cc | 86 ++++++++++ fastpair/internal/mediums/bluetooth_radio.h | 79 +++++++++ .../internal/mediums/bluetooth_radio_test.cc | 48 ++++++ fastpair/internal/mediums/mediums.h | 56 +++++++ fastpair/internal/mediums/mediums_test.cc | 31 ++++ fastpair/keyed_service/fast_pair_mediator.cc | 4 +- fastpair/keyed_service/fast_pair_mediator.h | 4 +- fastpair/scanning/BUILD | 4 +- fastpair/scanning/fastpair/BUILD | 4 +- .../fastpair/fake_fast_pair_scanner.h | 1 + .../fast_pair_discoverable_scanner_impl.cc | 23 +-- .../fast_pair_discoverable_scanner_impl.h | 18 +- ...ast_pair_discoverable_scanner_impl_test.cc | 29 ++-- .../scanning/fastpair/fast_pair_scanner.h | 3 +- .../fastpair/fast_pair_scanner_impl.cc | 33 +--- .../fastpair/fast_pair_scanner_impl.h | 28 +--- .../fastpair/fast_pair_scanner_impl_test.cc | 155 +++++------------- fastpair/scanning/mock_scanner_broker.h | 4 +- fastpair/scanning/scanner_broker.h | 4 +- fastpair/scanning/scanner_broker_impl.cc | 17 +- fastpair/scanning/scanner_broker_impl.h | 14 +- fastpair/scanning/scanner_broker_impl_test.cc | 38 +++-- 41 files changed, 754 insertions(+), 499 deletions(-) rename fastpair/internal/{ble => mediums}/BUILD (55%) rename fastpair/internal/{ble => mediums}/ble.cc (64%) rename fastpair/internal/{ble => mediums}/ble.h (50%) rename fastpair/internal/{ble => mediums}/ble_test.cc (59%) create mode 100644 fastpair/internal/mediums/ble_v2.cc create mode 100644 fastpair/internal/mediums/ble_v2.h create mode 100644 fastpair/internal/mediums/ble_v2_test.cc create mode 100644 fastpair/internal/mediums/bluetooth_radio.cc create mode 100644 fastpair/internal/mediums/bluetooth_radio.h create mode 100644 fastpair/internal/mediums/bluetooth_radio_test.cc create mode 100644 fastpair/internal/mediums/mediums.h create mode 100644 fastpair/internal/mediums/mediums_test.cc diff --git a/fastpair/dart/fast_pair_wrapper_impl.cc b/fastpair/dart/fast_pair_wrapper_impl.cc index de235a75..c29935e9 100644 --- a/fastpair/dart/fast_pair_wrapper_impl.cc +++ b/fastpair/dart/fast_pair_wrapper_impl.cc @@ -30,7 +30,8 @@ FastPairWrapperImpl::FastPairWrapperImpl() { FastPairWrapperImpl::~FastPairWrapperImpl() = default; void FastPairWrapperImpl::StartScan() { - scanner_broker_ = std::make_unique(); + Mediums mediums; + scanner_broker_ = std::make_unique(mediums); if (is_scanning_) { NEARBY_LOGS(VERBOSE) << __func__ << ": We're currently scanning. "; return; diff --git a/fastpair/dart/fast_pair_wrapper_impl_test.cc b/fastpair/dart/fast_pair_wrapper_impl_test.cc index afd1f768..b614ae37 100644 --- a/fastpair/dart/fast_pair_wrapper_impl_test.cc +++ b/fastpair/dart/fast_pair_wrapper_impl_test.cc @@ -16,8 +16,6 @@ #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "internal/platform/medium_environment.h" @@ -42,7 +40,7 @@ TEST_F(FastPairWrapperImplTest, StartScanningSuccess) { EXPECT_FALSE(wrapper_->IsPairing()); EXPECT_FALSE(wrapper_->IsServerAccessing()); wrapper_->StartScan(); - SystemClock::Sleep(absl::Milliseconds(200)); + SystemClock::Sleep(absl::Milliseconds(2000)); EXPECT_TRUE(wrapper_->IsScanning()); env_.Stop(); } diff --git a/fastpair/handshake/BUILD b/fastpair/handshake/BUILD index 2b6b079e..40de6d37 100644 --- a/fastpair/handshake/BUILD +++ b/fastpair/handshake/BUILD @@ -39,7 +39,7 @@ cc_library( "//fastpair/common", "//fastpair/crypto", "//fastpair/dataparser", - "//fastpair/internal/ble", + "//fastpair/internal/mediums", "//fastpair/repository", "//fastpair/server_access", "//internal/base:bluetooth_address", @@ -87,7 +87,7 @@ cc_test( "//fastpair/common", "//fastpair/crypto", "//fastpair/dataparser", - "//fastpair/internal/ble", + "//fastpair/internal/mediums", "//fastpair/server_access:test_support", "//fastpair/testing", "//internal/platform:logging", @@ -112,6 +112,7 @@ cc_test( ":handshake", ":test_support", "//fastpair/common", + "//fastpair/internal/mediums", "//fastpair/testing", "//internal/platform:base", "//internal/platform:comm", @@ -159,6 +160,7 @@ cc_test( deps = [ ":handshake", "//fastpair/common", + "//fastpair/internal/mediums", "//internal/platform:test_util", "//internal/platform:types", "//internal/platform/implementation/g3", # build_cleaner: keep diff --git a/fastpair/handshake/fast_pair_gatt_service_client_impl.cc b/fastpair/handshake/fast_pair_gatt_service_client_impl.cc index 4c0e2d04..c347db66 100644 --- a/fastpair/handshake/fast_pair_gatt_service_client_impl.cc +++ b/fastpair/handshake/fast_pair_gatt_service_client_impl.cc @@ -35,8 +35,8 @@ #include "fastpair/common/pair_failure.h" #include "fastpair/handshake/fast_pair_data_encryptor.h" #include "fastpair/handshake/fast_pair_gatt_service_client.h" +#include "fastpair/internal/mediums/mediums.h" #include "internal/base/bluetooth_address.h" -#include "internal/platform/ble_v2.h" #include "internal/platform/logging.h" #include "internal/platform/uuid.h" #include @@ -68,12 +68,13 @@ FastPairGattServiceClientImpl::Factory* // static std::unique_ptr -FastPairGattServiceClientImpl::Factory::Create(const FastPairDevice& device) { +FastPairGattServiceClientImpl::Factory::Create(const FastPairDevice& device, + Mediums& mediums) { if (g_test_factory_) { return g_test_factory_->CreateInstance(); } - return std::make_unique(device); + return std::make_unique(device, mediums); } // static @@ -85,8 +86,8 @@ void FastPairGattServiceClientImpl::Factory::SetFactoryForTesting( FastPairGattServiceClientImpl::Factory::~Factory() = default; FastPairGattServiceClientImpl::FastPairGattServiceClientImpl( - const FastPairDevice& device) - : device_address_(device.GetBleAddress()) {} + const FastPairDevice& device, Mediums& mediums) + : device_address_(device.GetBleAddress()), mediums_(mediums) {} void FastPairGattServiceClientImpl::InitializeGattConnection( absl::AnyInvocable)> @@ -118,7 +119,10 @@ void FastPairGattServiceClientImpl::AttemptGattConnection() { void FastPairGattServiceClientImpl::CreateGattConnection() { NEARBY_LOGS(INFO) << __func__ << " : Create Gatt Connection to the device."; - gatt_client_ = ble_.ConnectToGattServer(device_address_); + if (mediums_.GetBluetoothRadio().Enable() && + mediums_.GetBleV2().IsAvailable()) { + gatt_client_ = mediums_.GetBleV2().ConnectToGattServer(device_address_); + } if (!gatt_client_) { // The device must have been lost between connection attempts. NotifyInitializedError( @@ -260,7 +264,7 @@ void FastPairGattServiceClientImpl::WriteRequestAsync( std::vector data_to_write_vec(data_to_write.begin(), data_to_write.end()); - // Append the public version of the private key to the message so thedevice + // Append the public version of the private key to the message so the device // can generate the shared secret to decrypt the message. const std::optional> public_key = fast_pair_data_encryptor.GetPublicKey(); diff --git a/fastpair/handshake/fast_pair_gatt_service_client_impl.h b/fastpair/handshake/fast_pair_gatt_service_client_impl.h index d904e14a..bd8251b9 100644 --- a/fastpair/handshake/fast_pair_gatt_service_client_impl.h +++ b/fastpair/handshake/fast_pair_gatt_service_client_impl.h @@ -25,7 +25,7 @@ #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/pair_failure.h" #include "fastpair/handshake/fast_pair_gatt_service_client.h" -#include "fastpair/internal/ble/ble.h" +#include "fastpair/internal/mediums/mediums.h" #include "internal/platform/ble_v2.h" #include "internal/platform/timer_impl.h" @@ -41,7 +41,7 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient { class Factory { public: static std::unique_ptr Create( - const FastPairDevice& device); + const FastPairDevice& device, Mediums& mediums); static void SetFactoryForTesting(Factory* test_factory); protected: @@ -52,7 +52,8 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient { static Factory* g_test_factory_; }; - explicit FastPairGattServiceClientImpl(const FastPairDevice& device); + explicit FastPairGattServiceClientImpl(const FastPairDevice& device, + Mediums& mediums); FastPairGattServiceClientImpl(const FastPairGattServiceClientImpl&) = delete; FastPairGattServiceClientImpl& operator=( const FastPairGattServiceClientImpl&) = delete; @@ -144,7 +145,7 @@ class FastPairGattServiceClientImpl : public FastPairGattServiceClient { bool is_initialized_ = false; std::string device_address_; std::unique_ptr gatt_client_; - Ble ble_; + Mediums& mediums_; }; } // namespace fastpair } // namespace nearby diff --git a/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc b/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc index f6750688..8bd35736 100644 --- a/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc +++ b/fastpair/handshake/fast_pair_gatt_service_client_impl_test.cc @@ -30,6 +30,7 @@ #include "fastpair/common/protocol.h" #include "fastpair/handshake/fake_fast_pair_data_encryptor.h" #include "fastpair/handshake/fast_pair_gatt_service_client.h" +#include "fastpair/internal/mediums/mediums.h" #include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/byte_array.h" @@ -165,7 +166,9 @@ class FastPairGattServiceClientTest : public testing::Test { void InitializeFastPairGattServiceClient() { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); - gatt_client_ = FastPairGattServiceClientImpl::Factory::Create(device); + Mediums mediums; + gatt_client_ = + FastPairGattServiceClientImpl::Factory::Create(device, mediums); gatt_client_->InitializeGattConnection( [this](std::optional failure) { initalized_failure_ = failure; diff --git a/fastpair/handshake/fast_pair_handshake_impl.cc b/fastpair/handshake/fast_pair_handshake_impl.cc index 16317315..734c7112 100644 --- a/fastpair/handshake/fast_pair_handshake_impl.cc +++ b/fastpair/handshake/fast_pair_handshake_impl.cc @@ -31,10 +31,11 @@ namespace nearby { namespace fastpair { FastPairHandshakeImpl::FastPairHandshakeImpl(FastPairDevice& device, + Mediums& mediums, OnCompleteCallback on_complete) : FastPairHandshake(std::move(on_complete), nullptr, nullptr) { fast_pair_gatt_service_client_ = - FastPairGattServiceClientImpl::Factory::Create(device); + FastPairGattServiceClientImpl::Factory::Create(device, mediums); fast_pair_gatt_service_client_->InitializeGattConnection( [&](std::optional failure) { OnGattClientInitializedCallback(device, failure); diff --git a/fastpair/handshake/fast_pair_handshake_impl.h b/fastpair/handshake/fast_pair_handshake_impl.h index e38fc688..fa8a46a3 100644 --- a/fastpair/handshake/fast_pair_handshake_impl.h +++ b/fastpair/handshake/fast_pair_handshake_impl.h @@ -22,13 +22,15 @@ #include "fastpair/common/pair_failure.h" #include "fastpair/crypto/decrypted_response.h" #include "fastpair/handshake/fast_pair_handshake.h" +#include "fastpair/internal/mediums/mediums.h" namespace nearby { namespace fastpair { class FastPairHandshakeImpl : public FastPairHandshake { public: - FastPairHandshakeImpl(FastPairDevice& device, OnCompleteCallback on_complete); + explicit FastPairHandshakeImpl(FastPairDevice& device, Mediums& mediums, + OnCompleteCallback on_complete); FastPairHandshakeImpl(const FastPairHandshakeImpl&) = delete; FastPairHandshakeImpl& operator=(const FastPairHandshakeImpl&) = delete; diff --git a/fastpair/handshake/fast_pair_handshake_impl_test.cc b/fastpair/handshake/fast_pair_handshake_impl_test.cc index 47dac67c..d3511542 100644 --- a/fastpair/handshake/fast_pair_handshake_impl_test.cc +++ b/fastpair/handshake/fast_pair_handshake_impl_test.cc @@ -162,8 +162,9 @@ TEST_F(FastPairHandshakeImplTest, Success) { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); CountDownLatch latch(1); + Mediums mediums; handshake_ = std::make_unique( - device, + device, mediums, [&](FastPairDevice& callback_device, std::optional failure) { EXPECT_EQ(&device, &callback_device); EXPECT_EQ(device.public_address(), kPublicAddress); @@ -180,8 +181,9 @@ TEST_F(FastPairHandshakeImplTest, GattError) { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); CountDownLatch latch(1); + Mediums mediums; handshake_ = std::make_unique( - device, + device, mediums, [&](FastPairDevice& callback_device, std::optional failure) { EXPECT_EQ(&device, &callback_device); EXPECT_EQ(failure.value(), PairFailure::kCreateGattConnection); @@ -197,8 +199,9 @@ TEST_F(FastPairHandshakeImplTest, DataEncryptorCreateError) { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); CountDownLatch latch(1); + Mediums mediums; handshake_ = std::make_unique( - device, + device, mediums, [&](FastPairDevice& callback_device, std::optional failure) { EXPECT_EQ(&device, &callback_device); EXPECT_EQ(failure.value(), PairFailure::kDataEncryptorRetrieval); @@ -214,8 +217,9 @@ TEST_F(FastPairHandshakeImplTest, WriteResponseError) { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); CountDownLatch latch(1); + Mediums mediums; handshake_ = std::make_unique( - device, + device, mediums, [&](FastPairDevice& callback_device, std::optional failure) { EXPECT_EQ(&device, &callback_device); EXPECT_EQ(failure.value(), @@ -233,8 +237,9 @@ TEST_F(FastPairHandshakeImplTest, WriteResponseWrongSize) { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); CountDownLatch latch(1); + Mediums mediums; handshake_ = std::make_unique( - device, + device, mediums, [&](FastPairDevice& callback_device, std::optional failure) { EXPECT_EQ(&device, &callback_device); EXPECT_EQ(failure.value(), @@ -252,8 +257,9 @@ TEST_F(FastPairHandshakeImplTest, ParseResponseError) { FastPairDevice device(kMetadataId, kProviderAddress, Protocol::kFastPairInitialPairing); CountDownLatch latch(1); + Mediums mediums; handshake_ = std::make_unique( - device, + device, mediums, [&](FastPairDevice& callback_device, std::optional failure) { EXPECT_EQ(&device, &callback_device); EXPECT_EQ(failure.value(), diff --git a/fastpair/handshake/fast_pair_handshake_lookup.cc b/fastpair/handshake/fast_pair_handshake_lookup.cc index a137280d..93dc075e 100644 --- a/fastpair/handshake/fast_pair_handshake_lookup.cc +++ b/fastpair/handshake/fast_pair_handshake_lookup.cc @@ -77,11 +77,11 @@ void FastPairHandshakeLookup::Clear() { } FastPairHandshake* FastPairHandshakeLookup::Create( - FastPairDevice& device, OnCompleteCallback on_complete) { + FastPairDevice& device, Mediums& mediums, OnCompleteCallback on_complete) { absl::MutexLock lock(&mutex_); auto it = fast_pair_handshakes_.emplace( - &device, - std::make_unique(device, std::move(on_complete))); + &device, std::make_unique(device, mediums, + std::move(on_complete))); DCHECK(it.second); return it.first->second.get(); } diff --git a/fastpair/handshake/fast_pair_handshake_lookup.h b/fastpair/handshake/fast_pair_handshake_lookup.h index 4909fa17..2b459077 100644 --- a/fastpair/handshake/fast_pair_handshake_lookup.h +++ b/fastpair/handshake/fast_pair_handshake_lookup.h @@ -24,6 +24,7 @@ #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/pair_failure.h" #include "fastpair/handshake/fast_pair_handshake.h" +#include "fastpair/internal/mediums/mediums.h" namespace nearby { namespace fastpair { @@ -63,7 +64,7 @@ class FastPairHandshakeLookup { // Creates and returns a new instance for |FastPairdevice| if no instance // already exists. // Returns the existing instance if there is one. - FastPairHandshake* Create(FastPairDevice& device, + FastPairHandshake* Create(FastPairDevice& device, Mediums& mediums, OnCompleteCallback on_complete); protected: diff --git a/fastpair/handshake/fast_pair_handshake_lookup_test.cc b/fastpair/handshake/fast_pair_handshake_lookup_test.cc index d30e88ab..f95ab526 100644 --- a/fastpair/handshake/fast_pair_handshake_lookup_test.cc +++ b/fastpair/handshake/fast_pair_handshake_lookup_test.cc @@ -17,15 +17,13 @@ #include #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/strings/string_view.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/pair_failure.h" #include "fastpair/common/protocol.h" +#include "fastpair/internal/mediums/mediums.h" #include "internal/platform/count_down_latch.h" -#include "internal/platform/medium_environment.h" namespace nearby { namespace fastpair { @@ -43,8 +41,9 @@ class FastPairHandshakeLookupTest : public ::testing::Test { void CreateFastPairHandshkeInstanceForDevice(FastPairDevice& device) { CountDownLatch latch(1); + Mediums mediums; EXPECT_TRUE(FastPairHandshakeLookup::GetInstance()->Create( - device, + device, mediums, [&](FastPairDevice& cb_device, std::optional failure) { EXPECT_EQ(&device, &cb_device); EXPECT_EQ(failure, PairFailure::kCreateGattConnection); diff --git a/fastpair/internal/ble/BUILD b/fastpair/internal/mediums/BUILD similarity index 55% rename from fastpair/internal/ble/BUILD rename to fastpair/internal/mediums/BUILD index 2fe38e54..22bcdd14 100644 --- a/fastpair/internal/ble/BUILD +++ b/fastpair/internal/mediums/BUILD @@ -15,12 +15,17 @@ licenses(["notice"]) cc_library( - name = "ble", + name = "mediums", srcs = [ "ble.cc", + "ble_v2.cc", + "bluetooth_radio.cc", ], hdrs = [ "ble.h", + "ble_v2.h", + "bluetooth_radio.h", + "mediums.h", ], visibility = [ "//fastpair:__subpackages__", @@ -30,13 +35,41 @@ cc_library( "//internal/platform:comm", "//internal/platform:logging", "//internal/platform:types", - "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", ], ) +cc_test( + name = "bluetooth_radio_test", + size = "small", + srcs = [ + "bluetooth_radio_test.cc", + ], + shard_count = 16, + deps = [ + ":mediums", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "mediums_test", + size = "small", + srcs = [ + "mediums_test.cc", + ], + shard_count = 16, + deps = [ + ":mediums", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "ble_test", size = "small", @@ -45,7 +78,7 @@ cc_test( ], shard_count = 16, deps = [ - ":ble", + ":mediums", "//internal/platform:base", "//internal/platform:comm", "//internal/platform:test_util", @@ -57,3 +90,18 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "ble_v2_test", + size = "small", + srcs = [ + "ble_v2_test.cc", + ], + shard_count = 16, + deps = [ + ":mediums", + "//internal/platform/implementation/g3", # build_cleaner: keep + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/fastpair/internal/ble/ble.cc b/fastpair/internal/mediums/ble.cc similarity index 64% rename from fastpair/internal/ble/ble.cc rename to fastpair/internal/mediums/ble.cc index 7edfd25e..14c790da 100644 --- a/fastpair/internal/ble/ble.cc +++ b/fastpair/internal/mediums/ble.cc @@ -12,87 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "fastpair/internal/ble/ble.h" +#include "fastpair/internal/mediums/ble.h" -#include #include #include -#include "internal/platform/ble_v2.h" +#include "fastpair/internal/mediums/bluetooth_radio.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/logging.h" +#include "internal/platform/mutex_lock.h" namespace nearby { namespace fastpair { -namespace { -// A stub BlePeripheral implementation. -class BlePeripheralStub : public api::ble_v2::BlePeripheral { - public: - explicit BlePeripheralStub(absl::string_view ble_address) { - ble_address_ = std::string(ble_address); - } - - std::string GetAddress() const override { return ble_address_; } - - private: - std::string ble_address_; -}; -} // namespace - -Ble::~Ble() { - // We never enabled Bluetooth, nothing to do. - if (!ever_saved_state_.Get()) { - NEARBY_LOG(INFO, "BT adapter was not used. Not touching HW."); - return; - } - - NEARBY_LOG(INFO, "Bring BT adapter to original state"); - if (!SetBluetoothState(originally_enabled_.Get())) { - NEARBY_LOG(INFO, "Failed to restore BT adapter original state."); - } -} - -bool Ble::Enable() { - if (!SaveOriginalState()) { - return false; - } - - return SetBluetoothState(true); -} - -bool Ble::Disable() { - if (!SaveOriginalState()) { - return false; - } - - return SetBluetoothState(false); -} - -bool Ble::IsEnabled() const { - return IsAdapterValid() && IsInDesiredState(true); -} - -bool Ble::SetBluetoothState(bool enable) { - return adapter_.SetStatus(enable ? BluetoothAdapter::Status::kEnabled - : BluetoothAdapter::Status::kDisabled); -} - -bool Ble::IsInDesiredState(bool should_be_enabled) const { - return adapter_.IsEnabled() == should_be_enabled; -} - -bool Ble::SaveOriginalState() { - if (!IsAdapterValid()) { - return false; - } - - // If we haven't saved the original state of the radio, save it. - if (!ever_saved_state_.Set(true)) { - originally_enabled_.Set(adapter_.IsEnabled()); - } - - return true; -} +Ble::Ble(BluetoothRadio& radio) : radio_(radio) {} bool Ble::IsAvailable() const { MutexLock lock(&mutex_); @@ -122,7 +54,7 @@ bool Ble::StartScanning(const std::string& service_id, return false; } - if (!IsEnabled()) { + if (!radio_.IsEnabled()) { NEARBY_LOGS(INFO) << "Can't start BLE scanning because Bluetooth was NOT enabled"; return false; @@ -183,18 +115,9 @@ bool Ble::StopScanning(const std::string& service_id) { return ret; } -std::unique_ptr Ble::ConnectToGattServer( - absl::string_view ble_address) { - MutexLock lock(&mutex_); - auto v2_peripheral = std::make_unique(ble_address); - return v2_medium_.ConnectToGattServer(BleV2Peripheral(v2_peripheral.get()), - api::ble_v2::TxPowerLevel::kUnknown, - {}); -} - bool Ble::IsScanning() { + NEARBY_LOGS(INFO) << __func__; MutexLock lock(&mutex_); - return IsScanningLocked(); } diff --git a/fastpair/internal/ble/ble.h b/fastpair/internal/mediums/ble.h similarity index 50% rename from fastpair/internal/ble/ble.h rename to fastpair/internal/mediums/ble.h index b1710bdf..c6923384 100644 --- a/fastpair/internal/ble/ble.h +++ b/fastpair/internal/mediums/ble.h @@ -15,59 +15,30 @@ #ifndef THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_BLE_BLE_H_ #define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_BLE_BLE_H_ -#include -#include #include -#include "absl/container/flat_hash_map.h" -#include "absl/container/flat_hash_set.h" -#include "internal/platform/atomic_boolean.h" +#include "fastpair/internal/mediums/bluetooth_radio.h" #include "internal/platform/ble.h" -#include "internal/platform/ble_v2.h" #include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/multi_thread_executor.h" #include "internal/platform/mutex.h" namespace nearby { namespace fastpair { +// Provides the operations that can be performed on the Bluetooth Low Energy +// (BLE) medium. class Ble { public: using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback; - Ble() = default; - Ble(Ble&&) = default; - Ble& operator=(Ble&&) = default; + explicit Ble(BluetoothRadio& bluetooth_radio); + Ble(Ble&&) = delete; + Ble& operator=(Ble&&) = delete; + ~Ble() = default; - // Reverts the Ble to its original state. - ~Ble(); - - // Enables Bluetooth. Returns true if enabled successfully. - // This must be called before attempting to invoke any other methods of - // this class. - bool Enable(); - - // Disables Bluetooth. Returns true if disabled successfully. - bool Disable(); - - // Returns true if the Bluetooth radio is currently enabled. - bool IsEnabled() const; - - // Returns true if Ble communications are supported by a platform. + // Returns true, if Ble communications are supported by a platform. bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); - // Returns true if this object owns a valid platform implementation. - bool IsMediumValid() const ABSL_LOCKS_EXCLUDED(mutex_) { - MutexLock lock(&mutex_); - return medium_.IsValid(); - } - - // Returns true if this object has a valid BluetoothAdapter reference. - bool IsAdapterValid() const { return adapter_.IsValid(); } - - // Return true if Ble is currenlty scanning. - bool IsScanning() ABSL_LOCKS_EXCLUDED(mutex_); - // Enables Ble scanning mode. Will report any discoverable peripherals in // range through a callback. Returns true, if scanning mode was enabled, // false otherwise. @@ -76,51 +47,29 @@ class Ble { DiscoveredPeripheralCallback callback) ABSL_LOCKS_EXCLUDED(mutex_); - // Returns a new GattClient connection to a gatt server. - std::unique_ptr ConnectToGattServer( - absl::string_view ble_address); - // Disables Ble discovery mode. bool StopScanning(const std::string& service_id) ABSL_LOCKS_EXCLUDED(mutex_); + // Return true if Ble is currenlty scanning. + bool IsScanning() ABSL_LOCKS_EXCLUDED(mutex_); + // Return BleMedium BleMedium& getMedium() { return medium_; } - // Return BluetoothAdapter - BluetoothAdapter& GetBluetoothAdapter() { return adapter_; } - private: - mutable Mutex mutex_; - // BluetoothAdapter::IsValid() will return false if BT is not supported. - BluetoothAdapter adapter_; - DiscoveredPeripheralCallback discovered_peripheral_callback_; - BleMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; - BleV2Medium v2_medium_ ABSL_GUARDED_BY(mutex_){adapter_}; - bool is_scanning_ = false; - // Same as IsAvailable(), but must be called with mutex_ held. bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); // Same as IsDiscovering(), but must be called with mutex_ held. bool IsScanningLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - bool SetBluetoothState(bool enable); - - bool IsInDesiredState(bool should_be_enabled) const; - - // To be called in enable() and disable(). This will remember the - // original state of the ble before any ble state has been modified. - // Returns false if Bluetooth doesn't exist on the device and the state cannot - // be obtained. - bool SaveOriginalState(); - - // The Ble's original state, before we modified it. True if - // originally enabled, false if originally disabled. - // We restore the radio to its original state in the destructor. - AtomicBoolean originally_enabled_{false}; - - // false if we never modified the radio state, true otherwise. - AtomicBoolean ever_saved_state_{false}; + mutable Mutex mutex_; + DiscoveredPeripheralCallback discovered_peripheral_callback_; + BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); + BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ + radio_.GetBluetoothAdapter()}; + BleMedium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; + bool is_scanning_ = false; }; } // namespace fastpair diff --git a/fastpair/internal/ble/ble_test.cc b/fastpair/internal/mediums/ble_test.cc similarity index 59% rename from fastpair/internal/ble/ble_test.cc rename to fastpair/internal/mediums/ble_test.cc index f4d7c0d6..9fb93fd1 100644 --- a/fastpair/internal/ble/ble_test.cc +++ b/fastpair/internal/mediums/ble_test.cc @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// 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. @@ -12,13 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "fastpair/internal/ble/ble.h" +#include "fastpair/internal/mediums/ble.h" #include #include "gtest/gtest.h" -#include "internal/platform/ble.h" -#include "internal/platform/bluetooth_adapter.h" #include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" @@ -26,64 +24,27 @@ namespace nearby { namespace fastpair { namespace { -using FeatureFlags = FeatureFlags::Flags; - +using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback; constexpr absl::Duration kWaitDuration = absl::Milliseconds(1000); constexpr absl::string_view kServiceID{"com.google.location.nearby.apps.test"}; constexpr absl::string_view kAdvertisementString{"96C12E"}; constexpr absl::string_view kFastPairServiceUuid{"\x2c\xfe"}; -class BleTest : public ::testing::TestWithParam { - protected: - using DiscoveredPeripheralCallback = BleMedium::DiscoveredPeripheralCallback; - - MediumEnvironment& env_{MediumEnvironment::Instance()}; -}; - -TEST_F(BleTest, ConstructorDestructorWorks) { - Ble ble; - EXPECT_TRUE(ble.IsAdapterValid()); +TEST(BleTest, ConstructorDestructorWorks) { + BluetoothRadio radio; + Ble ble(radio); + EXPECT_TRUE(ble.IsAvailable()); + EXPECT_FALSE(ble.IsScanning()); } -TEST_F(BleTest, CanEnable) { - Ble ble; - EXPECT_TRUE(ble.IsAdapterValid()); - EXPECT_TRUE(ble.IsEnabled()); - EXPECT_TRUE(ble.Disable()); - EXPECT_FALSE(ble.IsEnabled()); - EXPECT_TRUE(ble.Enable()); - EXPECT_TRUE(ble.IsEnabled()); -} - -TEST_F(BleTest, CanDisable) { - Ble ble; - EXPECT_TRUE(ble.IsAdapterValid()); - EXPECT_TRUE(ble.IsEnabled()); - EXPECT_TRUE(ble.Disable()); - EXPECT_FALSE(ble.IsEnabled()); -} - -TEST_F(BleTest, CanConstructValidObject) { - env_.Start(); - Ble ble_a; - Ble ble_b; - - EXPECT_TRUE(ble_a.IsMediumValid()); - EXPECT_TRUE(ble_a.IsAdapterValid()); - EXPECT_TRUE(ble_a.IsAvailable()); - EXPECT_TRUE(ble_b.IsMediumValid()); - EXPECT_TRUE(ble_b.IsAdapterValid()); - EXPECT_TRUE(ble_b.IsAvailable()); - EXPECT_NE(&ble_a.GetBluetoothAdapter(), &ble_b.GetBluetoothAdapter()); - env_.Stop(); -} - -TEST_F(BleTest, CanStartDiscovery) { - env_.Start(); - Ble ble_a; - Ble ble_b; - ble_a.Enable(); - ble_b.Enable(); +TEST(BleTest, CanStartDiscovery) { + MediumEnvironment::Instance().Start(); + BluetoothRadio radio_a; + BluetoothRadio radio_b; + Ble ble_a{radio_a}; + Ble ble_b{radio_b}; + radio_a.Enable(); + radio_b.Enable(); std::string service_id(kServiceID); ByteArray advertisement_bytes{std::string(kAdvertisementString)}; std::string fast_pair_service_uuid(kFastPairServiceUuid); @@ -112,16 +73,8 @@ TEST_F(BleTest, CanStartDiscovery) { EXPECT_TRUE(lost_latch.Await(kWaitDuration).result()); EXPECT_TRUE(ble_a.StopScanning(service_id)); EXPECT_FALSE(ble_a.IsScanning()); - env_.Stop(); + MediumEnvironment::Instance().Stop(); } - -TEST_F(BleTest, CannConnectToGattServer) { - env_.Start(); - Ble ble; - EXPECT_NE(ble.ConnectToGattServer("bleaddress"), nullptr); - env_.Stop(); -} - } // namespace } // namespace fastpair } // namespace nearby diff --git a/fastpair/internal/mediums/ble_v2.cc b/fastpair/internal/mediums/ble_v2.cc new file mode 100644 index 00000000..0fdc0c14 --- /dev/null +++ b/fastpair/internal/mediums/ble_v2.cc @@ -0,0 +1,69 @@ +// 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 "fastpair/internal/mediums/ble_v2.h" + +#include +#include + +#include "internal/platform/mutex_lock.h" + +namespace nearby { +namespace fastpair { +namespace { +// A stub BlePeripheral implementation. +class BlePeripheralStub : public api::ble_v2::BlePeripheral { + public: + explicit BlePeripheralStub(absl::string_view ble_address) { + ble_address_ = std::string(ble_address); + } + + std::string GetAddress() const override { return ble_address_; } + + private: + std::string ble_address_; +}; +} // namespace + +BleV2::BleV2(BluetoothRadio& radio) : radio_(radio) {} + +bool BleV2::IsAvailable() const { + MutexLock lock(&mutex_); + return IsAvailableLocked(); +} + +bool BleV2::IsAvailableLocked() const { + return medium_.IsValid() && adapter_.IsValid() && adapter_.IsEnabled(); +} + +std::unique_ptr BleV2::ConnectToGattServer( + absl::string_view ble_address) { + MutexLock lock(&mutex_); + if (!radio_.IsEnabled()) { + NEARBY_LOGS(INFO) + << "Can't connect to GattServer because Bluetooth was NOT enabled"; + return nullptr; + } + if (!IsAvailableLocked()) { + NEARBY_LOGS(VERBOSE) + << __func__ + << "Can't connect to GattServer because BleV2 isn't available."; + return nullptr; + } + auto v2_peripheral = std::make_unique(ble_address); + return medium_.ConnectToGattServer(BleV2Peripheral(v2_peripheral.get()), + api::ble_v2::TxPowerLevel::kUnknown, {}); +} +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/mediums/ble_v2.h b/fastpair/internal/mediums/ble_v2.h new file mode 100644 index 00000000..5a79e201 --- /dev/null +++ b/fastpair/internal/mediums/ble_v2.h @@ -0,0 +1,56 @@ +// 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_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_ + +#include + +#include "fastpair/internal/mediums/bluetooth_radio.h" +#include "internal/platform/ble_v2.h" +#include "internal/platform/mutex.h" +#include "internal/platform/mutex_lock.h" + +namespace nearby { +namespace fastpair { + +// Provides the operations that can be performed on the Bluetooth Low Energy +// (BLE_V2) medium. +class BleV2 { + public: + explicit BleV2(BluetoothRadio& bluetooth_radio); + ~BleV2() = default; + + // Returns true, if BleV2 communications are supported by a platform. + bool IsAvailable() const ABSL_LOCKS_EXCLUDED(mutex_); + + // Returns a new GattClient connection to a gatt server. + std::unique_ptr ConnectToGattServer( + absl::string_view ble_address); + + private: + // Same as IsAvailable(), but must be called with mutex_ held. + bool IsAvailableLocked() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); + + mutable Mutex mutex_; + BluetoothRadio& radio_ ABSL_GUARDED_BY(mutex_); + BluetoothAdapter& adapter_ ABSL_GUARDED_BY(mutex_){ + radio_.GetBluetoothAdapter()}; + BleV2Medium medium_ ABSL_GUARDED_BY(mutex_){adapter_}; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLE_V2_H_ diff --git a/fastpair/internal/mediums/ble_v2_test.cc b/fastpair/internal/mediums/ble_v2_test.cc new file mode 100644 index 00000000..26e9e52c --- /dev/null +++ b/fastpair/internal/mediums/ble_v2_test.cc @@ -0,0 +1,46 @@ +// 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 "fastpair/internal/mediums/ble_v2.h" + +#include "gtest/gtest.h" + +namespace nearby { +namespace fastpair { +namespace { + +TEST(BleV2Test, IsAvailable) { + BluetoothRadio radio; + BleV2 bleV2(radio); + EXPECT_TRUE(bleV2.IsAvailable()); + EXPECT_TRUE(radio.Disable()); + EXPECT_FALSE(bleV2.IsAvailable()); +} + +TEST(BleV2Test, CanConnectToGattServer) { + BluetoothRadio radio; + BleV2 bleV2(radio); + EXPECT_TRUE(bleV2.ConnectToGattServer("bleaddress")); +} + +TEST(BleV2Test, CannotConnectToGattServer) { + BluetoothRadio radio; + BleV2 bleV2(radio); + EXPECT_TRUE(radio.Disable()); + EXPECT_FALSE(bleV2.ConnectToGattServer("bleaddress")); +} + +} // namespace +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/mediums/bluetooth_radio.cc b/fastpair/internal/mediums/bluetooth_radio.cc new file mode 100644 index 00000000..b22895f4 --- /dev/null +++ b/fastpair/internal/mediums/bluetooth_radio.cc @@ -0,0 +1,86 @@ +// 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 "fastpair/internal/mediums/bluetooth_radio.h" + +#include "internal/platform/logging.h" + +namespace nearby { +namespace fastpair { + +BluetoothRadio::BluetoothRadio() { + if (!IsAdapterValid()) { + NEARBY_LOGS(ERROR) << "Bluetooth adapter is not valid: BT is not supported"; + } +} + +BluetoothRadio::~BluetoothRadio() { + // We never enabled Bluetooth, nothing to do. + if (!ever_saved_state_.Get()) { + NEARBY_LOGS(INFO) << "BT adapter was not used. Not touching HW."; + return; + } + + NEARBY_LOG(INFO, "Bring BT adapter to original state"); + if (!SetBluetoothState(originally_enabled_.Get())) { + NEARBY_LOGS(INFO) << "Failed to restore BT adapter original state."; + } +} + +bool BluetoothRadio::Enable() { + NEARBY_LOGS(INFO) << __func__; + if (!SaveOriginalState()) { + return false; + } + + return SetBluetoothState(true); +} + +bool BluetoothRadio::Disable() { + if (!SaveOriginalState()) { + return false; + } + + return SetBluetoothState(false); +} + +bool BluetoothRadio::IsEnabled() const { + return IsAdapterValid() && IsInDesiredState(true); +} + +bool BluetoothRadio::SetBluetoothState(bool enable) { + return bluetooth_adapter_.SetStatus( + enable ? BluetoothAdapter::Status::kEnabled + : BluetoothAdapter::Status::kDisabled); +} + +bool BluetoothRadio::IsInDesiredState(bool should_be_enabled) const { + return bluetooth_adapter_.IsEnabled() == should_be_enabled; +} + +bool BluetoothRadio::SaveOriginalState() { + if (!IsAdapterValid()) { + return false; + } + + // If we haven't saved the original state of the radio, save it. + if (!ever_saved_state_.Set(true)) { + originally_enabled_.Set(bluetooth_adapter_.IsEnabled()); + } + + return true; +} + +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/mediums/bluetooth_radio.h b/fastpair/internal/mediums/bluetooth_radio.h new file mode 100644 index 00000000..135d3731 --- /dev/null +++ b/fastpair/internal/mediums/bluetooth_radio.h @@ -0,0 +1,79 @@ +// 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_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ + +#include "internal/platform/atomic_boolean.h" +#include "internal/platform/bluetooth_adapter.h" + +namespace nearby { +namespace fastpair { + +// Provides the operations that can be performed on the Bluetooth radio. +class BluetoothRadio { + public: + BluetoothRadio(); + BluetoothRadio(BluetoothRadio&&) = default; + BluetoothRadio& operator=(BluetoothRadio&&) = default; + + // Reverts the Bluetooth radio to its original state. + ~BluetoothRadio(); + + // Enables Bluetooth. + // + // This must be called before attempting to invoke any other methods of + // this class. + // + // Returns true if enabled successfully. + bool Enable(); + + // Disables Bluetooth. + // + // Returns true if disabled successfully. + bool Disable(); + + // Returns true if the Bluetooth radio is currently enabled. + bool IsEnabled() const; + + // Returns result of BluetoothAdapter::IsValid() for private adapter instance. + bool IsAdapterValid() const { return bluetooth_adapter_.IsValid(); } + + BluetoothAdapter& GetBluetoothAdapter() { return bluetooth_adapter_; } + + private: + bool SetBluetoothState(bool enable); + bool IsInDesiredState(bool should_be_enabled) const; + // To be called in enable() and disable(). This will remember the + // original state of the radio before any radio state has been modified. + // Returns false if Bluetooth doesn't exist on the device and the state cannot + // be obtained. + bool SaveOriginalState(); + + // BluetoothAdapter::IsValid() will return false if BT is not supported. + BluetoothAdapter bluetooth_adapter_; + + // The Bluetooth radio's original state, before we modified it. True if + // originally enabled, false if originally disabled. + // We restore the radio to its original state in the destructor. + + AtomicBoolean originally_enabled_{false}; + // false if we never modified the radio state, true otherwise. + AtomicBoolean ever_saved_state_{false}; +}; + +} // namespace fastpair +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_BLUETOOTH_RADIO_H_ diff --git a/fastpair/internal/mediums/bluetooth_radio_test.cc b/fastpair/internal/mediums/bluetooth_radio_test.cc new file mode 100644 index 00000000..834aca8e --- /dev/null +++ b/fastpair/internal/mediums/bluetooth_radio_test.cc @@ -0,0 +1,48 @@ +// 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 "fastpair/internal/mediums/bluetooth_radio.h" + +#include "gtest/gtest.h" + +namespace nearby { +namespace fastpair { +namespace { + +TEST(BluetoothRadioTest, ConstructorDestructorWorks) { + BluetoothRadio radio; + EXPECT_TRUE(radio.IsAdapterValid()); +} + +TEST(BluetoothRadioTest, CanEnable) { + BluetoothRadio radio; + EXPECT_TRUE(radio.IsAdapterValid()); + EXPECT_TRUE(radio.IsEnabled()); + EXPECT_TRUE(radio.Disable()); + EXPECT_FALSE(radio.IsEnabled()); + EXPECT_TRUE(radio.Enable()); + EXPECT_TRUE(radio.IsEnabled()); +} + +TEST(BluetoothRadioTest, CanDisable) { + BluetoothRadio radio; + EXPECT_TRUE(radio.IsAdapterValid()); + EXPECT_TRUE(radio.IsEnabled()); + EXPECT_TRUE(radio.Disable()); + EXPECT_FALSE(radio.IsEnabled()); +} + +} // namespace +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/internal/mediums/mediums.h b/fastpair/internal/mediums/mediums.h new file mode 100644 index 00000000..cf3f21a9 --- /dev/null +++ b/fastpair/internal/mediums/mediums.h @@ -0,0 +1,56 @@ +// 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_FASTPAIR_INTERNAL_MEDIUMS_MEDIUMS_H_ +#define THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_MEDIUMS_H_ + +#include "fastpair/internal/mediums/ble.h" +#include "fastpair/internal/mediums/ble_v2.h" +#include "fastpair/internal/mediums/bluetooth_radio.h" + +namespace nearby { +namespace fastpair { + +// Facilitates convenient and reliable usage of various wireless mediums. +class Mediums { + public: + Mediums() = default; + ~Mediums() = default; + + // Returns a handle to the Bluetooth radio. + BluetoothRadio& GetBluetoothRadio() { return bluetooth_radio_; } + + // Returns a handle to the Ble medium. + Ble& GetBle() { return ble_; } + + // Returns a handle to the Ble medium. + BleV2& GetBleV2() { return ble_v2_; } + + private: + // The order of declaration is critical for both construction and + // destruction. + // + // 1) Construction: The individual mediums have a dependency on the + // corresponding radio, so the radio must be initialized first. + // + // 2) Destruction: The individual mediums should be shut down before the + // corresponding radio. + BluetoothRadio bluetooth_radio_; + Ble ble_{bluetooth_radio_}; + BleV2 ble_v2_{bluetooth_radio_}; +}; + +} // namespace fastpair +} // namespace nearby +#endif // THIRD_PARTY_NEARBY_FASTPAIR_INTERNAL_MEDIUMS_MEDIUMS_H_ diff --git a/fastpair/internal/mediums/mediums_test.cc b/fastpair/internal/mediums/mediums_test.cc new file mode 100644 index 00000000..2746abb3 --- /dev/null +++ b/fastpair/internal/mediums/mediums_test.cc @@ -0,0 +1,31 @@ +// 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 "fastpair/internal/mediums/mediums.h" + +#include "gtest/gtest.h" + +namespace nearby { +namespace fastpair { +namespace { + +TEST(MediumTest, ConstructorWorks) { + Mediums medium; + EXPECT_TRUE(medium.GetBluetoothRadio().IsAdapterValid()); + EXPECT_FALSE(medium.GetBle().IsScanning()); + EXPECT_TRUE(medium.GetBleV2().ConnectToGattServer("ble_address")); +} +} // namespace +} // namespace fastpair +} // namespace nearby diff --git a/fastpair/keyed_service/fast_pair_mediator.cc b/fastpair/keyed_service/fast_pair_mediator.cc index d72d01c1..fee1b2c9 100644 --- a/fastpair/keyed_service/fast_pair_mediator.cc +++ b/fastpair/keyed_service/fast_pair_mediator.cc @@ -29,12 +29,12 @@ Mediator::Mediator(std::unique_ptr scanner_broker, scanner_broker_->AddObserver(this); } -void Mediator::OnDeviceFound(const FastPairDevice& device) { +void Mediator::OnDeviceFound(FastPairDevice& device) { NEARBY_LOGS(INFO) << __func__ << ": " << device; // Show discovery notification } -void Mediator::OnDeviceLost(const FastPairDevice& device) { +void Mediator::OnDeviceLost(FastPairDevice& device) { NEARBY_LOGS(INFO) << __func__ << ": " << device; } diff --git a/fastpair/keyed_service/fast_pair_mediator.h b/fastpair/keyed_service/fast_pair_mediator.h index c59857a1..499b6ea2 100644 --- a/fastpair/keyed_service/fast_pair_mediator.h +++ b/fastpair/keyed_service/fast_pair_mediator.h @@ -33,8 +33,8 @@ class Mediator final : public ScannerBroker::Observer { ~Mediator() override = default; // ScannerBroker::Observer - void OnDeviceFound(const FastPairDevice& device) override; - void OnDeviceLost(const FastPairDevice& device) override; + void OnDeviceFound(FastPairDevice& device) override; + void OnDeviceLost(FastPairDevice& device) override; void StartScanning(); diff --git a/fastpair/scanning/BUILD b/fastpair/scanning/BUILD index aa2afbf9..e1dc5370 100644 --- a/fastpair/scanning/BUILD +++ b/fastpair/scanning/BUILD @@ -29,7 +29,7 @@ cc_library( ], deps = [ "//fastpair/common", - "//fastpair/internal/ble", + "//fastpair/internal/mediums", "//fastpair/scanning/fastpair:scanning", "//internal/base", "//internal/platform:base", @@ -68,7 +68,7 @@ cc_test( deps = [ ":scanner", "//fastpair/common", - "//fastpair/internal/ble", + "//fastpair/internal/mediums", "//fastpair/proto:fastpair_cc_proto", "//fastpair/server_access:test_support", "//internal/platform:base", diff --git a/fastpair/scanning/fastpair/BUILD b/fastpair/scanning/fastpair/BUILD index a1c758a6..2f3bd825 100644 --- a/fastpair/scanning/fastpair/BUILD +++ b/fastpair/scanning/fastpair/BUILD @@ -33,7 +33,7 @@ cc_library( deps = [ "//fastpair/common", "//fastpair/dataparser", - "//fastpair/internal/ble", + "//fastpair/internal/mediums", "//fastpair/proto:fastpair_cc_proto", "//fastpair/repository", "//fastpair/server_access", @@ -46,6 +46,7 @@ cc_library( "@com_google_absl//absl/functional:bind_front", "@com_google_absl//absl/strings", "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", ], ) @@ -79,6 +80,7 @@ cc_test( deps = [ ":scanning", "//fastpair/common", + "//fastpair/internal/mediums", "//internal/platform:base", "//internal/platform:comm", "//internal/platform:test_util", diff --git a/fastpair/scanning/fastpair/fake_fast_pair_scanner.h b/fastpair/scanning/fastpair/fake_fast_pair_scanner.h index 960bf83f..ed9d9254 100644 --- a/fastpair/scanning/fastpair/fake_fast_pair_scanner.h +++ b/fastpair/scanning/fastpair/fake_fast_pair_scanner.h @@ -32,6 +32,7 @@ class FakeFastPairScanner final : public FastPairScanner { void RemoveObserver(Observer* observer) override; void NotifyDeviceFound(const BlePeripheral& peripheral); void NotifyDeviceLost(const BlePeripheral& peripheral); + void StartScanning() override {}; private: ObserverList observer_; diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc index cc3daaa1..37fb3c62 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.cc @@ -66,19 +66,16 @@ FastPairDiscoverableScannerImpl::Factory* FastPairDiscoverableScannerImpl::Factory::g_test_factory_ = nullptr; std::unique_ptr -FastPairDiscoverableScannerImpl::Factory::Create( - std::shared_ptr scanner, - std::shared_ptr adapter, DeviceCallback found_callback, - DeviceCallback lost_callback) { +FastPairDiscoverableScannerImpl::Factory::Create(FastPairScanner& scanner, + DeviceCallback found_callback, + DeviceCallback lost_callback) { if (g_test_factory_) { - return g_test_factory_->CreateInstance( - std::move(scanner), std::move(adapter), std::move(found_callback), - std::move(lost_callback)); + return g_test_factory_->CreateInstance(scanner, std::move(found_callback), + std::move(lost_callback)); } return std::make_unique( - std::move(scanner), std::move(adapter), std::move(found_callback), - std::move(lost_callback)); + scanner, std::move(found_callback), std::move(lost_callback)); } void FastPairDiscoverableScannerImpl::Factory::SetFactoryForTesting( @@ -90,14 +87,12 @@ FastPairDiscoverableScannerImpl::Factory::~Factory() = default; // FastPairScannerImpl FastPairDiscoverableScannerImpl::FastPairDiscoverableScannerImpl( - std::shared_ptr scanner, - std::shared_ptr adapter, DeviceCallback found_callback, + FastPairScanner& scanner, DeviceCallback found_callback, DeviceCallback lost_callback) - : scanner_(std::move(scanner)), - adapter_(std::move(adapter)), + : scanner_(scanner), found_callback_(std::move(found_callback)), lost_callback_(std::move(lost_callback)) { - scanner_->AddObserver(this); + scanner_.AddObserver(this); } void FastPairDiscoverableScannerImpl::OnDeviceFound( diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h index 2b798242..d2f6aeb8 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h @@ -22,6 +22,7 @@ #include "absl/synchronization/mutex.h" #include "fastpair/common/fast_pair_device.h" +#include "fastpair/internal/mediums/mediums.h" #include "fastpair/repository/device_metadata.h" #include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" #include "fastpair/scanning/fastpair/fast_pair_scanner.h" @@ -37,25 +38,22 @@ class FastPairDiscoverableScannerImpl : public FastPairDiscoverableScanner, class Factory { public: static std::unique_ptr Create( - std::shared_ptr scanner, - std::shared_ptr adapter, - DeviceCallback found_callback, DeviceCallback lost_callback); + FastPairScanner& scanner, DeviceCallback found_callback, + DeviceCallback lost_callback); static void SetFactoryForTesting(Factory* g_test_factory); protected: virtual ~Factory(); virtual std::unique_ptr CreateInstance( - std::shared_ptr scanner, - std::shared_ptr adapter, - DeviceCallback found_callback, DeviceCallback lost_callback) = 0; + FastPairScanner& scanner, DeviceCallback found_callback, + DeviceCallback lost_callback) = 0; private: static Factory* g_test_factory_; }; - FastPairDiscoverableScannerImpl(std::shared_ptr scanner, - std::shared_ptr adapter, + FastPairDiscoverableScannerImpl(FastPairScanner& scanner, DeviceCallback found_callback, DeviceCallback lost_callback); FastPairDiscoverableScannerImpl(const FastPairDiscoverableScannerImpl&) = @@ -75,9 +73,9 @@ class FastPairDiscoverableScannerImpl : public FastPairDiscoverableScanner, const std::string model_id, DeviceMetadata& device_metadata); void NotifyDeviceFound(FastPairDevice& device); + absl::Mutex mutex_; - std::shared_ptr scanner_; - std::shared_ptr adapter_; + FastPairScanner& scanner_; DeviceCallback found_callback_; DeviceCallback lost_callback_; absl::flat_hash_map> diff --git a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl_test.cc b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl_test.cc index 883ff12f..42a891d8 100644 --- a/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl_test.cc +++ b/fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl_test.cc @@ -19,8 +19,6 @@ #include #include -#include "gmock/gmock.h" -#include "protobuf-matchers/protocol-buffer-matchers.h" #include "gtest/gtest.h" #include "absl/synchronization/notification.h" #include "fastpair/scanning/fastpair/fake_fast_pair_scanner.h" @@ -78,13 +76,11 @@ class FastPairDiscoverableScannerImplTest : public testing::Test { public: void SetUp() override { SetUpMetadata(); - scanner_ = std::make_shared(); - adapter_ = std::make_shared(); + scanner_ = std::make_unique(); } void TearDown() override { scanner_.reset(); - adapter_.reset(); repository_.reset(); } @@ -98,9 +94,8 @@ class FastPairDiscoverableScannerImplTest : public testing::Test { // void TearDown() override { discoverable_scanner_.reset(); } protected: - std::shared_ptr scanner_; + std::unique_ptr scanner_; std::unique_ptr repository_; - std::shared_ptr adapter_; DeviceCallback found_device_callback_; DeviceCallback lost_device_callback_; }; @@ -117,7 +112,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, ValidModelId) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -136,7 +131,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, InvalidModelId) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = std::make_unique( @@ -153,7 +148,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, NoServiceData) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -174,7 +169,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, UnsupportedDeviceType) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -196,7 +191,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, UnsupportedNotifictionType) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -222,7 +217,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, UnspecifiedNotificationType) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -246,7 +241,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, V1NotificationType) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -270,7 +265,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, V2NotificationType) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = @@ -287,7 +282,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, NearbyShareModelId) { std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = std::make_unique( @@ -309,7 +304,7 @@ TEST_F(FastPairDiscoverableScannerImplTest, std::unique_ptr discoverable_scanner_from_factory = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, std::move(found_device_callback_), + *scanner_, std::move(found_device_callback_), std::move(lost_device_callback_)); auto ble_peripheral = diff --git a/fastpair/scanning/fastpair/fast_pair_scanner.h b/fastpair/scanning/fastpair/fast_pair_scanner.h index 48d54980..1ace2606 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner.h +++ b/fastpair/scanning/fastpair/fast_pair_scanner.h @@ -38,7 +38,8 @@ class FastPairScanner { virtual void AddObserver(Observer* observer) = 0; virtual void RemoveObserver(Observer* observer) = 0; - protected: + virtual void StartScanning() = 0; + virtual ~FastPairScanner() = default; }; diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc b/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc index 4b4efc71..770cc092 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl.cc @@ -17,6 +17,7 @@ #include #include +#include "absl/time/time.h" #include "fastpair/common/constant.h" #include "internal/platform/byte_array.h" #include "internal/platform/logging.h" @@ -31,31 +32,9 @@ constexpr absl::Duration kFastPairLowPowerInactiveSeconds = absl::Seconds(3); constexpr char kFastPairServiceUuid[] = "0000FE2C-0000-1000-8000-00805F9B34FB"; } // namespace -// static -FastPairScannerImpl::Factory* FastPairScannerImpl::Factory::g_test_factory_ = - nullptr; - -// static -std::shared_ptr FastPairScannerImpl::Factory::Create() { - if (g_test_factory_) { - return g_test_factory_->CreateInstance(); - } - - return std::make_shared(); -} - -// static -void FastPairScannerImpl::Factory::SetFactoryForTesting( - Factory* g_test_factory) { - g_test_factory_ = g_test_factory; -} - -FastPairScannerImpl::Factory::~Factory() = default; - // FastPairScannerImpl -FastPairScannerImpl::FastPairScannerImpl() { +FastPairScannerImpl::FastPairScannerImpl(Mediums& mediums) : mediums_(mediums) { task_runner_ = std::make_unique(1); - StartScanning(); } void FastPairScannerImpl::AddObserver(FastPairScanner::Observer* observer) { @@ -67,10 +46,12 @@ void FastPairScannerImpl::RemoveObserver(FastPairScanner::Observer* observer) { } void FastPairScannerImpl::StartScanning() { + NEARBY_LOGS(VERBOSE) << __func__; task_runner_->PostTask( [this]() { - if (ble_.Enable() && - ble_.StartScanning( + if (mediums_.GetBluetoothRadio().Enable() && + mediums_.GetBle().IsAvailable() && + mediums_.GetBle().StartScanning( kServiceId, kFastPairServiceUuid, { .peripheral_discovered_cb = @@ -108,7 +89,7 @@ void FastPairScannerImpl::StartScanning() { void FastPairScannerImpl::StopScanning() { DCHECK(IsFastPairLowPowerEnabled()); - ble_.StopScanning(kServiceId); + mediums_.GetBle().StopScanning(kServiceId); task_runner_->PostDelayedTask(kFastPairLowPowerInactiveSeconds, [this]() { StartScanning(); }); } diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl.h b/fastpair/scanning/fastpair/fast_pair_scanner_impl.h index 9162a425..4a8a15a0 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl.h +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl.h @@ -15,18 +15,14 @@ #ifndef THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAST_PAIR_SCANNER_IMPL_H_ #define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_FASTPAIR_FAST_PAIR_SCANNER_IMPL_H_ -#include #include #include #include -#include -#include "absl/strings/string_view.h" -#include "fastpair/internal/ble/ble.h" +#include "fastpair/internal/mediums/mediums.h" #include "fastpair/scanning/fastpair/fast_pair_scanner.h" #include "internal/base/observer_list.h" #include "internal/platform/bluetooth_adapter.h" -#include "internal/platform/byte_array.h" #include "internal/platform/task_runner.h" namespace nearby { @@ -34,21 +30,7 @@ namespace fastpair { class FastPairScannerImpl : public FastPairScanner { public: - class Factory { - public: - static std::shared_ptr Create(); - - static void SetFactoryForTesting(Factory* g_test_factory); - - protected: - virtual ~Factory(); - virtual std::shared_ptr CreateInstance() = 0; - - private: - static Factory* g_test_factory_; - }; - - FastPairScannerImpl(); + explicit FastPairScannerImpl(Mediums& mediums); FastPairScannerImpl(const FastPairScannerImpl&) = delete; FastPairScannerImpl& operator=(const FastPairScannerImpl&) = delete; ~FastPairScannerImpl() override = default; @@ -65,11 +47,9 @@ class FastPairScannerImpl : public FastPairScanner { // Todo(b/267348348): Support Flags to control feature ramp bool IsFastPairLowPowerEnabled() const { return false; } - // For unit test - Ble& GetBle() { return ble_; } + void StartScanning() override; private: - void StartScanning(); void StopScanning(); std::unique_ptr task_runner_; @@ -80,7 +60,7 @@ class FastPairScannerImpl : public FastPairScanner { device_address_advertisement_data_map_; BluetoothAdapter bluetooth_adapter_; - Ble ble_; + Mediums& mediums_; ObserverList observer_; }; diff --git a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc index d0e520a0..e91d5848 100644 --- a/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc +++ b/fastpair/scanning/fastpair/fast_pair_scanner_impl_test.cc @@ -14,153 +14,86 @@ #include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h" -#include #include #include -#include #include "gtest/gtest.h" +#include "absl/strings/escaping.h" #include "absl/strings/string_view.h" -#include "absl/time/time.h" +#include "fastpair/internal/mediums/mediums.h" #include "fastpair/scanning/fastpair/fast_pair_scanner.h" #include "internal/platform/bluetooth_adapter.h" #include "internal/platform/byte_array.h" +#include "internal/platform/count_down_latch.h" #include "internal/platform/medium_environment.h" namespace nearby { namespace fastpair { namespace { -// Below constants are used to construct MockBluetoothDevice for testing. -constexpr char kTestBleDeviceAddress[] = "11:12:13:14:15:16"; -constexpr char kTestModelId[] = "112233"; -constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(200); - -class FakeBlePeripheral : public api::BlePeripheral { - public: - explicit FakeBlePeripheral(absl::string_view name, - absl::string_view service_data) { - name_ = std::string(name); - std::string service_data_str = std::string(service_data); - ByteArray advertisement_bytes(service_data_str); - advertisement_data_ = advertisement_bytes; - } - FakeBlePeripheral(const FakeBlePeripheral&) = default; - ~FakeBlePeripheral() override = default; - - std::string GetName() const override { return name_; } - - ByteArray GetAdvertisementBytes( - const std::string& service_id) const override { - return advertisement_data_; - } - - void SetName(const std::string& name) { name_ = name; } - - void SetAdvertisementBytes(ByteArray advertisement_bytes) { - advertisement_data_ = advertisement_bytes; - } - - private: - std::string name_; - ByteArray advertisement_data_; -}; +constexpr absl::Duration kTaskWaitTimeout = absl::Milliseconds(1000); +constexpr absl::string_view kServiceID{"Fast Pair"}; +constexpr absl::string_view kModelId{"718c17"}; +constexpr absl::string_view kFastPairServiceUuid{ + "0000FE2C-0000-1000-8000-00805F9B34FB"}; class FastPairScannerObserver : public FastPairScanner::Observer { public: + explicit FastPairScannerObserver(FastPairScanner* scanner, + CountDownLatch* accept_latch, + CountDownLatch* lost_latch) { + accept_latch_ = accept_latch; + lost_latch_ = lost_latch; + scanner->AddObserver(this); + } // FastPairScanner::Observer overrides void OnDeviceFound(const BlePeripheral& peripheral) override { - device_addreses_.push_back(peripheral.GetName()); - on_device_found_count_++; + accept_latch_->CountDown(); } void OnDeviceLost(const BlePeripheral& peripheral) override { - auto it = std::find(device_addreses_.begin(), device_addreses_.end(), - peripheral.GetName()); - if (it == device_addreses_.end()) return; - device_addreses_.erase(it); + lost_latch_->CountDown(); } - bool DoesDeviceListContainTestDevice(const std::string& address) { - auto it = - std::find(device_addreses_.begin(), device_addreses_.end(), address); - return it != device_addreses_.end(); - } - - int on_device_found_count() { return on_device_found_count_; } - - private: - std::vector device_addreses_; - - int on_device_found_count_ = 0; + CountDownLatch* accept_latch_ = nullptr; + CountDownLatch* lost_latch_ = nullptr; }; class FastPairScannerImplTest : public testing::Test { - public: - void SetUp() override { - env_.Start(); - scanner_ = std::make_shared(); - SystemClock::Sleep(kTaskWaitTimeout); - scanner_observer_ = std::make_unique(); - scanner_->AddObserver(scanner_observer_.get()); - } - - void TearDown() override { - scanner_->RemoveObserver(scanner_observer_.get()); - scanner_.reset(); - scanner_observer_.reset(); - env_.Stop(); - } - - void TriggerOnDeviceFound(absl::string_view address, absl::string_view data) { - auto ble_peripheral = std::make_unique(address, data); - scanner_->OnDeviceFound(BlePeripheral(ble_peripheral.get())); - } - - void TriggerOnDeviceLost(absl::string_view address, absl::string_view data) { - auto ble_peripheral = std::make_unique(address, data); - scanner_->OnDeviceLost(BlePeripheral(ble_peripheral.get())); - } - protected: MediumEnvironment& env_{MediumEnvironment::Instance()}; - std::shared_ptr scanner_; - std::unique_ptr scanner_observer_; }; -TEST_F(FastPairScannerImplTest, StartScanningSuccessfully) { - EXPECT_TRUE(scanner_->GetBle().IsScanning()); - // Not StopScanning as FastPairLowPowerDisabled -} +TEST_F(FastPairScannerImplTest, StartScanning) { + env_.Start(); -TEST_F(FastPairScannerImplTest, DeviceFoundNotifiesObservers) { - TriggerOnDeviceFound(kTestBleDeviceAddress, kTestModelId); - EXPECT_TRUE(scanner_observer_->DoesDeviceListContainTestDevice( - kTestBleDeviceAddress)); -} + // Create Fast Pair Scanner and add its observer + Mediums mediums_1; + auto scanner = std::make_unique(mediums_1); + CountDownLatch accept_latch(1); + CountDownLatch lost_latch(1); + FastPairScannerObserver observer(scanner.get(), &accept_latch, &lost_latch); -TEST_F(FastPairScannerImplTest, DeviceLostNotifiesObservers) { - TriggerOnDeviceFound(kTestBleDeviceAddress, kTestModelId); - EXPECT_TRUE(scanner_observer_->DoesDeviceListContainTestDevice( - kTestBleDeviceAddress)); - TriggerOnDeviceLost(kTestBleDeviceAddress, kTestModelId); - EXPECT_FALSE(scanner_observer_->DoesDeviceListContainTestDevice( - kTestBleDeviceAddress)); -} + // Create Advertiser and startAdvertising + Mediums mediums_2; + std::string service_id(kServiceID); + ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; + std::string fast_pair_service_uuid(kFastPairServiceUuid); + mediums_2.GetBle().getMedium().StartAdvertising( + service_id, advertisement_bytes, fast_pair_service_uuid); -TEST_F(FastPairScannerImplTest, DeviceFoundWithNoServiceData) {; - TriggerOnDeviceFound(kTestBleDeviceAddress, ""); - EXPECT_FALSE(scanner_observer_->DoesDeviceListContainTestDevice( - kTestBleDeviceAddress)); -} + // Fast Pair scanner startScanning + scanner->StartScanning(); + // Notify device found + EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); -TEST_F(FastPairScannerImplTest, RemoveObserver) { - scanner_->RemoveObserver(scanner_observer_.get()); - TriggerOnDeviceFound(kTestBleDeviceAddress, kTestModelId); - EXPECT_FALSE(scanner_observer_->DoesDeviceListContainTestDevice( - kTestBleDeviceAddress)); -} + // Advertiser stopAdvertising + mediums_2.GetBle().getMedium().StopAdvertising(service_id); + // Notify device lost + EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); + env_.Stop(); +} } // namespace } // namespace fastpair } // namespace nearby diff --git a/fastpair/scanning/mock_scanner_broker.h b/fastpair/scanning/mock_scanner_broker.h index 0df0bea0..29042c8d 100644 --- a/fastpair/scanning/mock_scanner_broker.h +++ b/fastpair/scanning/mock_scanner_broker.h @@ -35,13 +35,13 @@ class MockScannerBroker : public ScannerBroker { observers_.RemoveObserver(observer); } - void NotifyDeviceFound(const FastPairDevice& device) { + void NotifyDeviceFound(FastPairDevice& device) { for (auto& observer : observers_.GetObservers()) { observer->OnDeviceFound(device); } } - void NotifyDeviceLost(const FastPairDevice& device) { + void NotifyDeviceLost(FastPairDevice& device) { for (auto& observer : observers_.GetObservers()) { observer->OnDeviceLost(device); } diff --git a/fastpair/scanning/scanner_broker.h b/fastpair/scanning/scanner_broker.h index 0e191e28..3242e7b4 100644 --- a/fastpair/scanning/scanner_broker.h +++ b/fastpair/scanning/scanner_broker.h @@ -32,8 +32,8 @@ class ScannerBroker { public: virtual ~Observer() = default; - virtual void OnDeviceFound(const FastPairDevice& device) = 0; - virtual void OnDeviceLost(const FastPairDevice& device) = 0; + virtual void OnDeviceFound(FastPairDevice& device) = 0; + virtual void OnDeviceLost(FastPairDevice& device) = 0; }; virtual ~ScannerBroker() = default; diff --git a/fastpair/scanning/scanner_broker_impl.cc b/fastpair/scanning/scanner_broker_impl.cc index 36a60d80..372caddf 100644 --- a/fastpair/scanning/scanner_broker_impl.cc +++ b/fastpair/scanning/scanner_broker_impl.cc @@ -15,21 +15,17 @@ #include "fastpair/scanning/scanner_broker_impl.h" #include -#include #include "absl/functional/bind_front.h" #include "fastpair/common/fast_pair_device.h" -#include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" #include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner_impl.h" #include "fastpair/scanning/fastpair/fast_pair_scanner_impl.h" -#include "internal/platform/bluetooth_adapter.h" #include "internal/platform/logging.h" #include "internal/platform/task_runner_impl.h" namespace nearby { namespace fastpair { -ScannerBrokerImpl::ScannerBrokerImpl() { - adapter_ = std::make_shared(); +ScannerBrokerImpl::ScannerBrokerImpl(Mediums& mediums) : mediums_(mediums) { task_runner_ = std::make_unique(1); } @@ -50,16 +46,17 @@ void ScannerBrokerImpl::StopScanning(Protocol protocol) { NEARBY_LOGS(VERBOSE) << __func__ << ": protocol=" << protocol; task_runner_->PostTask([this]() { StopFastPairScanning(); }); } + void ScannerBrokerImpl::StartFastPairScanning() { DCHECK(!fast_pair_discoverable_scanner_); - DCHECK(adapter_); NEARBY_LOGS(VERBOSE) << "Starting Fast Pair Scanning."; - scanner_ = std::make_shared(); + scanner_ = std::make_unique(mediums_); fast_pair_discoverable_scanner_ = FastPairDiscoverableScannerImpl::Factory::Create( - scanner_, adapter_, + *scanner_, absl::bind_front(&ScannerBrokerImpl::NotifyDeviceFound, this), absl::bind_front(&ScannerBrokerImpl::NotifyDeviceLost, this)); + scanner_->StartScanning(); } void ScannerBrokerImpl::StopFastPairScanning() { @@ -69,7 +66,7 @@ void ScannerBrokerImpl::StopFastPairScanning() { NEARBY_LOGS(VERBOSE) << __func__ << "Stopping Fast Pair Scanning."; } -void ScannerBrokerImpl::NotifyDeviceFound(const FastPairDevice& device) { +void ScannerBrokerImpl::NotifyDeviceFound(FastPairDevice& device) { NEARBY_LOGS(INFO) << __func__ << ": Notifying device found, model id = " << device.GetModelId(); for (auto& observer : observers_.GetObservers()) { @@ -77,7 +74,7 @@ void ScannerBrokerImpl::NotifyDeviceFound(const FastPairDevice& device) { } } -void ScannerBrokerImpl::NotifyDeviceLost(const FastPairDevice& device) { +void ScannerBrokerImpl::NotifyDeviceLost(FastPairDevice& device) { NEARBY_LOGS(INFO) << __func__ << ": Notifying device lost, model id = " << device.GetModelId(); for (auto& observer : observers_.GetObservers()) { diff --git a/fastpair/scanning/scanner_broker_impl.h b/fastpair/scanning/scanner_broker_impl.h index bb40d6b7..36774597 100644 --- a/fastpair/scanning/scanner_broker_impl.h +++ b/fastpair/scanning/scanner_broker_impl.h @@ -15,16 +15,14 @@ #ifndef THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_IMPL_H_ #define THIRD_PARTY_NEARBY_FASTPAIR_SCANNING_SCANNER_BROKER_IMPL_H_ -#include #include -#include #include "fastpair/common/fast_pair_device.h" +#include "fastpair/internal/mediums/mediums.h" #include "fastpair/scanning/fastpair/fast_pair_discoverable_scanner.h" #include "fastpair/scanning/fastpair/fast_pair_scanner.h" #include "fastpair/scanning/scanner_broker.h" #include "internal/base/observer_list.h" -#include "internal/platform/bluetooth_adapter.h" #include "internal/platform/task_runner.h" namespace nearby { @@ -32,7 +30,7 @@ namespace fastpair { class ScannerBrokerImpl : public ScannerBroker { public: - explicit ScannerBrokerImpl(); + explicit ScannerBrokerImpl(Mediums& mediums); ~ScannerBrokerImpl() override = default; // ScannerBroker: @@ -44,12 +42,12 @@ class ScannerBrokerImpl : public ScannerBroker { private: void StartFastPairScanning(); void StopFastPairScanning(); - void NotifyDeviceFound(const FastPairDevice& device); - void NotifyDeviceLost(const FastPairDevice& device); + void NotifyDeviceFound(FastPairDevice& device); + void NotifyDeviceLost(FastPairDevice& device); + Mediums& mediums_; std::unique_ptr task_runner_; - std::shared_ptr scanner_; - std::shared_ptr adapter_; + std::unique_ptr scanner_; std::unique_ptr fast_pair_discoverable_scanner_; ObserverList observers_; }; diff --git a/fastpair/scanning/scanner_broker_impl_test.cc b/fastpair/scanning/scanner_broker_impl_test.cc index 6b3bf46b..273dcd04 100644 --- a/fastpair/scanning/scanner_broker_impl_test.cc +++ b/fastpair/scanning/scanner_broker_impl_test.cc @@ -22,7 +22,7 @@ #include "absl/strings/string_view.h" #include "fastpair/common/fast_pair_device.h" #include "fastpair/common/protocol.h" -#include "fastpair/internal/ble/ble.h" +#include "fastpair/internal/mediums/mediums.h" #include "fastpair/proto/fastpair_rpcs.proto.h" #include "fastpair/scanning/scanner_broker.h" #include "fastpair/server_access/fake_fast_pair_repository.h" @@ -52,11 +52,11 @@ class ScannerBrokerObserver : public ScannerBroker::Observer { scanner_broker->AddObserver(this); } - void OnDeviceFound(const FastPairDevice& device) override { + void OnDeviceFound(FastPairDevice& device) override { accept_latch_->CountDown(); } - void OnDeviceLost(const FastPairDevice& device) override { + void OnDeviceLost(FastPairDevice& device) override { lost_latch_->CountDown(); } @@ -71,28 +71,40 @@ class ScannerBrokerImplTest : public testing::Test { TEST_F(ScannerBrokerImplTest, CanStartScanning) { env_.Start(); - auto repository_ = std::make_unique(); - auto scanner_broker = std::make_unique(); - proto::Device metadata; + // Setup FakeFastPairRepository std::string decoded_key; absl::Base64Unescape(kPublicAntiSpoof, &decoded_key); + proto::Device metadata; + auto repository_ = std::make_unique(); metadata.mutable_anti_spoofing_key_pair()->set_public_key(decoded_key); repository_->SetFakeMetadata(kModelId, metadata); - std::string service_id(kServiceID); - ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; - std::string fast_pair_service_uuid(kFastPairServiceUuid); - Ble ble; + // Create Fast Pair Scanner and add its observer + Mediums mediums_1; + auto scanner_broker = std::make_unique(mediums_1); CountDownLatch accept_latch(1); CountDownLatch lost_latch(1); ScannerBrokerObserver observer(scanner_broker.get(), &accept_latch, &lost_latch); - ble.getMedium().StartAdvertising(service_id, advertisement_bytes, - fast_pair_service_uuid); + // Create Advertiser and startAdvertising + Mediums mediums_2; + std::string service_id(kServiceID); + ByteArray advertisement_bytes{absl::HexStringToBytes(kModelId)}; + std::string fast_pair_service_uuid(kFastPairServiceUuid); + mediums_2.GetBle().getMedium().StartAdvertising( + service_id, advertisement_bytes, fast_pair_service_uuid); + + // Fast Pair scanner startScanning scanner_broker->StartScanning(Protocol::kFastPairInitialPairing); + + // Notify device found EXPECT_TRUE(accept_latch.Await(kTaskWaitTimeout).result()); - ble.getMedium().StopAdvertising(service_id); + + // Advertiser stopAdvertising + mediums_2.GetBle().getMedium().StopAdvertising(service_id); + + // Notify device lost EXPECT_TRUE(lost_latch.Await(kTaskWaitTimeout).result()); env_.Stop(); } From 465aa7a48977b661d72fb366bbcebe1800194491 Mon Sep 17 00:00:00 2001 From: hai007 Date: Mon, 1 May 2023 11:12:26 -0700 Subject: [PATCH 53/63] Applied platform thread to network lib PiperOrigin-RevId: 528521852 --- fastpair/internal/test/BUILD | 3 - .../test/fast_pair_fake_http_client.h | 6 - internal/network/BUILD | 5 +- internal/network/http_client.h | 7 +- internal/network/http_client_impl.cc | 178 ++++++++---------- internal/network/http_client_impl.h | 23 +-- internal/network/http_client_impl_test.cc | 78 ++------ internal/platform/BUILD | 1 - 8 files changed, 107 insertions(+), 194 deletions(-) diff --git a/fastpair/internal/test/BUILD b/fastpair/internal/test/BUILD index 3ea07c91..c7413fad 100644 --- a/fastpair/internal/test/BUILD +++ b/fastpair/internal/test/BUILD @@ -14,8 +14,6 @@ cc_library( deps = [ "//internal/network:types", "@com_google_absl//absl/functional:any_invocable", - "@com_google_absl//absl/status", - "@com_google_absl//absl/status:statusor", ], ) @@ -32,7 +30,6 @@ cc_test( deps = [ ":nearby_fastpair_test", "//internal/network:types", - "//internal/platform/implementation/g3", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/functional:any_invocable", diff --git a/fastpair/internal/test/fast_pair_fake_http_client.h b/fastpair/internal/test/fast_pair_fake_http_client.h index c5baccb6..84824a3a 100644 --- a/fastpair/internal/test/fast_pair_fake_http_client.h +++ b/fastpair/internal/test/fast_pair_fake_http_client.h @@ -21,7 +21,6 @@ #include #include -#include "absl/status/statusor.h" #include "internal/network/http_client.h" namespace nearby { @@ -52,11 +51,6 @@ class FastPairFakeHttpClient : public HttpClient { request_infos_.push_back(std::move(request_info)); } - absl::StatusOr GetResponse( - const HttpRequest& request) override { - return absl::UnimplementedError("unimplemented"); - } - // Mock methods void CompleteRequest(const absl::StatusOr& response, size_t pos = 0) { diff --git a/internal/network/BUILD b/internal/network/BUILD index 0aa6ae8e..228863bc 100644 --- a/internal/network/BUILD +++ b/internal/network/BUILD @@ -26,7 +26,6 @@ cc_library( "//location/nearby/cpp/sharing:__subpackages__", ], deps = [ - "//internal/platform:types", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", @@ -54,11 +53,11 @@ cc_library( deps = [ ":types", "//internal/platform:logging", - "//internal/platform:types", "//internal/platform/implementation:platform", "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/synchronization", ], ) diff --git a/internal/network/http_client.h b/internal/network/http_client.h index ac8e2bff..a99362c3 100644 --- a/internal/network/http_client.h +++ b/internal/network/http_client.h @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Google LLC +// 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. @@ -28,15 +28,10 @@ class HttpClient { public: virtual ~HttpClient() = default; - // Starts HTTP request in asynchronization mode. virtual void StartRequest( const HttpRequest& request, std::function&)> callback) = 0; - // Gets HTTP response in synchronization mode. - virtual absl::StatusOr GetResponse( - const HttpRequest& request) = 0; - // The error may be corrected if retried at a later time. static bool IsRetryableHttpError(absl::Status status) { return absl::IsUnavailable(status) || absl::IsFailedPrecondition(status); diff --git a/internal/network/http_client_impl.cc b/internal/network/http_client_impl.cc index ed59f5ee..3f7b4a77 100644 --- a/internal/network/http_client_impl.cc +++ b/internal/network/http_client_impl.cc @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Google LLC +// 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. @@ -14,135 +14,107 @@ #include "internal/network/http_client_impl.h" +#include // NOLINT #include -#include +#include // NOLINT #include #include #include -#include "absl/status/statusor.h" #include "internal/network/debug.h" #include "internal/platform/implementation/platform.h" #include "internal/platform/logging.h" -#include "internal/platform/mutex_lock.h" namespace nearby { namespace network { -namespace { - -// In nearby SDK, allowed maximum thread count. -constexpr int kMaxNetworkThreadCount = 3; - -} // namespace - -NearbyHttpClient::NearbyHttpClient() { - network_executor_ = - std::make_unique(kMaxNetworkThreadCount); -} void NearbyHttpClient::StartRequest( const HttpRequest& request, std::function&)> callback) { - MutexLock lock(&mutex_); - NEARBY_LOGS(INFO) << __func__ << ": Start async request to url=" - << request.GetUrl().GetUrlPath(); - if (network_executor_ == nullptr) { - callback(absl::ResourceExhaustedError("no available thread")); - return; - } + absl::MutexLock lock(&mutex_); + CleanThreads(); - network_executor_->Execute([&, request, callback]() { - absl::StatusOr response = InternalGetResponse(request); - if (response.ok()) { - NEARBY_LOGS(INFO) << __func__ << ": Got response from url=" - << request.GetUrl().GetUrlPath(); - } else { - NEARBY_LOGS(ERROR) << __func__ << ": Failed to get response from url=" - << request.GetUrl().GetUrlPath() << ", status" - << response.status(); + std::future http_thread = std::async(std::launch::async, [&, request, + callback]() { + api::WebRequest web_request; + web_request.url = request.GetUrl().GetUrlPath(); + web_request.method = absl::StrCat(request.GetMethodString()); + for (const auto& header : request.GetAllHeaders()) { + for (const auto& value : header.second) { + web_request.headers.emplace(header.first, value); + } + } + web_request.body = absl::StrCat(request.GetBody().GetRawData()); + + if (debug::kRequestEnabled) { + std::stringstream request_stream; + request_stream << "HTTP REQUEST====>" << std::endl; + request_stream << web_request.method << " " << web_request.url + << std::endl; + for (const auto& header : web_request.headers) { + request_stream << header.first << ": " << header.second << std::endl; + } + request_stream << std::endl; + request_stream << "body size: " << request.GetBody().GetRawData().size() + << std::endl; + NEARBY_LOGS(VERBOSE) << request_stream.str(); } - callback(response); - NEARBY_LOGS(INFO) << __func__ << ": Completed request to url=" - << request.GetUrl().GetUrlPath(); - }); -} + absl::StatusOr web_response = + api::ImplementationPlatform::SendRequest(web_request); -absl::StatusOr NearbyHttpClient::GetResponse( - const HttpRequest& request) { - NEARBY_LOGS(INFO) << __func__ << ": Start request to url=" - << request.GetUrl().GetUrlPath(); - - absl::StatusOr response = InternalGetResponse(request); - if (response.ok()) { - NEARBY_LOGS(INFO) << __func__ << ": Got response from url=" - << request.GetUrl().GetUrlPath(); - } else { - NEARBY_LOGS(ERROR) << __func__ << ": Failed to get response from url=" - << request.GetUrl().GetUrlPath() << ", status" - << response.status(); - } - - return response; -} - -absl::StatusOr NearbyHttpClient::InternalGetResponse( - const HttpRequest& request) { - api::WebRequest web_request; - web_request.url = request.GetUrl().GetUrlPath(); - web_request.method = absl::StrCat(request.GetMethodString()); - for (const auto& header : request.GetAllHeaders()) { - for (const auto& value : header.second) { - web_request.headers.emplace(header.first, value); + if (!web_response.ok()) { + if (callback != nullptr) { + callback(web_response.status()); + } + return; } - } - web_request.body = absl::StrCat(request.GetBody().GetRawData()); - if (debug::kRequestEnabled) { - std::stringstream request_stream; - request_stream << "HTTP REQUEST====>" << std::endl; - request_stream << web_request.method << " " << web_request.url << std::endl; - for (const auto& header : web_request.headers) { - request_stream << header.first << ": " << header.second << std::endl; + if (debug::kResponseEnabled) { + std::stringstream response_stream; + response_stream << "HTTP RESPONSE====>" << std::endl; + response_stream << "url: " << web_request.url << std::endl; + response_stream << web_response->status_code << " " + << web_response->status_text << std::endl; + for (const auto& header : web_response->headers) { + response_stream << header.first << ": " << header.second << std::endl; + } + response_stream << std::endl; + response_stream << "body size: " << web_response->body.size() + << std::endl; + NEARBY_LOGS(VERBOSE) << response_stream.str(); } - request_stream << std::endl; - request_stream << "body size: " << request.GetBody().GetRawData().size() - << std::endl; - NEARBY_LOGS(VERBOSE) << request_stream.str(); - } - absl::StatusOr web_response = - api::ImplementationPlatform::SendRequest(web_request); + HttpResponse response; - if (!web_response.ok()) { - return web_response.status(); - } - - if (debug::kResponseEnabled) { - std::stringstream response_stream; - response_stream << "HTTP RESPONSE====>" << std::endl; - response_stream << "url: " << web_request.url << std::endl; - response_stream << web_response->status_code << " " - << web_response->status_text << std::endl; + response.SetStatusCode( + static_cast(web_response->status_code)); + response.SetReasonPhrase(web_response->status_text); for (const auto& header : web_response->headers) { - response_stream << header.first << ": " << header.second << std::endl; + response.AddHeader(header.first, header.second); + } + response.SetBody(web_response->body); + + if (callback != nullptr) { + callback(response); + } + }); + + http_threads_.push_back(std::move(http_thread)); +} + +void NearbyHttpClient::CleanThreads() { + auto it = http_threads_.begin(); + + while (it != http_threads_.end()) { + // Delete the thread if it is ready + auto status = it->wait_for(std::chrono::seconds(0)); + if (status == std::future_status::ready) { + it = http_threads_.erase(it); + } else { + ++it; } - response_stream << std::endl; - response_stream << "body size: " << web_response->body.size() << std::endl; - NEARBY_LOGS(VERBOSE) << response_stream.str(); } - - HttpResponse response; - - response.SetStatusCode( - static_cast(web_response->status_code)); - response.SetReasonPhrase(web_response->status_text); - for (const auto& header : web_response->headers) { - response.AddHeader(header.first, header.second); - } - response.SetBody(web_response->body); - - return response; } } // namespace network diff --git a/internal/network/http_client_impl.h b/internal/network/http_client_impl.h index 6a350927..d0e0646c 100644 --- a/internal/network/http_client_impl.h +++ b/internal/network/http_client_impl.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 Google LLC +// 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. @@ -16,20 +16,21 @@ #define THIRD_PARTY_NEARBY_INTERNAL_NETWORK_HTTP_CLIENT_IMPL_H_ #include -#include +#include // NOLINT +#include // NOLINT +#include +#include #include "absl/base/thread_annotations.h" -#include "absl/status/statusor.h" +#include "absl/synchronization/mutex.h" #include "internal/network/http_client.h" -#include "internal/platform/multi_thread_executor.h" -#include "internal/platform/mutex.h" namespace nearby { namespace network { class NearbyHttpClient : public HttpClient { public: - NearbyHttpClient(); + NearbyHttpClient() = default; ~NearbyHttpClient() override = default; NearbyHttpClient(const NearbyHttpClient&) = default; @@ -37,19 +38,15 @@ class NearbyHttpClient : public HttpClient { NearbyHttpClient(NearbyHttpClient&&) = default; NearbyHttpClient& operator=(NearbyHttpClient&&) = default; - // Starts HTTP request in asynchronization mode. void StartRequest(const HttpRequest& request, std::function&)> callback) override ABSL_LOCKS_EXCLUDED(mutex_); - // Gets HTTP response in synchronization mode. - absl::StatusOr GetResponse(const HttpRequest& request) override; - private: - absl::StatusOr InternalGetResponse(const HttpRequest& request); + void CleanThreads() ABSL_SHARED_LOCKS_REQUIRED(mutex_); - Mutex mutex_; - std::unique_ptr network_executor_ = nullptr; + absl::Mutex mutex_; + std::vector> http_threads_ ABSL_GUARDED_BY(mutex_); }; } // namespace network diff --git a/internal/network/http_client_impl_test.cc b/internal/network/http_client_impl_test.cc index 887e2265..2f24e8ad 100644 --- a/internal/network/http_client_impl_test.cc +++ b/internal/network/http_client_impl_test.cc @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Google LLC +// 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. @@ -89,7 +89,7 @@ class NearbyHttpClientTest : public ::testing::Test { api::WebRequest GetWebRequest() { return api::GetContext()->web_request; } - absl::StatusOr GetResponseAsync( + absl::StatusOr GetResponse( absl::string_view url, HttpRequestMethod method, const std::multimap& headers, absl::string_view body) { @@ -121,28 +121,6 @@ class NearbyHttpClientTest : public ::testing::Test { return result; } - absl::StatusOr GetResponse( - absl::string_view url, HttpRequestMethod method, - const std::multimap& headers, - absl::string_view body) { - absl::StatusOr result; - absl::StatusOr request_url = Url::Create(url); - if (!request_url.ok()) { - return request_url.status(); - } - - HttpRequest request{request_url.value()}; - auto it = headers.begin(); - while (it != headers.end()) { - request.AddHeader(it->first, it->second); - ++it; - } - request.SetMethod(method); - request.SetBody(body); - - return client_.GetResponse(request); - } - void CheckHeader(const std::multimap& headers, absl::string_view key, absl::string_view expected_value) { auto it = headers.find(std::string(key)); @@ -168,8 +146,8 @@ namespace { TEST_F(NearbyHttpClientTest, TestGet) { MockResponse(HttpStatusCode::kHttpOk, "OK", {{"Content_Type", "text/html"}}, "web content"); - auto result = GetResponseAsync("http://www.google.com", - HttpRequestMethod::kGet, {}, ""); + auto result = + GetResponse("http://www.google.com", HttpRequestMethod::kGet, {}, ""); // Checks request. api::WebRequest web_request = GetWebRequest(); @@ -187,8 +165,8 @@ TEST_F(NearbyHttpClientTest, TestGet) { TEST_F(NearbyHttpClientTest, TestGetWithQuery) { MockResponse(HttpStatusCode::kHttpOk, "OK", {{"Content_Type", "text/html"}}, "web content"); - auto result = GetResponseAsync("http://www.google.com?name=name1&age=36", - HttpRequestMethod::kGet, {}, ""); + auto result = GetResponse("http://www.google.com?name=name1&age=36", + HttpRequestMethod::kGet, {}, ""); // Checks request. api::WebRequest web_request = GetWebRequest(); @@ -202,8 +180,8 @@ TEST_F(NearbyHttpClientTest, TestGetWithQuery) { TEST_F(NearbyHttpClientTest, TestGetWithErrorResult) { MockFailedResponse(absl::InternalError("no connection.")); - auto result = GetResponseAsync("http://www.google.com?name=name1&age=36", - HttpRequestMethod::kGet, {}, ""); + auto result = GetResponse("http://www.google.com?name=name1&age=36", + HttpRequestMethod::kGet, {}, ""); // Checks request. api::WebRequest web_request = GetWebRequest(); @@ -214,24 +192,6 @@ TEST_F(NearbyHttpClientTest, TestGetWithErrorResult) { EXPECT_FALSE(result.ok()); } -TEST_F(NearbyHttpClientTest, TestPostAsync) { - MockResponse(HttpStatusCode::kHttpNoContent, "OK", - {{"Content_Type", "text/html"}}, ""); - auto result = GetResponseAsync("http://www.google.com", - HttpRequestMethod::kPost, {}, ""); - - // Checks request. - api::WebRequest web_request = GetWebRequest(); - EXPECT_EQ(web_request.url, "http://www.google.com"); - EXPECT_EQ(web_request.method, "POST"); - - // Checks response. - ASSERT_TRUE(result.ok()); - EXPECT_EQ(result->GetStatusCode(), HttpStatusCode::kHttpNoContent); - HttpResponseBody body = result->GetBody(); - EXPECT_TRUE(body.empty()); -} - TEST_F(NearbyHttpClientTest, TestPost) { MockResponse(HttpStatusCode::kHttpNoContent, "OK", {{"Content_Type", "text/html"}}, ""); @@ -250,12 +210,12 @@ TEST_F(NearbyHttpClientTest, TestPost) { EXPECT_TRUE(body.empty()); } -TEST_F(NearbyHttpClientTest, TestPostWithHeaderAsync) { +TEST_F(NearbyHttpClientTest, TestPostWithHeader) { MockResponse(HttpStatusCode::kHttpNoContent, "OK", {{"Content_Type", "text/html"}}, ""); auto result = - GetResponseAsync("http://www.google.com", HttpRequestMethod::kPost, - {{"Content_Type", "text/json"}, {"size", "596"}}, ""); + GetResponse("http://www.google.com", HttpRequestMethod::kPost, + {{"Content_Type", "text/json"}, {"size", "596"}}, ""); // Checks request. api::WebRequest web_request = GetWebRequest(); @@ -271,11 +231,11 @@ TEST_F(NearbyHttpClientTest, TestPostWithHeaderAsync) { EXPECT_EQ(result->GetBody().GetRawData(), ""); } -TEST_F(NearbyHttpClientTest, TestPostWithErrorResultAsync) { +TEST_F(NearbyHttpClientTest, TestPostWithErrorResult) { MockFailedResponse(absl::UnauthenticatedError("no user.")); auto result = - GetResponseAsync("http://www.google.com", HttpRequestMethod::kPost, - {{"Content_Type", "text/json"}, {"size", "596"}}, ""); + GetResponse("http://www.google.com", HttpRequestMethod::kPost, + {{"Content_Type", "text/json"}, {"size", "596"}}, ""); // Checks request. api::WebRequest web_request = GetWebRequest(); @@ -289,11 +249,11 @@ TEST_F(NearbyHttpClientTest, TestPostWithErrorResultAsync) { ASSERT_FALSE(result.ok()); } -TEST_F(NearbyHttpClientTest, TestRequestWithCleanThreadsAsync) { +TEST_F(NearbyHttpClientTest, TestRequestWithCleanThreads) { MockResponse(HttpStatusCode::kHttpOk, "OK", {{"Content_Type", "text/html"}}, "web content"); - auto result = GetResponseAsync("http://www.google.com", - HttpRequestMethod::kGet, {}, ""); + auto result = + GetResponse("http://www.google.com", HttpRequestMethod::kGet, {}, ""); // Checks request. api::WebRequest web_request = GetWebRequest(); @@ -303,8 +263,8 @@ TEST_F(NearbyHttpClientTest, TestRequestWithCleanThreadsAsync) { // Checks response. ASSERT_TRUE(result.ok()); - result = GetResponseAsync("http://www.youtube.com", HttpRequestMethod::kGet, - {}, ""); + result = + GetResponse("http://www.youtube.com", HttpRequestMethod::kGet, {}, ""); ASSERT_TRUE(result.ok()); } diff --git a/internal/platform/BUILD b/internal/platform/BUILD index aa8ab327..e8107092 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -348,7 +348,6 @@ cc_library( "//fastpair:__subpackages__", "//internal/base:__subpackages__", "//internal/flags:__subpackages__", - "//internal/network:__subpackages__", "//internal/platform/implementation/windows:__subpackages__", "//internal/preferences:__subpackages__", "//internal/test:__subpackages__", From 560df8ea8ea8fa2f46b525c744b21c43e04769e6 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Mon, 1 May 2023 11:57:16 -0700 Subject: [PATCH 54/63] Implement encoding/decoding of actions PiperOrigin-RevId: 528534899 --- internal/platform/ble_connection_info.cc | 23 +-- internal/platform/ble_connection_info.h | 9 +- internal/platform/ble_connection_info_test.cc | 191 ++---------------- .../platform/bluetooth_connection_info.cc | 27 +-- internal/platform/bluetooth_connection_info.h | 9 +- .../bluetooth_connection_info_test.cc | 112 ++-------- internal/platform/connection_info.h | 5 +- internal/platform/connection_info_test.cc | 38 +++- internal/platform/wifi_lan_connection_info.cc | 27 ++- internal/platform/wifi_lan_connection_info.h | 9 +- .../platform/wifi_lan_connection_info_test.cc | 154 ++------------ presence/presence_device.cc | 8 +- presence/presence_device_test.cc | 7 +- 13 files changed, 143 insertions(+), 476 deletions(-) diff --git a/internal/platform/ble_connection_info.cc b/internal/platform/ble_connection_info.cc index 1f4b573e..e5b0e611 100644 --- a/internal/platform/ble_connection_info.cc +++ b/internal/platform/ble_connection_info.cc @@ -15,10 +15,10 @@ #include "internal/platform/ble_connection_info.h" #include +#include #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "internal/platform/connection_info.h" @@ -41,22 +41,22 @@ std::string BleConnectionInfo::ToDataElementBytes() const { mask |= has_psm ? kPsmMask : 0; payload_data.push_back(mask); if (has_mac) { - payload_data.insert(payload_data.end(), mac_address_.begin(), + payload_data.append(mac_address_.begin(), mac_address_.end()); } if (has_gatt) { payload_data.push_back(gatt_characteristic_.length()); - payload_data.insert(payload_data.end(), gatt_characteristic_.begin(), + payload_data.append(gatt_characteristic_.begin(), gatt_characteristic_.end()); } if (has_psm) { - payload_data.insert(payload_data.end(), psm_.begin(), psm_.end()); + payload_data.append(psm_.begin(), psm_.end()); } - payload_data.push_back(actions_); + payload_data.append(actions_.begin(), actions_.end()); std::string ret; ret.push_back(kDataElementFieldType); ret.push_back(payload_data.size()); - ret.insert(ret.end(), payload_data.begin(), payload_data.end()); + ret.append(payload_data.begin(), payload_data.end()); return ret; } @@ -111,12 +111,9 @@ absl::StatusOr BleConnectionInfo::FromDataElementBytes( return absl::InvalidArgumentError( "Insufficient remaining bytes to read action."); } - char action = bytes[position]; - // Check that we don't have any remaining bytes. - if (bytes.size() != ++position) { - return absl::InvalidArgumentError(absl::StrFormat( - "Nonzero remaining bytes: %d.", bytes.size() - position)); - } - return BleConnectionInfo(address, characteristic, psm, action); + auto action_str = bytes.substr(position); + return BleConnectionInfo( + address, characteristic, psm, + std::vector(action_str.begin(), action_str.end())); } } // namespace nearby diff --git a/internal/platform/ble_connection_info.h b/internal/platform/ble_connection_info.h index fee467fe..db5f7dc8 100644 --- a/internal/platform/ble_connection_info.h +++ b/internal/platform/ble_connection_info.h @@ -16,6 +16,7 @@ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_BLE_CONNECTION_INFO_H_ #include +#include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" @@ -31,7 +32,7 @@ class BleConnectionInfo : public ConnectionInfo { BleConnectionInfo(absl::string_view mac_address, absl::string_view gatt_characteristic, - absl::string_view psm, char actions) + absl::string_view psm, std::vector actions) : mac_address_(std::string(mac_address)), gatt_characteristic_(std::string(gatt_characteristic)), psm_(std::string(psm)), @@ -45,18 +46,18 @@ class BleConnectionInfo : public ConnectionInfo { std::string GetMacAddress() const { return mac_address_; } std::string GetGattCharacteristic() const { return gatt_characteristic_; } std::string GetPsm() const { return psm_; } - char GetActions() const override { return actions_; } + std::vector GetActions() const override { return actions_; } private: std::string mac_address_; std::string gatt_characteristic_; std::string psm_; - char actions_ = 0; + std::vector actions_; }; inline bool operator==(const BleConnectionInfo& a, const BleConnectionInfo& b) { return a.GetMacAddress() == b.GetMacAddress() && - a.GetActions() == b.GetActions() && + a.GetActions() == b.GetActions() && a.GetPsm() == b.GetPsm() && a.GetGattCharacteristic() == b.GetGattCharacteristic(); } diff --git a/internal/platform/ble_connection_info_test.cc b/internal/platform/ble_connection_info_test.cc index 99a98f56..e27f2bd6 100644 --- a/internal/platform/ble_connection_info_test.cc +++ b/internal/platform/ble_connection_info_test.cc @@ -38,10 +38,11 @@ constexpr absl::string_view kPsm = "\x45\x56"; constexpr char kAction = 0x0F; TEST(BleConnectionInfoTest, TestGetFields) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, {kAction}); EXPECT_EQ(info.GetMediumType(), Medium::BLE); EXPECT_EQ(info.GetGattCharacteristic(), kGattCharacteristic); - EXPECT_EQ(info.GetActions(), kAction); + ASSERT_EQ(info.GetActions().size(), 1); + ASSERT_EQ(info.GetActions()[0], kAction); EXPECT_EQ(info.GetMacAddress(), kMacAddr); EXPECT_EQ(info.GetPsm(), kPsm); } @@ -57,7 +58,7 @@ TEST(BleConnectionInfoTest, TestFromInvalidBytes) { } TEST(BleConnectionInfoTest, TestFromNoAction) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, {kAction}); std::string serialized = info.ToDataElementBytes(); serialized[1] -= 1; auto result = BleConnectionInfo::FromDataElementBytes( @@ -66,7 +67,7 @@ TEST(BleConnectionInfoTest, TestFromNoAction) { } TEST(BleConnectionInfoTest, TestToFromBytes) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BleConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -78,7 +79,7 @@ TEST(BleConnectionInfoTest, TestToFromBytes) { } TEST(BleConnectionInfoTest, TestToFromBytesNoGattCharacteristic) { - BleConnectionInfo info(kMacAddr, "", kPsm, kAction); + BleConnectionInfo info(kMacAddr, "", kPsm, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BleConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -90,7 +91,7 @@ TEST(BleConnectionInfoTest, TestToFromBytesNoGattCharacteristic) { } TEST(BleConnectionInfoTest, TestToFromBytesNoMac) { - BleConnectionInfo info("", kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info("", kGattCharacteristic, kPsm, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BleConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -103,7 +104,7 @@ TEST(BleConnectionInfoTest, TestToFromBytesNoMac) { TEST(BleConnectionInfoTest, TestToFromBytesLongMac) { BleConnectionInfo info(absl::StrCat(kMacAddr, kMacAddr), kGattCharacteristic, - kPsm, kAction); + kPsm, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BleConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -115,7 +116,7 @@ TEST(BleConnectionInfoTest, TestToFromBytesLongMac) { } TEST(BleConnectionInfoTest, TestToFromBytesNoPsm) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, "", kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, "", {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BleConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -128,7 +129,7 @@ TEST(BleConnectionInfoTest, TestToFromBytesNoPsm) { TEST(BleConnectionInfoTest, TestToFromBytesLongPsm) { BleConnectionInfo info(kMacAddr, kGattCharacteristic, - absl::StrCat(kPsm, kPsm), kAction); + absl::StrCat(kPsm, kPsm), {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BleConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -145,186 +146,22 @@ TEST(BleConnectionInfoTest, TestFromEmpty) { } TEST(BleConnectionInfoTest, TestFromBadElementType) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, {kAction}); std::string serialized = info.ToDataElementBytes(); serialized[0] = 0x56; auto result = BleConnectionInfo::FromDataElementBytes(serialized); EXPECT_THAT(result, StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST(BleConnectionInfoTest, TestFromBadMask) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for MAC address only. - serialized[3] = 0x40; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic only. - serialized[3] = 0x20; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for PSM only. - serialized[3] = 0x10; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for MAC address + GATT characteristic. - serialized[3] = 0x60; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic + PSM. - serialized[3] = 0x30; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for MAC address and PSM. - serialized[3] = 0x50; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x70; - EXPECT_OK(BleConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BleConnectionInfoTest, TestFromBadMaskNoMac) { - BleConnectionInfo info("", kGattCharacteristic, kPsm, kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for MAC address only. - serialized[3] = 0x40; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic only. - serialized[3] = 0x20; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for PSM only. - serialized[3] = 0x10; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for MAC address + GATT characteristic. - serialized[3] = 0x60; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for MAC address + PSM. - serialized[3] = 0x50; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x30; - EXPECT_OK(BleConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BleConnectionInfoTest, TestFromBadMaskNoGattCharacteristic) { - BleConnectionInfo info(kMacAddr, "", kPsm, kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for MAC address only. - serialized[3] = 0x40; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic only. - serialized[3] = 0x20; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for PSM only. - serialized[3] = 0x10; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for all fields. - serialized[3] = 0x70; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for MAC address + GATT characteristic. - serialized[3] = 0x60; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic + PSM. - serialized[3] = 0x30; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x50; - EXPECT_OK(BleConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BleConnectionInfoTest, TestFromBadMaskNoPsm) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, "", kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for MAC address only. - serialized[3] = 0x40; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic only. - serialized[3] = 0x20; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for PSM only. - serialized[3] = 0x10; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for all fields. - serialized[3] = 0x70; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic + PSM. - serialized[3] = 0x30; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for MAC address + PSM. - serialized[3] = 0x50; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x60; - EXPECT_OK(BleConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BleConnectionInfoTest, TestFromBadMaskEmpty) { - BleConnectionInfo info("", "", "", kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for MAC address only. - serialized[3] = 0x40; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for GATT characteristic only. - serialized[3] = 0x20; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for PSM only. - serialized[3] = 0x10; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for all fields. - serialized[3] = 0x70; - EXPECT_THAT(BleConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with correct mask. - serialized[3] = 0x00; - EXPECT_OK(BleConnectionInfo::FromDataElementBytes(serialized)); -} - TEST(BleConnectionInfoTest, TestCopy) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, {kAction}); BleConnectionInfo copy(info); EXPECT_EQ(info, copy); } TEST(BleConnectionInfoTest, TestEquals) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); - BleConnectionInfo info2(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, {kAction}); + BleConnectionInfo info2(kMacAddr, kGattCharacteristic, kPsm, {kAction}); EXPECT_EQ(info, info2); } diff --git a/internal/platform/bluetooth_connection_info.cc b/internal/platform/bluetooth_connection_info.cc index ac4512a4..18d2a284 100644 --- a/internal/platform/bluetooth_connection_info.cc +++ b/internal/platform/bluetooth_connection_info.cc @@ -15,10 +15,10 @@ #include "internal/platform/bluetooth_connection_info.h" #include +#include #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "internal/platform/connection_info.h" @@ -37,19 +37,17 @@ std::string BluetoothConnectionInfo::ToDataElementBytes() const { mask |= has_bluetooth_uuid ? kBluetoothUuidMask : 0; payload_data.push_back(mask); if (has_mac) { - payload_data.insert(payload_data.end(), mac_address_.begin(), - mac_address_.end()); + payload_data.append(mac_address_.begin(), mac_address_.end()); } if (has_bluetooth_uuid) { - payload_data.insert(payload_data.end(), bluetooth_uuid_.begin(), - bluetooth_uuid_.end()); + payload_data.append(bluetooth_uuid_.begin(), bluetooth_uuid_.end()); } - payload_data.push_back(actions_); + payload_data.append(actions_.begin(), actions_.end()); std::string ret; ret.push_back(kDataElementFieldType); ret.push_back(payload_data.size()); - ret.insert(ret.end(), payload_data.begin(), payload_data.end()); - return std::string(ret.data(), ret.size()); + ret.append(payload_data.begin(), payload_data.end()); + return ret; } absl::StatusOr @@ -90,14 +88,11 @@ BluetoothConnectionInfo::FromDataElementBytes(absl::string_view bytes) { } if (bytes.size() == position) { return absl::InvalidArgumentError( - "Insufficient remaining bytes to read action."); + "Insufficient remaining bytes to read actions."); } - char action = bytes[position]; - // Check that we don't have any remaining bytes. - if (bytes.size() != ++position) { - return absl::InvalidArgumentError(absl::StrFormat( - "Nonzero remaining bytes: %d.", bytes.size() - position)); - } - return BluetoothConnectionInfo(address, uuid, action); + auto action_str = bytes.substr(position); + return BluetoothConnectionInfo( + address, uuid, + std::vector(action_str.begin(), action_str.end())); } } // namespace nearby diff --git a/internal/platform/bluetooth_connection_info.h b/internal/platform/bluetooth_connection_info.h index 82afe528..838510e4 100644 --- a/internal/platform/bluetooth_connection_info.h +++ b/internal/platform/bluetooth_connection_info.h @@ -15,7 +15,9 @@ #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_BLUETOOTH_CONNECTION_INFO_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_BLUETOOTH_CONNECTION_INFO_H_ +#include #include +#include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" @@ -30,7 +32,8 @@ class BluetoothConnectionInfo : public ConnectionInfo { absl::string_view bytes); BluetoothConnectionInfo(absl::string_view mac_address, - absl::string_view bluetooth_uuid, char actions) + absl::string_view bluetooth_uuid, + std::vector actions) : mac_address_(std::string(mac_address)), bluetooth_uuid_(std::string(bluetooth_uuid)), actions_(actions) {} @@ -42,12 +45,12 @@ class BluetoothConnectionInfo : public ConnectionInfo { std::string ToDataElementBytes() const override; std::string GetMacAddress() const { return mac_address_; } std::string GetBluetoothUuid() const { return bluetooth_uuid_; } - char GetActions() const override { return actions_; } + std::vector GetActions() const override { return actions_; } private: std::string mac_address_; std::string bluetooth_uuid_; - char actions_; + std::vector actions_; }; inline bool operator==(const BluetoothConnectionInfo& a, diff --git a/internal/platform/bluetooth_connection_info_test.cc b/internal/platform/bluetooth_connection_info_test.cc index 592b7a2e..072731d9 100644 --- a/internal/platform/bluetooth_connection_info_test.cc +++ b/internal/platform/bluetooth_connection_info_test.cc @@ -35,21 +35,22 @@ constexpr absl::string_view kBluetoothUuid{"test"}; constexpr char kAction = 0x0F; TEST(BluetoothConnectionInfoTest, TestGetFields) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, {kAction}); EXPECT_EQ(info.GetMediumType(), Medium::BLUETOOTH); EXPECT_EQ(info.GetMacAddress(), kMacAddr); - EXPECT_EQ(info.GetActions(), kAction); + ASSERT_EQ(info.GetActions().size(), 1); + EXPECT_EQ(info.GetActions()[0], kAction); EXPECT_EQ(info.GetBluetoothUuid(), kBluetoothUuid); } TEST(BluetoothConnectionInfoTest, TestGetLongMacAddr) { BluetoothConnectionInfo info(absl::StrCat(kMacAddr, "\x56\x70\x89"), - kBluetoothUuid, kAction); + kBluetoothUuid, {kAction}); EXPECT_NE(info.GetMacAddress(), kMacAddr); } TEST(BluetoothConnectionInfoTest, TestToFromBytes) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BluetoothConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -57,18 +58,19 @@ TEST(BluetoothConnectionInfoTest, TestToFromBytes) { } TEST(BluetoothConnectionInfoTest, TestToFromNoMacAddress) { - BluetoothConnectionInfo info("", kBluetoothUuid, kAction); + BluetoothConnectionInfo info("", kBluetoothUuid, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BluetoothConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); info = result.value(); EXPECT_EQ(info.GetMacAddress(), ""); EXPECT_EQ(info.GetBluetoothUuid(), kBluetoothUuid); - EXPECT_EQ(info.GetActions(), kAction); + ASSERT_EQ(info.GetActions().size(), 1); + EXPECT_EQ(info.GetActions()[0], kAction); } TEST(BluetoothConnectionInfoTest, TestToFromWrongLength) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, {kAction}); std::string serialized = info.ToDataElementBytes(); ++serialized[1]; auto result = BluetoothConnectionInfo::FromDataElementBytes(serialized); @@ -76,7 +78,7 @@ TEST(BluetoothConnectionInfoTest, TestToFromWrongLength) { } TEST(BluetoothConnectionInfoTest, TestToFromNoBluetoothUuid) { - BluetoothConnectionInfo info(kMacAddr, "", kAction); + BluetoothConnectionInfo info(kMacAddr, "", {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = BluetoothConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -89,7 +91,7 @@ TEST(BluetoothConnectionInfoTest, TestFromEmptyBytes) { } TEST(BluetoothConnectionInfoTest, TestFromNoAction) { - BluetoothConnectionInfo info("", "", kAction); + BluetoothConnectionInfo info("", "", {kAction}); std::string serialized = info.ToDataElementBytes(); serialized[1] -= 1; auto result = BluetoothConnectionInfo::FromDataElementBytes( @@ -103,106 +105,22 @@ TEST(BluetoothConnectionInfoTest, TestFromInvalidBytes) { } TEST(BluetoothConnectionInfoTest, TestFromBadElementType) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, {kAction}); std::string serialized = info.ToDataElementBytes(); serialized[0] = 0x56; auto result = BluetoothConnectionInfo::FromDataElementBytes(serialized); EXPECT_THAT(result, StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST(BluetoothConnectionInfoTest, TestFromBadMask) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); - std::string serialized = info.ToDataElementBytes(); - // Remove the mask for UUID. - serialized[3] = 0x40; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove the mask for MAC address and add back UUID. - serialized[3] = 0x20; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set empty mask. - serialized[3] = 0x00; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x60; - EXPECT_OK(BluetoothConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BluetoothConnectionInfoTest, TestFromBadMaskNoUuid) { - BluetoothConnectionInfo info(kMacAddr, "", kAction); - std::string serialized = info.ToDataElementBytes(); - // Set the mask for UUID and MAC address. - serialized[3] = 0x60; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set the mask for only UUID. - serialized[3] = 0x20; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set empty mask. - serialized[3] = 0x00; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x40; - EXPECT_OK(BluetoothConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BluetoothConnectionInfoTest, TestFromBadMaskNoMac) { - BluetoothConnectionInfo info("", kBluetoothUuid, kAction); - std::string serialized = info.ToDataElementBytes(); - // Set the mask for UUID and MAC address. - serialized[3] = 0x60; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set the mask for only MAC address. - serialized[3] = 0x40; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set empty mask. - serialized[3] = 0x00; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x20; - EXPECT_OK(BluetoothConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(BluetoothConnectionInfoTest, TestFromBadMaskEmpty) { - BluetoothConnectionInfo info("", "", kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for UUID and MAC address. - serialized[3] = 0x60; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for only UUID. - serialized[3] = 0x20; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for only MAC address. - serialized[3] = 0x40; - EXPECT_THAT(BluetoothConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with correct mask. - serialized[3] = 0x00; - EXPECT_OK(BluetoothConnectionInfo::FromDataElementBytes(serialized)); -} - TEST(BluetoothConnectionInfoTest, TestCopy) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, {kAction}); BluetoothConnectionInfo copy(info); EXPECT_EQ(info, copy); } TEST(BluetoothConnectionInfoTest, TestEquals) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); - BluetoothConnectionInfo info2(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, {kAction}); + BluetoothConnectionInfo info2(kMacAddr, kBluetoothUuid, {kAction}); EXPECT_EQ(info, info2); } diff --git a/internal/platform/connection_info.h b/internal/platform/connection_info.h index 804de0ad..bb102354 100644 --- a/internal/platform/connection_info.h +++ b/internal/platform/connection_info.h @@ -15,8 +15,11 @@ #ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_CONNECTION_INFO_H_ #define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_CONNECTION_INFO_H_ +#include #include +#include +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/variant.h" #include "proto/connections_enums.pb.h" @@ -43,7 +46,7 @@ class ConnectionInfo { virtual ::location::nearby::proto::connections::Medium GetMediumType() const = 0; virtual std::string ToDataElementBytes() const = 0; - virtual char GetActions() const = 0; + virtual std::vector GetActions() const = 0; static ConnectionInfoVariant FromDataElementBytes( absl::string_view data_element_bytes); }; diff --git a/internal/platform/connection_info_test.cc b/internal/platform/connection_info_test.cc index caae8034..ff4a6372 100644 --- a/internal/platform/connection_info_test.cc +++ b/internal/platform/connection_info_test.cc @@ -14,11 +14,16 @@ #include "internal/platform/connection_info.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/strings/string_view.h" +#include "absl/types/variant.h" #include "internal/platform/ble_connection_info.h" #include "internal/platform/bluetooth_connection_info.h" #include "internal/platform/wifi_lan_connection_info.h" @@ -26,12 +31,14 @@ namespace nearby { namespace { +// Common +constexpr uint8_t kFirstAction = 0x0F; +constexpr uint8_t kSecondAction = 0x04; // BLE constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; constexpr absl::string_view kGattCharacteristic = "\x03\x0a\x13\x56\x67\x21\x12\x45"; constexpr absl::string_view kPsm = "\x45\x56"; -constexpr char kAction = 0x0F; // Bluetooth constexpr absl::string_view kBluetoothUuid{"test"}; // WLAN @@ -39,8 +46,13 @@ constexpr absl::string_view kIpv4Addr = "\x4C\x8B\x1D\xCE"; constexpr absl::string_view kPort = "\x12\x34"; constexpr absl::string_view kBssid = "\x0A\x1B\x2C\x34\x58\x7E"; +std::vector GetDefaultActions() { + return {kFirstAction, kSecondAction}; +} + TEST(ConnectionInfoTest, TestRestoreBle) { - BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, kAction); + BleConnectionInfo info(kMacAddr, kGattCharacteristic, kPsm, + GetDefaultActions()); auto serialized = info.ToDataElementBytes(); auto connection_info = ConnectionInfo::FromDataElementBytes(serialized); ASSERT_TRUE(absl::holds_alternative(connection_info)); @@ -49,7 +61,7 @@ TEST(ConnectionInfoTest, TestRestoreBle) { } TEST(ConnectionInfoTest, TestRestoreBluetooth) { - BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, kAction); + BluetoothConnectionInfo info(kMacAddr, kBluetoothUuid, GetDefaultActions()); auto serialized = info.ToDataElementBytes(); auto connection_info = ConnectionInfo::FromDataElementBytes(serialized); ASSERT_TRUE( @@ -59,7 +71,7 @@ TEST(ConnectionInfoTest, TestRestoreBluetooth) { } TEST(ConnectionInfoTest, TestRestoreMdns) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, GetDefaultActions()); auto serialized = info.ToDataElementBytes(); auto connection_info = ConnectionInfo::FromDataElementBytes(serialized); ASSERT_TRUE(absl::holds_alternative(connection_info)); @@ -68,9 +80,12 @@ TEST(ConnectionInfoTest, TestRestoreMdns) { } TEST(ConnectionInfoTest, TestMonostate) { - WifiLanConnectionInfo wifi_info(kIpv4Addr, kPort, kBssid, kAction); - BluetoothConnectionInfo bt_info(kMacAddr, kBluetoothUuid, kAction); - BleConnectionInfo ble_info(kMacAddr, kGattCharacteristic, kPsm, kAction); + WifiLanConnectionInfo wifi_info(kIpv4Addr, kPort, kBssid, + GetDefaultActions()); + BluetoothConnectionInfo bt_info(kMacAddr, kBluetoothUuid, + GetDefaultActions()); + BleConnectionInfo ble_info(kMacAddr, kGattCharacteristic, kPsm, + GetDefaultActions()); std::vector infos = {&bt_info, &ble_info, &wifi_info}; for (auto info : infos) { auto serialized = info->ToDataElementBytes(); @@ -81,9 +96,12 @@ TEST(ConnectionInfoTest, TestMonostate) { } TEST(ConnectionInfoTest, TestCannotRestoreAsOtherInfos) { - WifiLanConnectionInfo wifi_info(kIpv4Addr, kPort, kBssid, kAction); - BluetoothConnectionInfo bt_info(kMacAddr, kBluetoothUuid, kAction); - BleConnectionInfo ble_info(kMacAddr, kGattCharacteristic, kPsm, kAction); + WifiLanConnectionInfo wifi_info(kIpv4Addr, kPort, kBssid, + GetDefaultActions()); + BluetoothConnectionInfo bt_info(kMacAddr, kBluetoothUuid, + GetDefaultActions()); + BleConnectionInfo ble_info(kMacAddr, kGattCharacteristic, kPsm, + GetDefaultActions()); EXPECT_THAT( BleConnectionInfo::FromDataElementBytes(wifi_info.ToDataElementBytes()), testing::status::StatusIs(absl::StatusCode::kInvalidArgument)); diff --git a/internal/platform/wifi_lan_connection_info.cc b/internal/platform/wifi_lan_connection_info.cc index 361ddabe..424f2396 100644 --- a/internal/platform/wifi_lan_connection_info.cc +++ b/internal/platform/wifi_lan_connection_info.cc @@ -15,12 +15,13 @@ #include "internal/platform/wifi_lan_connection_info.h" #include +#include #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "internal/platform/connection_info.h" +#include "internal/platform/logging.h" namespace nearby { namespace { @@ -42,19 +43,18 @@ std::string WifiLanConnectionInfo::ToDataElementBytes() const { mask |= has_bssid ? kBssidMask : 0; payload_data.push_back(mask); if (has_ipv4 || has_ipv6) { - payload_data.insert(payload_data.end(), ip_address_.begin(), - ip_address_.end()); + payload_data.append(ip_address_.begin(), ip_address_.end()); } - payload_data.insert(payload_data.end(), port_.begin(), port_.end()); + payload_data.append(port_.begin(), port_.end()); if (has_bssid) { - payload_data.insert(payload_data.end(), bssid_.begin(), bssid_.end()); + payload_data.append(bssid_.begin(), bssid_.end()); } - payload_data.push_back(actions_); + payload_data.append(actions_.begin(), actions_.end()); std::string ret; ret.push_back(kDataElementFieldType); ret.push_back(payload_data.size()); - ret.insert(ret.end(), payload_data.begin(), payload_data.end()); - return std::string(ret.data(), ret.size()); + ret.append(payload_data.begin(), payload_data.end()); + return ret; } absl::StatusOr @@ -121,13 +121,10 @@ WifiLanConnectionInfo::FromDataElementBytes(absl::string_view bytes) { return absl::InvalidArgumentError( "Insufficient remaining bytes to read action."); } - char action = bytes[position]; - // Check that we don't have any remaining bytes. - if (bytes.size() != ++position) { - return absl::InvalidArgumentError(absl::StrFormat( - "Nonzero remaining bytes: %d.", bytes.size() - position)); - } - return WifiLanConnectionInfo(address, port, bssid, action); + auto action_str = bytes.substr(position); + return WifiLanConnectionInfo( + address, port, bssid, + std::vector(action_str.begin(), action_str.end())); } } // namespace nearby diff --git a/internal/platform/wifi_lan_connection_info.h b/internal/platform/wifi_lan_connection_info.h index 46a14a2c..32c58ca2 100644 --- a/internal/platform/wifi_lan_connection_info.h +++ b/internal/platform/wifi_lan_connection_info.h @@ -17,6 +17,7 @@ #include #include +#include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" @@ -36,10 +37,10 @@ class WifiLanConnectionInfo : public ConnectionInfo { absl::string_view bytes); WifiLanConnectionInfo(absl::string_view ip_address, absl::string_view port, - char actions) + std::vector actions) : ip_address_(ip_address), port_(port), bssid_(""), actions_(actions) {} WifiLanConnectionInfo(absl::string_view ip_address, absl::string_view port, - absl::string_view bssid, char actions) + absl::string_view bssid, std::vector actions) : ip_address_(ip_address), port_(port), bssid_(std::string(bssid)), @@ -56,13 +57,13 @@ class WifiLanConnectionInfo : public ConnectionInfo { // order (aka big-endian), so \x12\x34 will correspond to port 4660 (0x1234). std::string GetPort() const { return port_; } std::string GetBssid() const { return bssid_; } - char GetActions() const override { return actions_; } + std::vector GetActions() const override { return actions_; } private: std::string ip_address_; std::string port_; std::string bssid_; - char actions_; + std::vector actions_; }; inline bool operator==(const WifiLanConnectionInfo& a, diff --git a/internal/platform/wifi_lan_connection_info_test.cc b/internal/platform/wifi_lan_connection_info_test.cc index d35b5cdd..3e5473c6 100644 --- a/internal/platform/wifi_lan_connection_info_test.cc +++ b/internal/platform/wifi_lan_connection_info_test.cc @@ -38,20 +38,21 @@ using ::testing::status::StatusIs; using Medium = ::location::nearby::proto::connections::Medium; TEST(WifiLanConnectionInfoTest, TestMediumType) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, {kAction}); EXPECT_EQ(info.GetMediumType(), Medium::WIFI_LAN); } TEST(WifiLanConnectionInfoTest, TestGetMembers) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); EXPECT_EQ(info.GetIpAddress(), kIpv4Addr); EXPECT_EQ(info.GetPort(), kPort); EXPECT_EQ(info.GetBssid(), kBssid); - EXPECT_EQ(info.GetActions(), kAction); + ASSERT_EQ(info.GetActions().size(), 1); + EXPECT_EQ(info.GetActions()[0], kAction); } TEST(WifiLanConnectionInfoTest, TestToFromBytesIpv4) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = WifiLanConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -59,7 +60,7 @@ TEST(WifiLanConnectionInfoTest, TestToFromBytesIpv4) { } TEST(WifiLanConnectionInfoTest, TestToFromBytesIpv6) { - WifiLanConnectionInfo info(kIpv6Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv6Addr, kPort, kBssid, {kAction}); std::string serialized = info.ToDataElementBytes(); auto result = WifiLanConnectionInfo::FromDataElementBytes(serialized); ASSERT_OK(result); @@ -67,19 +68,19 @@ TEST(WifiLanConnectionInfoTest, TestToFromBytesIpv6) { } TEST(WifiLanConnectionInfoTest, TestCopy) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); WifiLanConnectionInfo copy(info); EXPECT_EQ(info, copy); } TEST(WifiLanConnectionInfoTest, TestEquals) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); - WifiLanConnectionInfo info2(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); + WifiLanConnectionInfo info2(kIpv4Addr, kPort, kBssid, {kAction}); EXPECT_EQ(info, info2); } TEST(WifiLanConnectionInfoTest, TestFromNoAction) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); std::string serialized = info.ToDataElementBytes(); serialized[1] -= 1; auto result = WifiLanConnectionInfo::FromDataElementBytes( @@ -89,37 +90,40 @@ TEST(WifiLanConnectionInfoTest, TestFromNoAction) { TEST(WifiLanConnectionInfoTest, TestToFromShortBssid) { std::string shortBssid = "\x0A\x1B\x2C"; - WifiLanConnectionInfo info(kIpv4Addr, kPort, shortBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, shortBssid, {kAction}); auto bytes = info.ToDataElementBytes(); auto result = WifiLanConnectionInfo::FromDataElementBytes(bytes); ASSERT_OK(result); EXPECT_EQ(result->GetIpAddress(), kIpv4Addr); EXPECT_EQ(result->GetPort(), kPort); EXPECT_TRUE(result->GetBssid().empty()); - EXPECT_EQ(result->GetActions(), kAction); + ASSERT_EQ(result->GetActions().size(), 1); + EXPECT_EQ(result->GetActions()[0], kAction); } TEST(WifiLanConnectionInfoTest, TestToFromNoIp) { - WifiLanConnectionInfo info("", kPort, kBssid, kAction); + WifiLanConnectionInfo info("", kPort, kBssid, {kAction}); auto bytes = info.ToDataElementBytes(); auto result = WifiLanConnectionInfo::FromDataElementBytes(bytes); ASSERT_OK(result); EXPECT_TRUE(result->GetIpAddress().empty()); EXPECT_EQ(result->GetPort(), kPort); EXPECT_EQ(result->GetBssid(), kBssid); - EXPECT_EQ(result->GetActions(), kAction); + ASSERT_EQ(result->GetActions().size(), 1); + EXPECT_EQ(result->GetActions()[0], kAction); } TEST(WifiLanConnectionInfoTest, TestToFromLongIp) { WifiLanConnectionInfo info(absl::StrCat(kIpv4Addr, kIpv6Addr), kPort, kBssid, - kAction); + {kAction}); auto bytes = info.ToDataElementBytes(); auto result = WifiLanConnectionInfo::FromDataElementBytes(bytes); ASSERT_OK(result); EXPECT_TRUE(result->GetIpAddress().empty()); EXPECT_EQ(result->GetPort(), kPort); EXPECT_EQ(result->GetBssid(), kBssid); - EXPECT_EQ(result->GetActions(), kAction); + ASSERT_EQ(result->GetActions().size(), 1); + EXPECT_EQ(result->GetActions()[0], kAction); } TEST(WifiLanConnectionInfoTest, TestFromIp) { @@ -130,7 +134,7 @@ TEST(WifiLanConnectionInfoTest, TestFromIp) { } TEST(WifiLanConnectionInfoTest, TestBadBytesLength) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); std::string serialized = info.ToDataElementBytes(); std::string modified_short( serialized.substr(0, kIpv4AddressLength + kPortLength)); @@ -144,128 +148,12 @@ TEST(WifiLanConnectionInfoTest, TestBadBytesLength) { } TEST(WifiLanConnectionInfoTest, TestFromBadElementType) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, {kAction}); std::string serialized = info.ToDataElementBytes(); serialized[0] = 0x56; auto result = WifiLanConnectionInfo::FromDataElementBytes(serialized); EXPECT_THAT(result, StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST(WifiLanConnectionInfoTest, TestFromBadMaskIpv4) { - WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid, kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for IPV4 address only. - serialized[3] = 0x40; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV6 address only. - serialized[3] = 0x20; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for port only. - serialized[3] = 0x10; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for BSSID only. - serialized[3] = 0x08; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV4 + IPV6 addresses. - serialized[3] = 0x60; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV4 + port. - serialized[3] = 0x50; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV4 + BSSID. - serialized[3] = 0x48; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for all fields present. - serialized[3] = 0x78; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x58; - EXPECT_OK(WifiLanConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(WifiLanConnectionInfoTest, TestFromBadMaskIpv6) { - WifiLanConnectionInfo info(kIpv6Addr, kPort, kBssid, kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for IPV4 address only. - serialized[3] = 0x40; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV6 address only. - serialized[3] = 0x20; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for port only. - serialized[3] = 0x10; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for BSSID only. - serialized[3] = 0x08; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Remove all masks. - serialized[3] = 0x00; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV4 + IPV6 addresses. - serialized[3] = 0x60; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV6 + port. - serialized[3] = 0x30; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV6 + BSSID. - serialized[3] = 0x28; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for all fields present. - serialized[3] = 0x78; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with the correct mask. - serialized[3] = 0x38; - EXPECT_OK(WifiLanConnectionInfo::FromDataElementBytes(serialized)); -} - -TEST(WifiLanConnectionInfoTest, TestFromBadMaskEmpty) { - WifiLanConnectionInfo info("", "", "", kAction); - std::string serialized = info.ToDataElementBytes(); - // Set mask for IPV4 address only. - serialized[3] = 0x40; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for IPV6 address only. - serialized[3] = 0x20; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for port only. - serialized[3] = 0x10; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for BSSID only. - serialized[3] = 0x08; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Set mask for all fields. - serialized[3] = 0x78; - EXPECT_THAT(WifiLanConnectionInfo::FromDataElementBytes(serialized), - StatusIs(absl::StatusCode::kInvalidArgument)); - // Verify OK with correct mask. - serialized[3] = 0x00; - EXPECT_OK(WifiLanConnectionInfo::FromDataElementBytes(serialized)); -} - } // namespace } // namespace nearby diff --git a/presence/presence_device.cc b/presence/presence_device.cc index 2f9229a8..585d92c4 100644 --- a/presence/presence_device.cc +++ b/presence/presence_device.cc @@ -51,8 +51,14 @@ PresenceDevice::PresenceDevice(DeviceMotion device_motion, 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(metadata_.bluetooth_mac_address(), - /*gatt_characteristic=*/"", /*psm=*/"", 0)}; + /*gatt_characteristic=*/"", /*psm=*/"", + transformed_actions)}; } } // namespace presence } // namespace nearby diff --git a/presence/presence_device_test.cc b/presence/presence_device_test.cc index b6c1ff13..0ad5c8d5 100644 --- a/presence/presence_device_test.cc +++ b/presence/presence_device_test.cc @@ -72,13 +72,16 @@ TEST(PresenceDeviceTest, ExplicitInitNotEquals) { EXPECT_NE(device1, device2); } -TEST(PresenceDeviceTest, TestGetBluetoothAddress) { +TEST(PresenceDeviceTest, TestGetBleConnectionInfo) { Metadata metadata = CreateTestMetadata(); PresenceDevice device = PresenceDevice({kDefaultMotionType}, metadata); + device.AddAction(PresenceAction(kTestAction)); auto info = (device.GetConnectionInfos().at(0)); ASSERT_TRUE(absl::holds_alternative(info)); - EXPECT_EQ(absl::get(info).GetMacAddress(), + auto ble_info = absl::get(info); + EXPECT_EQ(ble_info.GetMacAddress(), kMacAddr); + EXPECT_EQ(ble_info.GetActions(), std::vector{kTestAction}); } TEST(PresenceDevicetest, TestGetAddExtendedProperties) { From 84f480fdd1cd7479f1390d93586b363b1bb15b40 Mon Sep 17 00:00:00 2001 From: Nick Bourdakos Date: Mon, 1 May 2023 14:19:12 -0700 Subject: [PATCH 55/63] Fix IP address bug where 4 byte version wasn't converted to dotted decimal form Introduces a tested `GNCIPAddress` class to make it more explicit of which IP address format is being used at call sites to prevent similar issues in the future. PiperOrigin-RevId: 528572993 --- internal/platform/implementation/apple/BUILD | 2 + .../implementation/apple/Mediums/BUILD | 2 + .../apple/Mediums/WiFiLAN/GNCIPv4Address.h | 60 +++++++++ .../apple/Mediums/WiFiLAN/GNCIPv4Address.m | 59 +++++++++ .../apple/Mediums/WiFiLAN/GNCWiFiLANMedium.h | 5 +- .../apple/Mediums/WiFiLAN/GNCWiFiLANMedium.m | 7 +- .../Mediums/WiFiLAN/GNCWiFiLANServerSocket.h | 5 +- .../Mediums/WiFiLAN/GNCWiFiLANServerSocket.m | 20 +-- .../platform/implementation/apple/Tests/BUILD | 9 +- .../apple/Tests/GNCIPAddressTest.mm | 114 ++++++++++++++++++ .../platform/implementation/apple/wifi_lan.mm | 12 +- 11 files changed, 272 insertions(+), 23 deletions(-) create mode 100644 internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h create mode 100644 internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.m create mode 100644 internal/platform/implementation/apple/Tests/GNCIPAddressTest.mm diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index a5d76eba..b52e1b0e 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -65,8 +65,10 @@ objc_library( "//third_party/apple_frameworks:Foundation", "//third_party/apple_frameworks:Network", "//third_party/objective_c/google_toolbox_for_mac:GTM_Logger", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", "@nlohmann_json//:json", diff --git a/internal/platform/implementation/apple/Mediums/BUILD b/internal/platform/implementation/apple/Mediums/BUILD index 649bd04f..e5ec3b9f 100644 --- a/internal/platform/implementation/apple/Mediums/BUILD +++ b/internal/platform/implementation/apple/Mediums/BUILD @@ -25,6 +25,7 @@ objc_library( "GNCLeaks.h", "GNCLeaks.m", "GNCMConnection.m", + "WiFiLAN/GNCIPv4Address.m", "WiFiLAN/GNCWiFiLANError.m", "WiFiLAN/GNCWiFiLANMedium.m", "WiFiLAN/GNCWiFiLANServerSocket.m", @@ -37,6 +38,7 @@ objc_library( "Ble/GNCMBlePeripheral.h", "Ble/GNCMBleUtils.h", "GNCMConnection.h", + "WiFiLAN/GNCIPv4Address.h", "WiFiLAN/GNCWiFiLANError.h", "WiFiLAN/GNCWiFiLANMedium.h", "WiFiLAN/GNCWiFiLANServerSocket.h", diff --git a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h new file mode 100644 index 00000000..6ffce1cc --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h @@ -0,0 +1,60 @@ +// 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 + +/** A container for IPv4 address information. */ +@interface GNCIPv4Address : NSObject + +/** + * @remark init is not an available initializer. + */ +- (nonnull instancetype)init NS_UNAVAILABLE; + +/** + * Creates a container for IPv4 address information. + * + * @param byte1 The first byte of the IP address. + * @param byte2 The second byte of the IP address. + * @param byte3 The third byte of the IP address. + * @param byte4 The forth byte of the IP address. + */ +- (nonnull instancetype)initWithByte1:(uint8_t)byte1 + byte2:(uint8_t)byte2 + byte3:(uint8_t)byte3 + byte4:(uint8_t)byte4 NS_DESIGNATED_INITIALIZER; + ++ (nonnull instancetype)addressFromFourByteInt:(uint32_t)address; + ++ (nonnull instancetype)addressFromData:(nonnull NSData *)address; + +/** The first byte of the IP address. */ +@property(nonatomic, readonly) uint8_t byte1; + +/** The second byte of the IP address. */ +@property(nonatomic, readonly) uint8_t byte2; + +/** The third byte of the IP address. */ +@property(nonatomic, readonly) uint8_t byte3; + +/** The forth byte of the IP address. */ +@property(nonatomic, readonly) uint8_t byte4; + +/** The 4 byte binary representation for the IPv4 address. */ +@property(nonatomic, nonnull, readonly) NSData *binaryRepresentation; + +/** The human readable dotted representation for the IPv4 address. */ +@property(nonatomic, nonnull, readonly) NSString *dottedRepresentation; + +@end diff --git a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.m b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.m new file mode 100644 index 00000000..3333dda7 --- /dev/null +++ b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.m @@ -0,0 +1,59 @@ +// 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/WiFiLAN/GNCIPv4Address.h" + +@implementation GNCIPv4Address + +- (instancetype)initWithByte1:(uint8_t)byte1 + byte2:(uint8_t)byte2 + byte3:(uint8_t)byte3 + byte4:(uint8_t)byte4 { + self = [super init]; + if (self) { + _byte1 = byte1; + _byte2 = byte2; + _byte3 = byte3; + _byte4 = byte4; + } + return self; +} + ++ (instancetype)addressFromFourByteInt:(uint32_t)address { + uint8_t byte1 = (address >> (8 * 0)) & 0xff; + uint8_t byte2 = (address >> (8 * 1)) & 0xff; + uint8_t byte3 = (address >> (8 * 2)) & 0xff; + uint8_t byte4 = (address >> (8 * 3)) & 0xff; + return [[GNCIPv4Address alloc] initWithByte1:byte1 byte2:byte2 byte3:byte3 byte4:byte4]; +} + ++ (instancetype)addressFromData:(NSData *)address { + NSAssert(address.length == 4, @"Address must be 4 bytes"); + const uint8_t *bytes = address.bytes; + return [[GNCIPv4Address alloc] initWithByte1:bytes[0] + byte2:bytes[1] + byte3:bytes[2] + byte4:bytes[3]]; +} + +- (NSData *)binaryRepresentation { + const uint8_t bytes[] = {_byte1, _byte2, _byte3, _byte4}; + return [NSData dataWithBytes:bytes length:4]; +} + +- (NSString *)dottedRepresentation { + return [NSString stringWithFormat:@"%d.%d.%d.%d", _byte1, _byte2, _byte3, _byte4]; +} + +@end diff --git a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.h b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.h index a6918f5a..9ac55431 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.h +++ b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.h @@ -14,6 +14,7 @@ #import +@class GNCIPv4Address; @class GNCWiFiLANServerSocket; @class GNCWiFiLANSocket; @@ -102,12 +103,12 @@ typedef void (^ServiceUpdateHandler)(NSString *_Nonnull serviceName, /** * Connects to an IP address and port. * - * @param host The 4 byte binary representation IPv4 address to connect to. + * @param host The IPv4 address to connect to. * @param port The port to connect to. * @param[out] error Error that will be populated on failure. * @return Returns a connected socket or nil if an error has occured. */ -- (nullable GNCWiFiLANSocket *)connectToHost:(nonnull NSString *)host +- (nullable GNCWiFiLANSocket *)connectToHost:(nonnull GNCIPv4Address *)host port:(NSInteger)port error:(NSError **_Nullable)error; diff --git a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.m b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.m index 202a95df..b1783208 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.m +++ b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.m @@ -17,6 +17,7 @@ #import #import +#import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANError.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket+Internal.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.h" @@ -258,9 +259,11 @@ NSDictionary *GNCTXTRecordForBrowseResult(nw_browse_resu return [self connectToEndpoint:endpoint error:error]; } -- (GNCWiFiLANSocket *)connectToHost:(NSString *)host port:(NSInteger)port error:(NSError **)error { +- (GNCWiFiLANSocket *)connectToHost:(GNCIPv4Address *)host + port:(NSInteger)port + error:(NSError **)error { nw_endpoint_t endpoint = - nw_endpoint_create_host([host UTF8String], [[@(port) stringValue] UTF8String]); + nw_endpoint_create_host(host.dottedRepresentation.UTF8String, @(port).stringValue.UTF8String); return [self connectToEndpoint:endpoint error:error]; } diff --git a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.h b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.h index 9acbc1c7..278193f5 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.h +++ b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.h @@ -14,6 +14,7 @@ #import +@class GNCIPv4Address; @class GNCWiFiLANSocket; @interface GNCWiFiLANServerSocket : NSObject @@ -31,9 +32,9 @@ - (nonnull instancetype)initWithPort:(NSInteger)port NS_DESIGNATED_INITIALIZER; /** - * The 4 byte binary representation for the IPv4 address of the physical network interface. + * The IPv4 address of the physical network interface. */ -@property(nonatomic, readonly, copy) NSString *ipAddress; +@property(nonatomic, readonly, copy) GNCIPv4Address *ipAddress; /** * The port of the server socket. diff --git a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.m b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.m index d4163457..66a6bac8 100644 --- a/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.m +++ b/internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.m @@ -22,6 +22,7 @@ #include #include +#import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANError.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket+Internal.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANSocket.h" @@ -71,7 +72,7 @@ @synthesize ipAddress = _ipAddress; -- (NSString *)ipAddress { +- (GNCIPv4Address *)ipAddress { if (!_ipAddress) { _ipAddress = [GNCWiFiLANServerSocket lookupIpAddress]; } @@ -235,7 +236,7 @@ * Returns the IP address as a 4 byte string. If not available, this returns an empty string to * align with the Windows implementation. */ -+ (NSString *)lookupIpAddress { ++ (GNCIPv4Address *)lookupIpAddress { struct ifaddrs *ifaddr; // Note: The data returned by `getifaddrs()` is dynamically allocated and should be freed using @@ -243,7 +244,7 @@ // // See: https://linux.die.net/man/3/getifaddrs if (getifaddrs(&ifaddr) == -1) { - return @""; + return [GNCIPv4Address addressFromFourByteInt:0]; } // Walk through linked list, maintaining head pointer so we can free list later. @@ -264,22 +265,13 @@ continue; } - // Break the 4 byte binary representation of the hostname into 4 separate bytes. uint32_t host = ((struct sockaddr_in *)address)->sin_addr.s_addr; - uint8_t byte1 = (host >> (8 * 0)) & 0xff; - uint8_t byte2 = (host >> (8 * 1)) & 0xff; - uint8_t byte3 = (host >> (8 * 2)) & 0xff; - uint8_t byte4 = (host >> (8 * 3)) & 0xff; - - // Join the bytes into a 4 character string. - NSString *hostString = [NSString stringWithFormat:@"%c%c%c%c", byte1, byte2, byte3, byte4]; - freeifaddrs(ifaddr); - return hostString; + return [GNCIPv4Address addressFromFourByteInt:host]; } freeifaddrs(ifaddr); - return @""; + return [GNCIPv4Address addressFromFourByteInt:0]; } @end diff --git a/internal/platform/implementation/apple/Tests/BUILD b/internal/platform/implementation/apple/Tests/BUILD index 21c91daf..16e7ef0d 100644 --- a/internal/platform/implementation/apple/Tests/BUILD +++ b/internal/platform/implementation/apple/Tests/BUILD @@ -26,6 +26,7 @@ objc_library( "GNCBleTest.mm", "GNCBluetoothAdapterTest.mm", "GNCCryptoTest.mm", + "GNCIPAddressTest.mm", "GNCMultiThreadExecutorTest.mm", "GNCScheduledExecutorTest.mm", "GNCSingleThreadExecutorTest.mm", @@ -33,9 +34,15 @@ objc_library( ], features = ["-layering_check"], deps = [ + "//internal/platform:base", + "//internal/platform/implementation:comm", + "//internal/platform/implementation:platform", + "//internal/platform/implementation:types", "//internal/platform/implementation/apple", - "//internal/platform/implementation/apple:Shared", + "//internal/platform/implementation/apple/Mediums", + "//third_party/apple_frameworks:Foundation", "//third_party/apple_frameworks:XCTest", + "@com_google_absl//absl/time", ], ) diff --git a/internal/platform/implementation/apple/Tests/GNCIPAddressTest.mm b/internal/platform/implementation/apple/Tests/GNCIPAddressTest.mm new file mode 100644 index 00000000..65166717 --- /dev/null +++ b/internal/platform/implementation/apple/Tests/GNCIPAddressTest.mm @@ -0,0 +1,114 @@ +// 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 +#import + +#include + +#import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h" + +@interface GNCIPv4AddressTest : XCTestCase +@end + +@implementation GNCIPv4AddressTest + +- (void)testInitFromIntWithZero { + GNCIPv4Address *address = [GNCIPv4Address addressFromFourByteInt:0]; + XCTAssertEqual(address.byte1, 0); + XCTAssertEqual(address.byte2, 0); + XCTAssertEqual(address.byte3, 0); + XCTAssertEqual(address.byte4, 0); +} + +- (void)testInitFromIntWithRealIP { + GNCIPv4Address *address = [GNCIPv4Address addressFromFourByteInt:2869012672]; + XCTAssertEqual(address.byte1, 192); + XCTAssertEqual(address.byte2, 168); + XCTAssertEqual(address.byte3, 1); + XCTAssertEqual(address.byte4, 171); +} + +- (void)testInitFromDataWithZero { + std::string addressString = "\0\0\0\0"; + NSData *addressData = [NSData dataWithBytes:addressString.data() length:4]; + GNCIPv4Address *address = [GNCIPv4Address addressFromData:addressData]; + XCTAssertEqual(address.byte1, 0); + XCTAssertEqual(address.byte2, 0); + XCTAssertEqual(address.byte3, 0); + XCTAssertEqual(address.byte4, 0); +} + +- (void)testInitFromDataWithLeadingEmptyBytes { + std::string addressString = "\0\0\0\0"; + addressString[3] = static_cast(6); + + NSData *addressData = [NSData dataWithBytes:addressString.data() length:4]; + GNCIPv4Address *address = [GNCIPv4Address addressFromData:addressData]; + XCTAssertEqual(address.byte1, 0); + XCTAssertEqual(address.byte2, 0); + XCTAssertEqual(address.byte3, 0); + XCTAssertEqual(address.byte4, 6); +} + +- (void)testInitFromDataWithRealIP { + std::string addressString = "\0\0\0\0"; + addressString[0] = static_cast(192); + addressString[1] = static_cast(168); + addressString[2] = static_cast(1); + addressString[3] = static_cast(171); + + NSData *addressData = [NSData dataWithBytes:addressString.data() length:4]; + GNCIPv4Address *address = [GNCIPv4Address addressFromData:addressData]; + XCTAssertEqual(address.byte1, 192); + XCTAssertEqual(address.byte2, 168); + XCTAssertEqual(address.byte3, 1); + XCTAssertEqual(address.byte4, 171); +} + +- (void)testInitFromDataThrowsForWrongByteSize { + std::string addressString = "\0"; + NSData *addressData = [NSData dataWithBytes:addressString.data() length:addressString.size()]; + XCTAssertThrows([GNCIPv4Address addressFromData:addressData]); +} + +- (void)testDottedRepressentationWithZero { + GNCIPv4Address *address = [[GNCIPv4Address alloc] initWithByte1:0 byte2:0 byte3:0 byte4:0]; + XCTAssertEqualObjects(address.dottedRepresentation, @"0.0.0.0"); +} + +- (void)testDottedRepressentationWithRealIP { + GNCIPv4Address *address = [[GNCIPv4Address alloc] initWithByte1:192 byte2:168 byte3:1 byte4:171]; + XCTAssertEqualObjects(address.dottedRepresentation, @"192.168.1.171"); +} + +- (void)testBinaryRepressentationWithZero { + GNCIPv4Address *address = [[GNCIPv4Address alloc] initWithByte1:0 byte2:0 byte3:0 byte4:0]; + const uint8_t *bytes = (uint8_t *)address.binaryRepresentation.bytes; + XCTAssertEqual(bytes[0], 0); + XCTAssertEqual(bytes[1], 0); + XCTAssertEqual(bytes[2], 0); + XCTAssertEqual(bytes[3], 0); +} + +- (void)testBinaryRepressentationWithRealIP { + GNCIPv4Address *address = [[GNCIPv4Address alloc] initWithByte1:192 byte2:168 byte3:1 byte4:171]; + const uint8_t *bytes = (uint8_t *)address.binaryRepresentation.bytes; + XCTAssertEqual(bytes[0], 192); + XCTAssertEqual(bytes[1], 168); + XCTAssertEqual(bytes[2], 1); + XCTAssertEqual(bytes[3], 171); +} + +@end diff --git a/internal/platform/implementation/apple/wifi_lan.mm b/internal/platform/implementation/apple/wifi_lan.mm index 7cadd50a..5f2cc663 100644 --- a/internal/platform/implementation/apple/wifi_lan.mm +++ b/internal/platform/implementation/apple/wifi_lan.mm @@ -13,11 +13,13 @@ // limitations under the License. #import "internal/platform/implementation/apple/wifi_lan.h" +#import #include #include #include +#import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCIPv4Address.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANMedium.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANServerSocket.h" #import "internal/platform/implementation/apple/Mediums/WiFiLAN/GNCWiFiLANSocket.h" @@ -94,7 +96,8 @@ WifiLanServerSocket::WifiLanServerSocket(GNCWiFiLANServerSocket* server_socket) : server_socket_(server_socket) {} std::string WifiLanServerSocket::GetIPAddress() const { - return [server_socket_.ipAddress UTF8String]; + NSData* addressData = server_socket_.ipAddress.binaryRepresentation; + return std::string((char*)addressData.bytes, addressData.length); } int WifiLanServerSocket::GetPort() const { return server_socket_.port; } @@ -204,7 +207,12 @@ std::unique_ptr WifiLanMedium::ConnectToService( std::unique_ptr WifiLanMedium::ConnectToService( const std::string& ip_address, int port, CancellationFlag* cancellation_flag) { NSError* error = nil; - NSString* host = @(ip_address.c_str()); + if (ip_address.size() != 4) { + GTMLoggerError(@"Error IP address must be 4 bytes, but is %lu bytes", ip_address.size()); + return nil; + } + NSData* hostData = [NSData dataWithBytes:ip_address.data() length:ip_address.size()]; + GNCIPv4Address* host = [GNCIPv4Address addressFromData:hostData]; GNCWiFiLANSocket* socket = [medium_ connectToHost:host port:port error:&error]; if (socket != nil) { return std::make_unique(socket); From 15d81201f87baf054fd5ee42d37bc25729ffb09a Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Mon, 1 May 2023 18:05:25 -0700 Subject: [PATCH 56/63] Fixed data race in FakeTaskRunner PiperOrigin-RevId: 528627577 --- internal/test/BUILD | 15 ++++ internal/test/fake_task_runner.cc | 111 +++++++++++++++++++------ internal/test/fake_task_runner.h | 62 ++++++++------ internal/test/fake_task_runner_test.cc | 55 ++++++++---- 4 files changed, 178 insertions(+), 65 deletions(-) diff --git a/internal/test/BUILD b/internal/test/BUILD index 618ee62f..dc5407b7 100644 --- a/internal/test/BUILD +++ b/internal/test/BUILD @@ -1,3 +1,17 @@ +# 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. + licenses(["notice"]) cc_library( @@ -50,6 +64,7 @@ cc_test( "//internal/platform/implementation:types", "//internal/platform/implementation/g3", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], diff --git a/internal/test/fake_task_runner.cc b/internal/test/fake_task_runner.cc index 316e74cf..cd35a9a1 100644 --- a/internal/test/fake_task_runner.cc +++ b/internal/test/fake_task_runner.cc @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// 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. @@ -14,21 +14,36 @@ #include "internal/test/fake_task_runner.h" -#include +#include #include // NOLINT #include #include #include +#include "absl/synchronization/mutex.h" +#include "absl/synchronization/notification.h" #include "absl/time/time.h" +#include "internal/test/fake_timer.h" namespace nearby { -std::atomic_uint FakeTaskRunner::running_thread_count_ = 0; +std::atomic_uint FakeTaskRunner::total_running_thread_count_ = 0; + +FakeTaskRunner::~FakeTaskRunner() { + absl::MutexLock lock(&mutex_); + CleanThreads(); +} bool FakeTaskRunner::PostTask(absl::AnyInvocable task) { - if (mode_ == Mode::kNoPending) { - run(std::move(task)); + absl::MutexLock lock(&mutex_); + if (mode_ == Mode::kActive) { + if (running_thread_count_ >= count_) { + queued_tasks_.push_back(std::move(task)); + return true; + } + + ++running_thread_count_; + Run(std::move(task)); return true; } pending_tasks_.push_back(std::move(task)); @@ -37,56 +52,80 @@ bool FakeTaskRunner::PostTask(absl::AnyInvocable task) { bool FakeTaskRunner::PostDelayedTask(absl::Duration delay, absl::AnyInvocable task) { + absl::MutexLock lock(&mutex_); std::unique_ptr timer = std::make_unique(clock_); Timer* timer_ptr = timer.get(); uint32_t id = GenerateId(); - pending_delayed_tasks_.emplace(id, std::move(timer)); + queued_delayed_tasks_.emplace(id, std::move(timer)); timer_ptr->Start(delay / absl::Milliseconds(1), 0, [this, task = std::move(task), id]() mutable { PostTask(std::move(task)); - completed_delayed_tasks_.push_back(id); + { + absl::MutexLock lock(&mutex_); + completed_delayed_tasks_.push_back(id); + } }); return true; } -void FakeTaskRunner::RunNextTask() { - if (pending_tasks_.empty()) { - return; - } +void FakeTaskRunner::SetMode(Mode mode) { + absl::MutexLock lock(&mutex_); + mode_ = mode; +} - run(std::move(pending_tasks_.front())); - pending_tasks_.erase(pending_tasks_.begin()); +FakeTaskRunner::Mode FakeTaskRunner::GetMode() const { + absl::MutexLock lock(&mutex_); + return mode_; +} + +void FakeTaskRunner::RunNextPendingTask() { + absl::MutexLock lock(&mutex_); + InternalRunNextPendingTask(); } void FakeTaskRunner::RunAllPendingTasks() { + absl::MutexLock lock(&mutex_); while (!pending_tasks_.empty()) { - RunNextTask(); + InternalRunNextPendingTask(); } } -const std::vector>& FakeTaskRunner::GetPendingTasks() - const { +void FakeTaskRunner::Sync() { + absl::Notification notification; + PostTask([&] { notification.Notify(); }); + notification.WaitForNotification(); +} + +const std::vector>& +FakeTaskRunner::GetAllPendingTasks() const { + absl::MutexLock lock(&mutex_); return pending_tasks_; } const absl::flat_hash_map>& -FakeTaskRunner::GetPendingDelayedTask() { +FakeTaskRunner::GetAllDelayedTasks() { + absl::MutexLock lock(&mutex_); if (!completed_delayed_tasks_.empty()) { for (uint32_t id : completed_delayed_tasks_) { - pending_delayed_tasks_.erase(id); + queued_delayed_tasks_.erase(id); } } - return pending_delayed_tasks_; + return queued_delayed_tasks_; +} + +int FakeTaskRunner::GetConcurrentCount() const { + absl::MutexLock lock(&mutex_); + return count_; } bool FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Duration timeout) { int i = (timeout / absl::Milliseconds(1)) / 50; - while (running_thread_count_ != 0 && i > 0) { + while (total_running_thread_count_ != 0 && i > 0) { absl::SleepFor(absl::Milliseconds(50)); --i; } - return running_thread_count_ == 0; + return total_running_thread_count_ == 0; } uint32_t FakeTaskRunner::GenerateId() { @@ -107,17 +146,39 @@ void FakeTaskRunner::CleanThreads() { } } -void FakeTaskRunner::run(absl::AnyInvocable task) { - absl::MutexLock lock(&mutex_); +void FakeTaskRunner::Run(absl::AnyInvocable task) { CleanThreads(); - ++running_thread_count_; + ++total_running_thread_count_; // Run the task in a new thread, to simulate the real environment. std::future thread = std::async(std::launch::async, [&, task = std::move(task)]() mutable { task(); - --running_thread_count_; + RunNextQueueTask(); + --total_running_thread_count_; }); threads_.push_back(std::move(thread)); } +void FakeTaskRunner::InternalRunNextPendingTask() { + if (pending_tasks_.empty()) { + return; + } + + Run(std::move(pending_tasks_.front())); + pending_tasks_.erase(pending_tasks_.begin()); +} + +void FakeTaskRunner::RunNextQueueTask() { + absl::MutexLock lock(&mutex_); + --running_thread_count_; + if (queued_tasks_.empty()) { + return; + } + + auto task = std::move(queued_tasks_.front()); + queued_tasks_.erase(queued_tasks_.begin()); + ++running_thread_count_; + Run(std::move(task)); +} + } // namespace nearby diff --git a/internal/test/fake_task_runner.h b/internal/test/fake_task_runner.h index 4b433e83..f92b07f9 100644 --- a/internal/test/fake_task_runner.h +++ b/internal/test/fake_task_runner.h @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// 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. @@ -19,8 +19,6 @@ #include #include //NOLINT #include -#include //NOLINT -#include #include #include "absl/base/thread_annotations.h" @@ -34,52 +32,68 @@ namespace nearby { class FakeTaskRunner : public TaskRunner { public: - enum class Mode { kNoPending, kPending }; + enum class Mode { kActive, kPending }; FakeTaskRunner(FakeClock* clock, uint32_t count) : clock_(clock), count_(count) {} - ~FakeTaskRunner() override = default; + ~FakeTaskRunner() override ABSL_LOCKS_EXCLUDED(mutex_); - bool PostTask(absl::AnyInvocable task) override; + bool PostTask(absl::AnyInvocable task) override + ABSL_LOCKS_EXCLUDED(mutex_); // No matter the mode is pending or not, always put the task in timer control. // Caller can move forward time to trigger it. bool PostDelayedTask(absl::Duration delay, - absl::AnyInvocable task) override; + absl::AnyInvocable task) override + ABSL_LOCKS_EXCLUDED(mutex_); // Mocked methods. - void SetMode(Mode mode) { mode_ = mode; } - Mode GetMode() const { return mode_; } + void SetMode(Mode mode) ABSL_LOCKS_EXCLUDED(mutex_); + Mode GetMode() const ABSL_LOCKS_EXCLUDED(mutex_); - void RunNextTask(); - void RunAllPendingTasks(); + void RunNextPendingTask() ABSL_LOCKS_EXCLUDED(mutex_); + void RunAllPendingTasks() ABSL_LOCKS_EXCLUDED(mutex_); + void Sync(); - const std::vector>& GetPendingTasks() const; + const std::vector>& GetAllPendingTasks() const + ABSL_LOCKS_EXCLUDED(mutex_); const absl::flat_hash_map>& - GetPendingDelayedTask(); + GetAllDelayedTasks() ABSL_LOCKS_EXCLUDED(mutex_); - int GetConcurrentCount() const { return count_; } + int GetConcurrentCount() const ABSL_LOCKS_EXCLUDED(mutex_); - // In some testcases, we needs to make sure all running tasks completion + // In some test cases, we needs to make sure all running tasks completion // before go to next task. This method can be used for the purpose. static bool WaitForRunningTasksWithTimeout(absl::Duration timeout); + static int GetTotalRunningThreadCount() { + return total_running_thread_count_; + } private: uint32_t GenerateId(); void CleanThreads() ABSL_SHARED_LOCKS_REQUIRED(mutex_); - void run(absl::AnyInvocable task) ABSL_LOCKS_EXCLUDED(mutex_); + void Run(absl::AnyInvocable task) ABSL_SHARED_LOCKS_REQUIRED(mutex_); + void InternalRunNextPendingTask() ABSL_SHARED_LOCKS_REQUIRED(mutex_); + void RunNextQueueTask() ABSL_LOCKS_EXCLUDED(mutex_); - Mode mode_ = Mode::kNoPending; + mutable absl::Mutex mutex_; + mutable absl::Mutex thread_mutex_; + Mode mode_ ABSL_GUARDED_BY(mutex_) = Mode::kActive; std::atomic_uint current_id_ = 0; FakeClock* clock_ = nullptr; - uint32_t count_; - std::vector> pending_tasks_; - std::vector completed_delayed_tasks_; - absl::flat_hash_map> pending_delayed_tasks_; - absl::Mutex mutex_; - std::vector> threads_ ABSL_GUARDED_BY(mutex_); + uint32_t count_ ABSL_GUARDED_BY(mutex_); - static std::atomic_uint running_thread_count_; + // Used for pending mode + std::vector> pending_tasks_ + ABSL_GUARDED_BY(mutex_); + std::vector> queued_tasks_ ABSL_GUARDED_BY(mutex_); + std::vector completed_delayed_tasks_ ABSL_GUARDED_BY(mutex_); + absl::flat_hash_map> queued_delayed_tasks_ + ABSL_GUARDED_BY(mutex_); + std::vector> threads_ ABSL_GUARDED_BY(mutex_); + int running_thread_count_ ABSL_GUARDED_BY(mutex_) = 0; + + static std::atomic_uint total_running_thread_count_; }; } // namespace nearby diff --git a/internal/test/fake_task_runner_test.cc b/internal/test/fake_task_runner_test.cc index fd2b0554..e778d0ae 100644 --- a/internal/test/fake_task_runner_test.cc +++ b/internal/test/fake_task_runner_test.cc @@ -1,4 +1,4 @@ -// Copyright 2022 Google LLC +// 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. @@ -14,7 +14,11 @@ #include "internal/test/fake_task_runner.h" +#include + #include "gtest/gtest.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" #include "absl/time/time.h" #include "internal/test/fake_clock.h" @@ -28,7 +32,7 @@ TEST(FakeTaskRunner, PostTask) { task_runner.PostTask([&count] { ++count; }); ASSERT_TRUE( FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100))); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 0); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 0); EXPECT_EQ(count, 1); } @@ -37,14 +41,14 @@ TEST(FakeTaskRunner, PostDelayedTask) { int count = 0; FakeTaskRunner task_runner{&clock, 1}; task_runner.PostDelayedTask(absl::Seconds(10), [&count] { ++count; }); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 0); - EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 1); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 0); + EXPECT_EQ(task_runner.GetAllDelayedTasks().size(), 1); EXPECT_EQ(count, 0); clock.FastForward(absl::Seconds(10)); ASSERT_TRUE( FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100))); EXPECT_EQ(count, 1); - EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 0); + EXPECT_EQ(task_runner.GetAllDelayedTasks().size(), 0); } TEST(FakeTaskRunner, PostTasksInPendingMode) { @@ -54,11 +58,11 @@ TEST(FakeTaskRunner, PostTasksInPendingMode) { EXPECT_EQ(task_runner.GetConcurrentCount(), 1); task_runner.PostTask([]() {}); task_runner.PostTask([]() {}); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 2); - task_runner.RunNextTask(); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 1); - task_runner.RunNextTask(); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 0); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 2); + task_runner.RunNextPendingTask(); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 1); + task_runner.RunNextPendingTask(); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 0); } TEST(FakeTaskRunner, RunAllPostedTasksInPendingMode) { @@ -67,11 +71,11 @@ TEST(FakeTaskRunner, RunAllPostedTasksInPendingMode) { task_runner.SetMode(FakeTaskRunner::Mode::kPending); task_runner.PostTask([]() {}); task_runner.PostTask([]() {}); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 2); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 2); task_runner.RunAllPendingTasks(); ASSERT_TRUE( FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100))); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 0); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 0); } TEST(FakeTaskRunner, PostDelayedTaskInPendingMode) { @@ -80,17 +84,36 @@ TEST(FakeTaskRunner, PostDelayedTaskInPendingMode) { FakeTaskRunner task_runner{&clock, 1}; task_runner.SetMode(FakeTaskRunner::Mode::kPending); task_runner.PostDelayedTask(absl::Seconds(1), [&called]() { called = true; }); - EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 1); + EXPECT_EQ(task_runner.GetAllDelayedTasks().size(), 1); clock.FastForward(absl::Seconds(1)); - EXPECT_EQ(task_runner.GetPendingDelayedTask().size(), 0); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 1); + EXPECT_EQ(task_runner.GetAllDelayedTasks().size(), 0); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 1); task_runner.RunAllPendingTasks(); ASSERT_TRUE( FakeTaskRunner::WaitForRunningTasksWithTimeout(absl::Milliseconds(100))); - EXPECT_EQ(task_runner.GetPendingTasks().size(), 0); + EXPECT_EQ(task_runner.GetAllPendingTasks().size(), 0); EXPECT_TRUE(called); } +TEST(FakeTaskRunner, PostTasksRunInSequence) { + std::list result; + absl::Mutex mutex; + FakeClock clock; + FakeTaskRunner task_runner{&clock, 1}; + for (int i = 0; i < 100; ++i) { + task_runner.PostTask([&, i]() { + absl::MutexLock lock(&mutex); + absl::SleepFor(absl::Milliseconds(40)); + result.push_back(i); + }); + } + task_runner.Sync(); + for (int i = 0; i < 100; ++i) { + EXPECT_EQ(result.front(), i); + result.pop_front(); + } +} + TEST(FakeTaskRunner, PostDelayedTaskInDelayedTask) { FakeClock clock; int called_count = 0; From 8741eb6c71eeaeb5fad6eef5c53fa88ac12a4b61 Mon Sep 17 00:00:00 2001 From: Joy Babafemi Date: Mon, 1 May 2023 18:19:17 -0700 Subject: [PATCH 57/63] Add "Foldable" DeviceType to PresenceDevice. PiperOrigin-RevId: 528629960 --- internal/proto/metadata.proto | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/proto/metadata.proto b/internal/proto/metadata.proto index 948b47cd..819a68b7 100644 --- a/internal/proto/metadata.proto +++ b/internal/proto/metadata.proto @@ -70,4 +70,7 @@ enum DeviceType { // The device is a ChromeOS device. ChromeOS can be a laptop, desktop, or // convertible (tablet + clamshell). DEVICE_TYPE_CHROMEOS = 7; + + // The device is a foldable. + DEVICE_TYPE_FOLDABLE = 8; } From 9ea2c9fd8ec386e77eeffac303d134492928c9ac Mon Sep 17 00:00:00 2001 From: Guogang Li Date: Mon, 1 May 2023 19:10:53 -0700 Subject: [PATCH 58/63] Fixed the data race in ObserverList PiperOrigin-RevId: 528638464 --- internal/base/observer_list.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/base/observer_list.h b/internal/base/observer_list.h index a4d44a2f..d91333cb 100644 --- a/internal/base/observer_list.h +++ b/internal/base/observer_list.h @@ -28,6 +28,11 @@ class ObserverList { using const_iterator = typename absl::flat_hash_set::const_iterator; + ~ObserverList() ABSL_LOCKS_EXCLUDED(mutex_) { + MutexLock lock(&mutex_); + observers_.clear(); + } + void AddObserver(ObserverType* observer) ABSL_LOCKS_EXCLUDED(mutex_) { MutexLock lock(&mutex_); observers_.insert(observer); From 6b25d430d9f010c000072489fea5188d738da3f2 Mon Sep 17 00:00:00 2001 From: hai007 Date: Tue, 2 May 2023 12:46:43 -0700 Subject: [PATCH 59/63] copybara update PiperOrigin-RevId: 528861897 --- .../platform/implementation/apple/Mediums/Ble/Sockets/BUILD | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD index 169c2f67..7f134cf1 100644 --- a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD +++ b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD @@ -17,9 +17,7 @@ load("//third_party/nearby:minimum_os.bzl", "IOS_MINIMUM_OS") licenses(["notice"]) -package( - default_visibility = ["//visibility:public"], -) +package(default_visibility = ["//visibility:public"]) objc_library( name = "Central", From 21d2efbccd5607fb8d9fa2b4c8f5474e4d9169af Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Tue, 2 May 2023 16:01:21 -0700 Subject: [PATCH 60/63] Create PresenceDeviceProvider PiperOrigin-RevId: 528913199 --- connections/core.h | 5 +- internal/interop/BUILD | 1 + internal/interop/device.h | 4 -- internal/interop/device_provider.h | 5 +- internal/platform/BUILD | 1 + presence/BUILD | 8 +++ presence/implementation/service_controller.h | 1 + .../implementation/service_controller_impl.h | 2 + presence/presence_client.cc | 12 +++- presence/presence_client.h | 6 ++ presence/presence_client_test.cc | 32 +++++++++ presence/presence_device.h | 7 +- presence/presence_device_provider.h | 42 +++++++++++ presence/presence_device_provider_test.cc | 72 +++++++++++++++++++ presence/presence_service.cc | 5 +- presence/presence_service.h | 7 ++ presence/presence_service_test.cc | 5 ++ 17 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 presence/presence_device_provider.h create mode 100644 presence/presence_device_provider_test.cc diff --git a/connections/core.h b/connections/core.h index 714ebbc8..7142b6e4 100644 --- a/connections/core.h +++ b/connections/core.h @@ -17,6 +17,7 @@ #include #include +#include #include "absl/strings/string_view.h" #include "absl/types/span.h" @@ -507,7 +508,9 @@ class Core { // Registers a DeviceProvider to provide functionality for Nearby Connections // to interact with the DeviceProvider for retrieving the local device. - void RegisterDeviceProvider(NearbyDeviceProvider&& provider); + template ::value>::type* = nullptr> + void RegisterDeviceProvider(NearbyDeviceProvider* provider); private: ClientProxy client_; diff --git a/internal/interop/BUILD b/internal/interop/BUILD index 9836cef4..f5423d06 100644 --- a/internal/interop/BUILD +++ b/internal/interop/BUILD @@ -10,6 +10,7 @@ cc_library( ], deps = [ "//internal/platform:connection_info", + "//internal/platform:types", "@com_google_absl//absl/strings", "@com_google_absl//absl/types:variant", ], diff --git a/internal/interop/device.h b/internal/interop/device.h index 82f2f9b7..d13979f3 100644 --- a/internal/interop/device.h +++ b/internal/interop/device.h @@ -41,10 +41,6 @@ class NearbyDevice { }; NearbyDevice() = default; virtual ~NearbyDevice() = default; - NearbyDevice(NearbyDevice&&) = default; - NearbyDevice& operator=(NearbyDevice&&) = default; - NearbyDevice(const NearbyDevice&) = delete; - NearbyDevice& operator=(const NearbyDevice&) = delete; virtual std::string GetEndpointId() const = 0; // We will be adding more ConnectionInfo types to this variant as they are // implemented. diff --git a/internal/interop/device_provider.h b/internal/interop/device_provider.h index a622601d..828b2613 100644 --- a/internal/interop/device_provider.h +++ b/internal/interop/device_provider.h @@ -22,10 +22,13 @@ namespace nearby { // The base device provider class for use with the Nearby Connections V3 APIs. // This class currently provides a function to get the local device for whatever // client implements it. +template ::value>::type* = nullptr> class NearbyDeviceProvider { + public: virtual ~NearbyDeviceProvider() = default; - virtual NearbyDevice* GetLocalDevice() = 0; + const virtual T& GetLocalDevice() = 0; }; } // namespace nearby diff --git a/internal/platform/BUILD b/internal/platform/BUILD index e8107092..ab66288c 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -348,6 +348,7 @@ cc_library( "//fastpair:__subpackages__", "//internal/base:__subpackages__", "//internal/flags:__subpackages__", + "//internal/interop:__pkg__", "//internal/platform/implementation/windows:__subpackages__", "//internal/preferences:__subpackages__", "//internal/test:__subpackages__", diff --git a/presence/BUILD b/presence/BUILD index 55b534a4..d416aee1 100644 --- a/presence/BUILD +++ b/presence/BUILD @@ -23,11 +23,14 @@ cc_library( ], hdrs = [ "presence_client.h", + "presence_device_provider.h", "presence_service.h", ], deps = [ ":types", + "//internal/interop:device", "//internal/platform:types", + "//internal/proto:metadata_cc_proto", "//presence/implementation:internal", # build_cleaner: keep "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", @@ -64,6 +67,7 @@ cc_library( "//internal/interop:device", "//internal/platform:connection_info", "//internal/platform:logging", + "//internal/platform:types", "//internal/platform/implementation:types", "//internal/proto:credential_cc_proto", "//internal/proto:metadata_cc_proto", @@ -138,6 +142,7 @@ cc_test( size = "small", srcs = [ "presence_client_test.cc", + "presence_device_provider_test.cc", "presence_service_test.cc", ], shard_count = 6, @@ -145,8 +150,11 @@ cc_test( ":presence", ":types", "//internal/platform:test_util", + "//internal/platform:types", + "//internal/proto:metadata_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ] + select({ "//tools/cc_target_os:windows": [ diff --git a/presence/implementation/service_controller.h b/presence/implementation/service_controller.h index ead85a23..ab041728 100644 --- a/presence/implementation/service_controller.h +++ b/presence/implementation/service_controller.h @@ -19,6 +19,7 @@ #include #include "absl/status/statusor.h" +#include "internal/proto/metadata.pb.h" #include "presence/broadcast_request.h" #include "presence/data_types.h" #include "presence/scan_request.h" diff --git a/presence/implementation/service_controller_impl.h b/presence/implementation/service_controller_impl.h index 48ea2624..6233b772 100644 --- a/presence/implementation/service_controller_impl.h +++ b/presence/implementation/service_controller_impl.h @@ -20,6 +20,7 @@ #include #include "absl/status/statusor.h" +#include "internal/proto/metadata.pb.h" #include "presence/implementation/broadcast_manager.h" #include "presence/implementation/credential_manager_impl.h" #include "presence/implementation/mediums/mediums.h" @@ -52,6 +53,7 @@ class ServiceControllerImpl : public ServiceController { const std::vector& identity_types, int credential_life_cycle_days, int contiguous_copy_of_credentials, GenerateCredentialsResultCallback credentials_generated_cb) override; + ::nearby::internal::Metadata GetLocalDeviceMetadata() override { return credential_manager_.GetLocalDeviceMetadata(); } diff --git a/presence/presence_client.cc b/presence/presence_client.cc index 32418486..b011590e 100644 --- a/presence/presence_client.cc +++ b/presence/presence_client.cc @@ -14,13 +14,13 @@ #include "presence/presence_client.h" -#include +#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 { @@ -62,5 +62,13 @@ void PresenceClient::StopBroadcast(BroadcastSessionId session_id) { } } +std::optional PresenceClient::GetLocalDevice() { + ::nearby::Borrowed borrowed = service_.Borrow(); + if (borrowed) { + return (*borrowed)->GetLocalDeviceProvider()->GetLocalDevice(); + } + return std::nullopt; +} + } // namespace presence } // namespace nearby diff --git a/presence/presence_client.h b/presence/presence_client.h index 23b70791..16845b47 100644 --- a/presence/presence_client.h +++ b/presence/presence_client.h @@ -23,6 +23,7 @@ #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 { @@ -78,6 +79,11 @@ class PresenceClient { // terminated. void StopBroadcast(BroadcastSessionId session_id); + // Returns the local PresenceDevice describing the current device's actions, + // connectivity info and unique identifier for use in Connections and + // Presence. + std::optional GetLocalDevice(); + private: BorrowablePresenceService service_; }; diff --git a/presence/presence_client_test.cc b/presence/presence_client_test.cc index 2403ad15..9a4585cd 100644 --- a/presence/presence_client_test.cc +++ b/presence/presence_client_test.cc @@ -20,14 +20,18 @@ #include "absl/status/status.h" #include "internal/platform/medium_environment.h" #include "presence/data_types.h" +#include "presence/presence_device.h" #include "presence/presence_service.h" namespace nearby { namespace presence { namespace { +using ::nearby::internal::Metadata; using ::testing::status::StatusIs; +constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; + // Creates a PresenceClient and destroys PresenceService that was used to create // it. PresenceClient CreateDefunctPresenceClient() { @@ -35,6 +39,17 @@ PresenceClient CreateDefunctPresenceClient() { return presence_service.CreatePresenceClient(); } +Metadata CreateTestMetadata() { + Metadata metadata; + metadata.set_device_type(internal::DEVICE_TYPE_PHONE); + metadata.set_account_name("test_account"); + metadata.set_device_name("NP test device"); + metadata.set_user_name("Test user"); + metadata.set_device_profile_url("test_image.test.com"); + metadata.set_bluetooth_mac_address(kMacAddr); + return metadata; +} + class PresenceClientTest : public testing::Test { protected: nearby::MediumEnvironment& env_{nearby::MediumEnvironment::Instance()}; @@ -104,6 +119,23 @@ TEST_F(PresenceClientTest, StartScanFailsWhenPresenceServiceIsGone) { env_.Stop(); } +TEST_F(PresenceClientTest, GettingDeviceWorks) { + PresenceService presence_service; + PresenceClient presence_client = presence_service.CreatePresenceClient(); + presence_service.UpdateLocalDeviceMetadata(CreateTestMetadata(), false, "", + {}, 0, 0, {}); + auto device = presence_client.GetLocalDevice(); + ASSERT_NE(device, std::nullopt); + EXPECT_EQ(device->GetEndpointId().length(), kEndpointIdLength); + EXPECT_EQ(device->GetMetadata().SerializeAsString(), + CreateTestMetadata().SerializeAsString()); +} + +TEST_F(PresenceClientTest, TestGettingDeviceDefunct) { + PresenceClient presence_client = CreateDefunctPresenceClient(); + auto device = presence_client.GetLocalDevice(); + EXPECT_EQ(device, std::nullopt); +} } // namespace } // namespace presence } // namespace nearby diff --git a/presence/presence_device.h b/presence/presence_device.h index b4455c2a..3d56b5db 100644 --- a/presence/presence_device.h +++ b/presence/presence_device.h @@ -60,12 +60,13 @@ class PresenceDevice : public nearby::NearbyDevice { const override; DeviceMotion GetDeviceMotion() const { return device_motion_; } Metadata GetMetadata() const { return metadata_; } + void SetMetadata(const Metadata metadata) { metadata_ = metadata; } absl::Time GetDiscoveryTimestamp() const { return discovery_timestamp_; } private: const absl::Time discovery_timestamp_; const DeviceMotion device_motion_; - const Metadata metadata_; + Metadata metadata_; std::vector extended_properties_; std::vector actions_; std::string endpoint_id_; @@ -77,7 +78,9 @@ class PresenceDevice : public nearby::NearbyDevice { inline bool operator==(const PresenceDevice& d1, const PresenceDevice& d2) { return d1.GetDeviceMotion() == d2.GetDeviceMotion() && d1.GetMetadata().SerializeAsString() == - d2.GetMetadata().SerializeAsString(); + d2.GetMetadata().SerializeAsString() && + d1.GetActions() == d2.GetActions() && + d1.GetExtendedProperties() == d2.GetExtendedProperties(); } inline bool operator!=(const PresenceDevice& d1, const PresenceDevice& d2) { diff --git a/presence/presence_device_provider.h b/presence/presence_device_provider.h new file mode 100644 index 00000000..45be14c8 --- /dev/null +++ b/presence/presence_device_provider.h @@ -0,0 +1,42 @@ +// 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 "internal/interop/device_provider.h" +#include "internal/proto/metadata.proto.h" +#include "presence/presence_device.h" + +namespace nearby { +namespace presence { + +class PresenceDeviceProvider : public NearbyDeviceProvider { + public: + explicit PresenceDeviceProvider(::nearby::internal::Metadata metadata) + : device_{metadata} {} + + const PresenceDevice& GetLocalDevice() override { return device_; } + + void UpdateMetadata(const ::nearby::internal::Metadata& metadata) { + device_.SetMetadata(metadata); + } + + private: + PresenceDevice device_; +}; +} // 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 new file mode 100644 index 00000000..cf7b3e22 --- /dev/null +++ b/presence/presence_device_provider_test.cc @@ -0,0 +1,72 @@ +// 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 "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "internal/proto/metadata.pb.h" +#include "internal/proto/metadata.proto.h" +#include "presence/presence_device.h" + +namespace nearby { +namespace presence { +namespace { +using ::nearby::internal::Metadata; + +constexpr absl::string_view kMacAddr = "\x4C\x8B\x1D\xCE\xBA\xD1"; + +Metadata CreateTestMetadata() { + Metadata metadata; + metadata.set_device_type(internal::DEVICE_TYPE_PHONE); + metadata.set_account_name("test_account"); + metadata.set_device_name("NP test device"); + metadata.set_user_name("Test user"); + metadata.set_device_profile_url("test_image.test.com"); + metadata.set_bluetooth_mac_address(kMacAddr); + return metadata; +} + +TEST(PresenceDeviceProviderTest, ProviderIsNotTriviallyConstructible) { + EXPECT_FALSE(std::is_trivially_constructible::value); +} + +TEST(PresenceDeviceProviderTest, DeviceProviderWorks) { + PresenceDeviceProvider provider(CreateTestMetadata()); + auto device = provider.GetLocalDevice(); + EXPECT_EQ(device.GetMetadata().SerializeAsString(), + CreateTestMetadata().SerializeAsString()); +} + +TEST(PresenceDeviceProviderTest, DeviceProviderCanUpdateDevice) { + PresenceDeviceProvider provider(CreateTestMetadata()); + auto device = provider.GetLocalDevice(); + EXPECT_EQ(device.GetMetadata().SerializeAsString(), + CreateTestMetadata().SerializeAsString()); + Metadata new_metadata = CreateTestMetadata(); + new_metadata.set_device_name("NP interop device"); + provider.UpdateMetadata(new_metadata); + EXPECT_NE(device.GetMetadata().SerializeAsString(), + new_metadata.SerializeAsString()); + EXPECT_EQ(provider.GetLocalDevice().GetMetadata().SerializeAsString(), + new_metadata.SerializeAsString()); +} + +} // namespace +} // namespace presence +} // namespace nearby diff --git a/presence/presence_service.cc b/presence/presence_service.cc index e4d4c3b8..5fee1268 100644 --- a/presence/presence_service.cc +++ b/presence/presence_service.cc @@ -24,7 +24,9 @@ namespace nearby { namespace presence { PresenceService::PresenceService() { - this->service_controller_ = std::make_unique(); + service_controller_ = std::make_unique(); + provider_ = std::make_unique( + service_controller_->GetLocalDeviceMetadata()); } PresenceClient PresenceService::CreatePresenceClient() { @@ -35,6 +37,7 @@ absl::StatusOr PresenceService::StartScan( ScanRequest scan_request, ScanCallback callback) { return service_controller_->StartScan(scan_request, std::move(callback)); } + void PresenceService::StopScan(ScanSessionId id) { service_controller_->StopScan(id); } diff --git a/presence/presence_service.h b/presence/presence_service.h index 651776e8..d86b8d09 100644 --- a/presence/presence_service.h +++ b/presence/presence_service.h @@ -20,9 +20,11 @@ #include #include "internal/platform/borrowable.h" +#include "internal/proto/metadata.proto.h" #include "presence/data_types.h" #include "presence/implementation/service_controller.h" #include "presence/presence_client.h" +#include "presence/presence_device_provider.h" namespace nearby { namespace presence { @@ -54,12 +56,16 @@ class PresenceService { const std::vector& identity_types, int credential_life_cycle_days, int contiguous_copy_of_credentials, GenerateCredentialsResultCallback credentials_generated_cb) { + provider_->UpdateMetadata(metadata); service_controller_->UpdateLocalDeviceMetadata( metadata, regen_credentials, manager_app_id, identity_types, credential_life_cycle_days, contiguous_copy_of_credentials, std::move(credentials_generated_cb)); } + PresenceDeviceProvider* GetLocalDeviceProvider() { return provider_.get(); } + + // Testing only. ::nearby::internal::Metadata GetLocalDeviceMetadata() { return service_controller_->GetLocalDeviceMetadata(); } @@ -67,6 +73,7 @@ class PresenceService { private: std::unique_ptr service_controller_; ::nearby::Lender lender_{this}; + std::unique_ptr provider_; }; } // namespace presence diff --git a/presence/presence_service_test.cc b/presence/presence_service_test.cc index b80035ca..564754d1 100644 --- a/presence/presence_service_test.cc +++ b/presence/presence_service_test.cc @@ -78,6 +78,11 @@ TEST_F(PresenceServiceTest, UpdatingLocalMetadataWorks) { CreateTestMetadata("Test account").SerializeAsString()); } +TEST_F(PresenceServiceTest, TestGetDeviceProvider) { + PresenceService presence_service; + EXPECT_NE(presence_service.GetLocalDeviceProvider(), nullptr); +} + } // namespace } // namespace presence } // namespace nearby From 608fb93ad6f8c173590702965dcd00f549de119d Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Wed, 3 May 2023 13:23:18 -0700 Subject: [PATCH 61/63] Switch to the correct proto includes PiperOrigin-RevId: 529178647 --- presence/presence_device_provider.h | 2 +- presence/presence_service.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/presence/presence_device_provider.h b/presence/presence_device_provider.h index 45be14c8..31d65e4e 100644 --- a/presence/presence_device_provider.h +++ b/presence/presence_device_provider.h @@ -16,7 +16,7 @@ #define THIRD_PARTY_NEARBY_PRESENCE_PRESENCE_DEVICE_PROVIDER_H_ #include "internal/interop/device_provider.h" -#include "internal/proto/metadata.proto.h" +#include "internal/proto/metadata.pb.h" #include "presence/presence_device.h" namespace nearby { diff --git a/presence/presence_service.h b/presence/presence_service.h index d86b8d09..623e6169 100644 --- a/presence/presence_service.h +++ b/presence/presence_service.h @@ -20,7 +20,7 @@ #include #include "internal/platform/borrowable.h" -#include "internal/proto/metadata.proto.h" +#include "internal/proto/metadata.pb.h" #include "presence/data_types.h" #include "presence/implementation/service_controller.h" #include "presence/presence_client.h" From f21b1e7089a3b19cb14298a5fc7ec7ae640ac6a0 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Wed, 3 May 2023 13:26:27 -0700 Subject: [PATCH 62/63] internal change PiperOrigin-RevId: 529179617 --- internal/platform/implementation/apple/BUILD | 2 +- .../apple/Mediums/Ble/Sockets/BUILD | 2 +- presence/BUILD | 6 ++--- presence/implementation/BUILD | 22 +++++++++---------- presence/implementation/mediums/BUILD | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index b52e1b0e..2c6616d7 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -73,7 +73,7 @@ objc_library( "@com_google_absl//absl/types:optional", "@nlohmann_json//:json", ] + select({ - "//tools/cc_target_os:platform_ios": [ + "@platforms//os:platform_ios": [ "//third_party/apple_frameworks:UIKit", ], "//conditions:default": [], diff --git a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD index 7f134cf1..255b6a1b 100644 --- a/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD +++ b/internal/platform/implementation/apple/Mediums/Ble/Sockets/BUILD @@ -57,7 +57,7 @@ objc_library( "//third_party/apple_frameworks:QuartzCore", "//third_party/objective_c/google_toolbox_for_mac:GTM_Logger", ] + select({ - "//tools/cc_target_os:platform_ios": [ + "@platforms//os:platform_ios": [ "//third_party/apple_frameworks:UIKit", ], "//conditions:default": [], diff --git a/presence/BUILD b/presence/BUILD index d416aee1..6d48be7f 100644 --- a/presence/BUILD +++ b/presence/BUILD @@ -104,7 +104,7 @@ cc_test( "@com_google_absl//absl/types:variant", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -128,7 +128,7 @@ cc_test( "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -157,7 +157,7 @@ cc_test( "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ diff --git a/presence/implementation/BUILD b/presence/implementation/BUILD index 3985f6f1..dec31ae5 100644 --- a/presence/implementation/BUILD +++ b/presence/implementation/BUILD @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") -load("//third_party/bazel_skylib/lib:selects.bzl", "selects") +load("@bazel_skylib//lib:selects.bzl", "selects") licenses(["notice"]) @@ -36,8 +36,8 @@ selects.config_setting_group( name = "norust_or_windows_or_android", match_any = [ ":no_link_with_rust", - "//tools/cc_target_os:windows", - "//tools/cc_target_os:android", + "@platforms//os:windows", + "@platforms//os:android", ], ) @@ -159,7 +159,7 @@ cc_test( "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -183,7 +183,7 @@ cc_test( "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -206,7 +206,7 @@ cc_test( "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -227,7 +227,7 @@ cc_test( "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -247,7 +247,7 @@ cc_test( "@com_google_absl//absl/types:variant", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -267,7 +267,7 @@ cc_test( "@com_google_absl//absl/strings", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -294,7 +294,7 @@ cc_test( "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ @@ -317,7 +317,7 @@ cc_test( "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ diff --git a/presence/implementation/mediums/BUILD b/presence/implementation/mediums/BUILD index c8ebe2df..e30cdad4 100644 --- a/presence/implementation/mediums/BUILD +++ b/presence/implementation/mediums/BUILD @@ -50,7 +50,7 @@ cc_test( "@com_github_protobuf_matchers//protobuf-matchers", "@com_google_googletest//:gtest_main", ] + select({ - "//tools/cc_target_os:windows": [ + "@platforms//os:windows": [ "//internal/platform/implementation/windows", ], "//conditions:default": [ From 7caeb98443ab872d2c308b53b4ae02c9e2abeb85 Mon Sep 17 00:00:00 2001 From: Anay Wadhera Date: Wed, 3 May 2023 13:31:41 -0700 Subject: [PATCH 63/63] Remove v2 callbacks from client_proxy PiperOrigin-RevId: 529181183 --- connections/implementation/client_proxy.h | 47 ----------------------- 1 file changed, 47 deletions(-) diff --git a/connections/implementation/client_proxy.h b/connections/implementation/client_proxy.h index 53457101..f3bc81bf 100644 --- a/connections/implementation/client_proxy.h +++ b/connections/implementation/client_proxy.h @@ -199,53 +199,6 @@ class ClientProxy final { std::string Dump(); - //********************************** V2 ********************************** - void OnDeviceFound(const absl::string_view service_id, - const NearbyDevice& device, - location::nearby::proto::connections::Medium medium); - // Proxies to the client's DiscoveryListener::OnEndpointLost() callback. - void OnEndpointLost(absl::string_view service_id, const NearbyDevice& device); - - // Proxies to the client's ConnectionListener::OnInitiated() callback. - void OnConnectionInitiated(const NearbyDevice& device, - const ConnectionResponseInfo& info, - const ConnectionOptions& connection_options, - const ConnectionListener& listener, - absl::string_view connection_token); - - void OnConnectionAccepted(const NearbyDevice& device); - void OnConnectionRejected(const NearbyDevice& device, const Status& status); - - void OnBandwidthChanged(const NearbyDevice& device, Medium new_medium); - - // If notify is true, also calls the client's - // ConnectionListener.disconnected_cb() callback. - void OnDisconnected(const NearbyDevice& device, bool notify); - - BooleanMediumSelector GetUpgradableMediums(const NearbyDevice& device) const; - bool IsConnectedToEndpoint(const NearbyDevice& device) const; - // No payloads should be sent until isConnectedToEndpoint() - // returns true. - bool HasPendingConnectionToEndpoint(const NearbyDevice& device) const; - bool HasLocalEndpointResponded(const NearbyDevice& device) const; - bool HasRemoteEndpointResponded(const NearbyDevice& device) const; - void LocalEndpointAcceptedConnection(const NearbyDevice& device, - const PayloadListener& listener); - void LocalEndpointRejectedConnection(const NearbyDevice& device); - void RemoteEndpointAcceptedConnection(const NearbyDevice& device); - void RemoteEndpointRejectedConnection(const NearbyDevice& device); - bool IsConnectionAccepted(const NearbyDevice& device) const; - bool IsConnectionRejected(const NearbyDevice& device) const; - - void OnPayload(const NearbyDevice& device, Payload payload); - void OnPayloadProgress(const NearbyDevice& device, - const PayloadProgressInfo& info); - bool LocalConnectionIsAccepted(const NearbyDevice& device) const; - bool RemoteConnectionIsAccepted(const NearbyDevice& device) const; - void AddCancellationFlag(const NearbyDevice& device); - CancellationFlag* GetCancellationFlag(const NearbyDevice& device); - void CancelEndpoint(const NearbyDevice& device); - const location::nearby::connections::OsInfo& GetLocalOsInfo() const; std::optional GetRemoteOsInfo( absl::string_view endpoint_id) const;