Increase plugin life time

A plugin is created when it is first needed and destroyed when the FP device
is destroyed. This allows the plugins to keep state during long running
operations such as presenting a UI query.

PiperOrigin-RevId: 543502491
This commit is contained in:
Janusz Sobczak
2023-06-26 11:58:56 -07:00
committed by Copybara-Service
parent c5c65714a0
commit 33abd7d879
7 changed files with 76 additions and 9 deletions
+28 -6
View File
@@ -39,11 +39,14 @@ FastPairService::FastPairService()
: FastPairService(std::make_unique<FastPairRepositoryImpl>()) {}
FastPairService::FastPairService(std::unique_ptr<FastPairRepository> repository)
: fast_pair_repository_(std::move(repository)) {
: fast_pair_repository_(std::move(repository)),
on_device_destroyed_callback_(
[this](const FastPairDevice& device) { OnDeviceDestroyed(device); }) {
NearbyFlags::GetInstance().OverrideBoolFlagValue(
platform::config_package_nearby::nearby_platform_feature::
kEnableBleV2Gatt,
true);
devices_.AddObserver(&on_device_destroyed_callback_);
seeker_ = std::make_unique<FastPairSeekerImpl>(
FastPairSeekerImpl::ServiceCallbacks{
.on_initial_discovery =
@@ -81,8 +84,10 @@ absl::Status FastPairService::RegisterPluginProvider(
absl::string_view name, std::unique_ptr<FastPairPluginProvider> provider) {
Future<absl::Status> result;
executor_.Execute("register-plugin", [&]() {
bool success =
providers_.insert({std::string(name), std::move(provider)}).second;
bool success = plugin_states_
.insert({std::string(name),
PluginState{.provider = std::move(provider)}})
.second;
absl::Status status = success
? absl::OkStatus()
: absl::AlreadyExistsError(absl::StrFormat(
@@ -97,7 +102,7 @@ absl::Status FastPairService::RegisterPluginProvider(
absl::Status FastPairService::UnregisterPluginProvider(absl::string_view name) {
Future<absl::Status> result;
executor_.Execute("unregister-plugin", [&]() {
bool success = success = providers_.erase(name);
bool success = success = plugin_states_.erase(name);
absl::Status status = success
? absl::OkStatus()
: absl::NotFoundError(absl::StrFormat(
@@ -114,8 +119,8 @@ void FastPairService::OnInitialDiscoveryEvent(const FastPairDevice& device,
executor_.Execute("on-initial-discovery", [this, device = &device,
event = std::move(event)]() {
NEARBY_LOGS(INFO) << "OnInitialDiscoveryEvent " << *device;
for (auto& entry : providers_) {
auto plugin = entry.second->GetPlugin(seeker_.get(), device);
for (auto& entry : plugin_states_) {
auto plugin = entry.second.GetPlugin(seeker_.get(), device);
plugin->OnInitialDiscoveryEvent(event);
}
});
@@ -131,5 +136,22 @@ void FastPairService::OnBatteryEvent(const FastPairDevice& device,
void FastPairService::OnRingEvent(const FastPairDevice& device,
RingEvent event) {}
void FastPairService::OnDeviceDestroyed(const FastPairDevice& device) {
NEARBY_LOGS(INFO) << "OnDeviceDestroyed " << device;
for (auto& entry : plugin_states_) {
entry.second.plugins.erase(&device);
}
}
FastPairPlugin* FastPairService::PluginState::GetPlugin(
FastPairSeeker* seeker, const FastPairDevice* device) {
auto it = plugins.find(device);
if (it != plugins.end()) {
return it->second.get();
}
auto result = plugins.insert({device, provider->GetPlugin(seeker, device)});
DCHECK(result.second);
return result.first->second.get();
}
} // namespace fastpair
} // namespace nearby
+12 -2
View File
@@ -57,6 +57,14 @@ class FastPairService {
FastPairSeeker* GetSeeker() const { return seeker_.get(); }
private:
struct PluginState {
// Gets the plugin for `device`. Creates the plugin if it does not exist.
FastPairPlugin* GetPlugin(FastPairSeeker* seeker,
const FastPairDevice* device);
std::unique_ptr<FastPairPluginProvider> provider;
absl::flat_hash_map<const FastPairDevice*, std::unique_ptr<FastPairPlugin>>
plugins;
};
void OnInitialDiscoveryEvent(const FastPairDevice& device,
InitialDiscoveryEvent event);
void OnSubsequentDiscoveryEvent(const FastPairDevice& device,
@@ -65,12 +73,14 @@ class FastPairService {
void OnScreenEvent(const FastPairDevice& device, ScreenEvent event);
void OnBatteryEvent(const FastPairDevice& device, BatteryEvent event);
void OnRingEvent(const FastPairDevice& device, RingEvent event);
void OnDeviceDestroyed(const FastPairDevice& device);
SingleThreadExecutor executor_;
std::unique_ptr<FastPairSeeker> seeker_;
absl::flat_hash_map<std::string, std::unique_ptr<FastPairPluginProvider>>
providers_;
// Plugin name is the key.
absl::flat_hash_map<std::string, PluginState> plugin_states_;
FastPairDeviceRepository devices_{&executor_};
std::unique_ptr<FastPairRepository> fast_pair_repository_;
FastPairDeviceRepository::RemoveDeviceCallback on_device_destroyed_callback_;
};
} // namespace fastpair
+1
View File
@@ -18,6 +18,7 @@ cc_library(
"//fastpair/repository:device_repository",
"//fastpair/scanning:scanner",
"//internal/platform:types",
"@com_google_absl//absl/functional:any_invocable",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings:str_format",
],
+2
View File
@@ -40,8 +40,10 @@ cc_library(
visibility = ["//fastpair:__subpackages__"],
deps = [
"//fastpair/common",
"//internal/base",
"//internal/platform:logging",
"//internal/platform:types",
"@com_google_absl//absl/functional:any_invocable",
],
)
@@ -47,7 +47,10 @@ void FastPairDeviceRepository::RemoveDevice(const FastPairDevice* device) {
// Tasks running in the background may still be referencing `device`. Defering
// the destruction to the background thread should prevent use-after-free
// errors.
executor_->Execute([fast_pair_device = std::move(fast_pair_device)]() {
executor_->Execute([this, fast_pair_device = std::move(fast_pair_device)]() {
for (auto* callback : observers_.GetObservers()) {
(*callback)(*fast_pair_device);
}
NEARBY_LOGS(VERBOSE) << "Destroyed FP device: " << fast_pair_device;
});
}
@@ -19,7 +19,9 @@
#include <optional>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "fastpair/common/fast_pair_device.h"
#include "internal/base/observer_list.h"
#include "internal/platform/mutex.h"
#include "internal/platform/single_thread_executor.h"
@@ -29,6 +31,12 @@ namespace fastpair {
// Owner of `FastPairDevice` instances.
class FastPairDeviceRepository {
public:
// Called on the background thread right before `device` is destroyed.
// The callbacks are not called when FastPairDeviceRepository is
// destructing.
using RemoveDeviceCallback =
absl::AnyInvocable<void(const FastPairDevice& device)>;
explicit FastPairDeviceRepository(SingleThreadExecutor* executor)
: executor_(executor) {}
@@ -46,12 +54,20 @@ class FastPairDeviceRepository {
// or BLE.
std::optional<FastPairDevice*> FindDevice(absl::string_view mac_address);
void AddObserver(RemoveDeviceCallback* observer) {
observers_.AddObserver(observer);
}
void RemoveObserver(RemoveDeviceCallback* observer) {
observers_.RemoveObserver(observer);
}
private:
// Removes `device` from `devices_`.
std::unique_ptr<FastPairDevice> ExtractDevice(const FastPairDevice* device);
Mutex mutex_;
SingleThreadExecutor* executor_;
std::vector<std::unique_ptr<FastPairDevice>> devices_ ABSL_GUARDED_BY(mutex_);
ObserverList<RemoveDeviceCallback> observers_;
};
} // namespace fastpair
@@ -100,6 +100,19 @@ TEST(FastPairDeviceRepositoryTest, RemovingNonRegisteredDeviceIsSafe) {
EXPECT_FALSE(repo.FindDevice(kBleAddress).has_value());
}
TEST(FastPairDeviceRepositoryTest, RemovingDeviceCallsCallback) {
SingleThreadExecutor executor;
FastPairDeviceRepository repo(&executor);
FastPairDevice* device = repo.AddDevice(std::make_unique<FastPairDevice>(
kModelId, kBleAddress, Protocol::kFastPairInitialPairing));
FastPairDeviceRepository::RemoveDeviceCallback callback =
[&](const FastPairDevice& device) {};
repo.AddObserver(&callback);
repo.RemoveDevice(device);
EXPECT_FALSE(repo.FindDevice(kBleAddress).has_value());
}
} // namespace
} // namespace fastpair