From 4301bc4fcedacec7a7867b88d52ff82e9430ba82 Mon Sep 17 00:00:00 2001 From: Francis Tsui Date: Thu, 16 Jul 2026 20:10:17 -0700 Subject: [PATCH] Handle system standby PiperOrigin-RevId: 949324299 --- .../implementation/p2p_cluster_pcp_handler.cc | 6 +- .../platform/implementation/device_info.h | 10 +++ .../platform/implementation/windows/BUILD | 8 +- .../implementation/windows/device_info.cc | 74 ++++++++++++++++- .../implementation/windows/device_info.h | 27 +++++- .../generated/nearby_sharing_feature_flags.h | 4 + sharing/nearby_sharing_service_impl.cc | 83 +++++++++++++++++++ sharing/nearby_sharing_service_impl.h | 9 ++ 8 files changed, 215 insertions(+), 6 deletions(-) diff --git a/connections/implementation/p2p_cluster_pcp_handler.cc b/connections/implementation/p2p_cluster_pcp_handler.cc index 709b3651..19f60a99 100644 --- a/connections/implementation/p2p_cluster_pcp_handler.cc +++ b/connections/implementation/p2p_cluster_pcp_handler.cc @@ -307,6 +307,9 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { << bluetooth_classic_advertiser_client_id_; } + wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); + wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); + bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); ble_medium_.StopAdvertising(client->GetAdvertisingServiceId()); ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); @@ -316,9 +319,6 @@ Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { client->GetAdvertisingServiceId()); } - wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); - wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); - if (NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_connections_feature::kEnableAwdl)) { awdl_medium_.StopAdvertising(client->GetAdvertisingServiceId()); diff --git a/internal/platform/implementation/device_info.h b/internal/platform/implementation/device_info.h index 3d3e859a..38101619 100644 --- a/internal/platform/implementation/device_info.h +++ b/internal/platform/implementation/device_info.h @@ -16,6 +16,7 @@ #define PLATFORM_API_DEVICE_INFO_H_ #include +#include #include #include #include @@ -39,6 +40,7 @@ class DeviceInfo { kWindows, kMacOS }; + enum class SuspendResumeEvent { kSuspend, kResume }; virtual ~DeviceInfo() = default; @@ -69,6 +71,14 @@ class DeviceInfo { // Control device sleep virtual bool PreventSleep() = 0; virtual bool AllowSleep() = 0; + + // Monitor suspend/resume events. + // Returns a listener id that can be used to unregister the listener. + virtual int64_t RegisterSuspendResumeListener( + std::function callback) { + return 0; + } + virtual void UnregisterSuspendResumeListener(int64_t listener_id) {} }; template diff --git a/internal/platform/implementation/windows/BUILD b/internal/platform/implementation/windows/BUILD index 94698475..b0021587 100644 --- a/internal/platform/implementation/windows/BUILD +++ b/internal/platform/implementation/windows/BUILD @@ -72,7 +72,13 @@ cc_library( "timer.h", "utils.h", ], - defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"], + defines = [ + "_SILENCE_CLANG_COROUTINE_MESSAGE", + "_WIN32_WINNT=_WIN32_WINNT_WIN10", + ], + linkopts = [ + "powrprof.lib", + ], tags = ["windows"], visibility = ["//visibility:private"], deps = [ diff --git a/internal/platform/implementation/windows/device_info.cc b/internal/platform/implementation/windows/device_info.cc index 348f7ce6..40d8192d 100644 --- a/internal/platform/implementation/windows/device_info.cc +++ b/internal/platform/implementation/windows/device_info.cc @@ -14,13 +14,19 @@ #include "internal/platform/implementation/windows/device_info.h" +// clang-format off #include #include #include +#include +#include +// clang-format on +#include #include #include #include +#include #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" @@ -30,10 +36,19 @@ #include "internal/platform/implementation/windows/device_paths.h" #include "internal/platform/implementation/windows/string_utils.h" #include "internal/platform/implementation/windows/utils.h" +#include "internal/platform/logging.h" namespace nearby::windows { - +namespace { using ::nearby::windows::string_utils::WideStringToString; +} // namespace + +DeviceInfo::~DeviceInfo() { + if (suspend_resume_notification_handle_ != nullptr) { + PowerUnregisterSuspendResumeNotification( + suspend_resume_notification_handle_); + } +} std::optional DeviceInfo::GetOsDeviceName() const { std::optional device_name = GetDnsHostName(); @@ -113,4 +128,61 @@ bool DeviceInfo::AllowSleep() { return session_manager_.AllowSleep(); } +ULONG DeviceInfo::PowerSuspendResumeCallback(PVOID context, ULONG type, + PVOID setting) { + api::DeviceInfo::SuspendResumeEvent event; + switch (type) { + case PBT_APMSUSPEND: + event = api::DeviceInfo::SuspendResumeEvent::kSuspend; + break; + case PBT_APMRESUMESUSPEND: + event = api::DeviceInfo::SuspendResumeEvent::kResume; + break; + default: + return 0; + } + DeviceInfo* device_info = static_cast(context); + device_info->OnSuspendResumeEvent(event); + return 0; +} + +int64_t DeviceInfo::RegisterSuspendResumeListener( + std::function callback) { + absl::MutexLock lock(suspend_resume_mutex_); + int64_t listener_id = ++next_suspend_resume_listener_id_; + suspend_resume_listeners_.emplace(listener_id, std::move(callback)); + if (suspend_resume_listeners_.size() == 1) { + DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS subscribe_params; + subscribe_params.Callback = PowerSuspendResumeCallback; + subscribe_params.Context = this; + PowerRegisterSuspendResumeNotification( + DEVICE_NOTIFY_CALLBACK, &subscribe_params, + &suspend_resume_notification_handle_); + } + return listener_id; +} + +void DeviceInfo::UnregisterSuspendResumeListener(int64_t listener_id) { + absl::MutexLock lock(suspend_resume_mutex_); + suspend_resume_listeners_.erase(listener_id); + if (suspend_resume_listeners_.empty()) { + if (suspend_resume_notification_handle_ != nullptr) { + PowerUnregisterSuspendResumeNotification( + suspend_resume_notification_handle_); + } + suspend_resume_notification_handle_ = nullptr; + } +} + +void DeviceInfo::OnSuspendResumeEvent( + api::DeviceInfo::SuspendResumeEvent event) { + LOG(INFO) << "OnSuspendResumeEvent: " + << (event == DeviceInfo::SuspendResumeEvent::kSuspend ? "kSuspend" + : "kResume"); + absl::MutexLock lock(suspend_resume_mutex_); + for (auto& it : suspend_resume_listeners_) { + it.second(event); + } +} + } // namespace nearby::windows diff --git a/internal/platform/implementation/windows/device_info.h b/internal/platform/implementation/windows/device_info.h index 8de0d388..278a2d68 100644 --- a/internal/platform/implementation/windows/device_info.h +++ b/internal/platform/implementation/windows/device_info.h @@ -15,11 +15,19 @@ #ifndef PLATFORM_IMPL_WINDOWS_DEVICE_INFO_H_ #define PLATFORM_IMPL_WINDOWS_DEVICE_INFO_H_ +// clang-format off +#include +#include +// clang-format on + +#include #include #include #include #include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "internal/base/file_path.h" @@ -31,7 +39,7 @@ namespace windows { class DeviceInfo : public api::DeviceInfo { public: - ~DeviceInfo() override = default; + ~DeviceInfo() override; std::optional GetOsDeviceName() const override; api::DeviceInfo::DeviceType GetDeviceType() const override; @@ -51,9 +59,26 @@ class DeviceInfo : public api::DeviceInfo { bool PreventSleep() override; bool AllowSleep() override; + int64_t RegisterSuspendResumeListener( + std::function callback) + override; + void UnregisterSuspendResumeListener(int64_t listener_id) override; + private: + static ULONG PowerSuspendResumeCallback(PVOID context, ULONG type, + PVOID setting); + void OnSuspendResumeEvent(SuspendResumeEvent event); + mutable absl::Mutex mutex_; SessionManager session_manager_ ABSL_GUARDED_BY(mutex_); + absl::Mutex suspend_resume_mutex_; + int64_t next_suspend_resume_listener_id_ ABSL_GUARDED_BY( + suspend_resume_mutex_) = 0; + absl::flat_hash_map< + int64_t, absl::AnyInvocable> + suspend_resume_listeners_ ABSL_GUARDED_BY(suspend_resume_mutex_); + HPOWERNOTIFY suspend_resume_notification_handle_ + ABSL_GUARDED_BY(suspend_resume_mutex_) = nullptr; }; } // namespace windows diff --git a/sharing/flags/generated/nearby_sharing_feature_flags.h b/sharing/flags/generated/nearby_sharing_feature_flags.h index afe3896e..701baec8 100755 --- a/sharing/flags/generated/nearby_sharing_feature_flags.h +++ b/sharing/flags/generated/nearby_sharing_feature_flags.h @@ -61,6 +61,9 @@ constexpr auto kShowAutoUpdateSetting = // The default time in milliseconds a cached entry can be in LOST state. constexpr auto kDiscoveryCacheLostExpiryMs = flags::Flag(kConfigPackage, "45658774", 15000); +// When true, enable suspend resume listener. +constexpr auto kEnableSuspendResumeListener = + flags::Flag(kConfigPackage, "45815625", false); // When true, enable wifi hotspot medium for HP Realtek devices. constexpr auto kEnableWifiHotspotForHpRealtekDevices = flags::Flag(kConfigPackage, "45673628", false); @@ -105,6 +108,7 @@ inline absl::btree_map&> GetBoolFlags() { {45411589, kEnableRetryResumeTransfer}, {45459748, kEnableSendingDesktopEvents}, {45409033, kShowAutoUpdateSetting}, + {45815625, kEnableSuspendResumeListener}, {45673628, kEnableWifiHotspotForHpRealtekDevices}, {45683539, kUseAlternateServiceUuidForDiscovery}, {45776229, kEnableBackup}, diff --git a/sharing/nearby_sharing_service_impl.cc b/sharing/nearby_sharing_service_impl.cc index 1fa8bc5c..c1b8fed1 100644 --- a/sharing/nearby_sharing_service_impl.cc +++ b/sharing/nearby_sharing_service_impl.cc @@ -44,6 +44,7 @@ #include "absl/strings/escaping.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "absl/types/span.h" #include "internal/base/file_path.h" @@ -134,6 +135,12 @@ constexpr absl::Duration kProcessShutdownPendingTimerDelay = // NOLINT absl::Seconds(15); constexpr absl::Duration kProcessNetworkChangeTimerDelay = absl::Seconds(1); +// Delay invalidating the surface state after a resume event. +// Network activities can cause system to resume for short periods before +// suspending again. This delay allows us to ignore those and only resume +// fully when the system is stable. +constexpr absl::Duration kResumeDelay = absl::Milliseconds(500); + // The maximum number of certificate downloads that can be performed during a // discovery session. // Assuming a 2min discovery session and 10s download interval. @@ -337,6 +344,13 @@ NearbySharingServiceImpl::NearbySharingServiceImpl( OnLockStateChanged(screen_status == nearby::api::DeviceInfo::ScreenStatus::kLocked); }); + if (NearbyFlags::GetInstance().GetBoolFlag( + config_package_nearby::nearby_sharing_feature:: + kEnableSuspendResumeListener)) { + suspend_resume_listener_id_ = + device_info_.RegisterSuspendResumeListener(absl::bind_front( + &NearbySharingServiceImpl::OnSuspendResumeEvent, this)); + } account_manager_.AddObserver(this); settings_->AddSettingsObserver(this); @@ -384,6 +398,8 @@ void NearbySharingServiceImpl::Shutdown( background_receive_callbacks_map_.clear(); device_info_.UnregisterScreenLockedListener(kScreenStateListenerName); + device_info_.UnregisterSuspendResumeListener( + suspend_resume_listener_id_); settings_->RemoveSettingsObserver(this); @@ -1415,6 +1431,42 @@ void NearbySharingServiceImpl::OnLockStateChanged(bool locked) { }); } +void NearbySharingServiceImpl::OnSuspendResumeEvent( + nearby::api::DeviceInfo::SuspendResumeEvent event) { + bool suspended = + event == nearby::api::DeviceInfo::SuspendResumeEvent::kSuspend; + { + absl::MutexLock lock(suspend_mutex_); + suspended_ = suspended; + if (!suspended) { + resume_delay_timer_ = std::make_unique( + *service_thread_, "suspend_resume_timer", kResumeDelay, [this]() { + { + absl::MutexLock lock(suspend_mutex_); + if (suspended_) { + return; + } + } + LOG(INFO) << "InvalidateSurfaceState due to system resume"; + InvalidateSurfaceState(); + }); + } + } + if (suspended) { + RunOnNearbySharingServiceThread("on_suspend", [this]() { + LOG(INFO) << "InvalidateSurfaceState due to system suspend"; + { + absl::MutexLock lock(suspend_mutex_); + if (!suspended_) { + return; + } + resume_delay_timer_.reset(); + } + InvalidateSurfaceState(); + }); + } +} + void NearbySharingServiceImpl::AdapterPresentChanged( sharing::api::BluetoothAdapter* adapter, bool present) { RunOnNearbySharingServiceThread("bt_adapter_present_changed", [this, adapter, @@ -1873,6 +1925,16 @@ void NearbySharingServiceImpl::InvalidateSendSurfaceState() { } void NearbySharingServiceImpl::InvalidateScanningState() { + { + absl::MutexLock lock(suspend_mutex_); + if (suspended_) { + StopScanning(); + VLOG(1) << __func__ + << ": Stopping discovery because the system is suspended."; + return; + } + } + // Stop scanning when screen is off. if (is_screen_locked_) { StopScanning(); @@ -1910,6 +1972,17 @@ void NearbySharingServiceImpl::InvalidateScanningState() { } void NearbySharingServiceImpl::InvalidateFastInitiationAdvertising() { + { + absl::MutexLock lock(suspend_mutex_); + if (suspended_) { + StopFastInitiationAdvertising(); + VLOG(1) << __func__ + << ": Stopping fast initiation advertising because the " + "system is suspended."; + return; + } + } + // Screen is off. Do no work. if (is_screen_locked_) { StopFastInitiationAdvertising(); @@ -1949,6 +2022,16 @@ void NearbySharingServiceImpl::InvalidateFastInitiationAdvertising() { } void NearbySharingServiceImpl::InvalidateAdvertisingState() { + { + absl::MutexLock lock(suspend_mutex_); + if (suspended_) { + StopAdvertising(); + VLOG(1) << __func__ + << ": Stopping advertising because the system is suspended."; + return; + } + } + bool supports_advertising_on_lock_screen = NearbyFlags::GetInstance().GetBoolFlag( config_package_nearby::nearby_sharing_feature:: diff --git a/sharing/nearby_sharing_service_impl.h b/sharing/nearby_sharing_service_impl.h index 668a3e6f..fe799f4b 100644 --- a/sharing/nearby_sharing_service_impl.h +++ b/sharing/nearby_sharing_service_impl.h @@ -31,6 +31,7 @@ #include "location/nearby/sharing/lib/rpc/sharing_rpc_client.h" #include "location/nearby/sharing/lib/sync/sync_manager.h" #include "absl/base/nullability.h" +#include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/functional/any_invocable.h" @@ -219,6 +220,9 @@ class NearbySharingServiceImpl // Handle the state changes of screen lock. void OnLockStateChanged(bool locked); + void OnSuspendResumeEvent( + nearby::api::DeviceInfo::SuspendResumeEvent event); + // Handle the state changes of bluetooth adapter. void AdapterPresentChanged(sharing::api::BluetoothAdapter* adapter, bool present) override; @@ -550,6 +554,11 @@ class NearbySharingServiceImpl proto::DeviceVisibility last_advertised_device_visibility_ = proto::DeviceVisibility::DEVICE_VISIBILITY_UNSPECIFIED; bool advertising_on_screen_locked_ = false; + int64_t suspend_resume_listener_id_ = 0; + absl::Mutex suspend_mutex_; + bool suspended_ ABSL_GUARDED_BY(suspend_mutex_) = false; + std::unique_ptr resume_delay_timer_ + ABSL_GUARDED_BY(suspend_mutex_); }; } // namespace nearby::sharing