1 // Copyright 2024 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_ 6 #define NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_ 7 8 #include <netlistmgr.h> 9 #include <wrl/client.h> 10 11 #include "base/functional/callback_forward.h" 12 #include "base/memory/weak_ptr.h" 13 #include "base/sequence_checker.h" 14 #include "base/threading/sequence_bound.h" 15 #include "base/win/windows_version.h" 16 #include "net/base/net_export.h" 17 #include "net/base/network_change_notifier.h" 18 19 namespace net { 20 class NetworkCostManagerEventSinkWin; 21 22 // Uses the `INetworkCostManager` Windows OS API to monitor the cost of the 23 // current connection. `INetworkCostManager` performs blocking IO and 24 // synchronous RPC, which must be accessed through a thread pool worker thread. 25 // `NetworkCostChangeNotifierWin` uses `base::SequenceBound` to prevent these 26 // expensive operations from happening on the UI thread. 27 class NET_EXPORT_PRIVATE NetworkCostChangeNotifierWin final { 28 public: 29 // `INetworkCostManager` requires Windows Build 19041 or higher. On prior 30 // builds, calls to the Windows OS API `IConnectionPoint::Advise()` may hang. 31 static constexpr base::win::Version kSupportedOsVersion = 32 base::win::Version::WIN10_20H1; 33 34 using CostChangedCallback = 35 base::RepeatingCallback<void(NetworkChangeNotifier::ConnectionCost)>; 36 37 // Constructs a new instance using a COM STA single threaded task runner. 38 // Posts the task that subscribes to cost change events using Windows OS APIs. 39 static base::SequenceBound<NetworkCostChangeNotifierWin> CreateInstance( 40 CostChangedCallback cost_changed_callback); 41 42 // Use `CreateInstance()` above. This constructor is public for use by 43 // `base::SequenceBound` only. 44 explicit NetworkCostChangeNotifierWin( 45 CostChangedCallback cost_changed_callback); 46 ~NetworkCostChangeNotifierWin(); 47 48 // Tests use this hook to provide a fake implementation of the OS APIs. 49 // The fake implementation enables tests to simulate different network 50 // conditions. 51 using CoCreateInstanceCallback = base::RepeatingCallback< 52 HRESULT(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>; 53 static void OverrideCoCreateInstanceForTesting( 54 CoCreateInstanceCallback callback_for_testing); 55 56 NetworkCostChangeNotifierWin(const NetworkCostChangeNotifierWin&) = delete; 57 NetworkCostChangeNotifierWin& operator=(const NetworkCostChangeNotifierWin&) = 58 delete; 59 60 private: 61 // Creates `INetworkCostManager` for `cost_manager_` and subscribe to cost 62 // change events. 63 void StartWatching(); 64 65 // Stops monitoring the cost of the current connection by unsubscribing to 66 // `INetworkCostManager` events and releasing all members. 67 void StopWatching(); 68 69 // Gets the current cost from `cost_manager_` and then runs 70 // `cost_changed_callback_`. 71 void HandleCostChanged(); 72 73 // All members must be accessed on the sequence from `sequence_checker_` 74 SEQUENCE_CHECKER(sequence_checker_); 75 76 CostChangedCallback cost_changed_callback_; 77 78 Microsoft::WRL::ComPtr<INetworkCostManager> cost_manager_; 79 80 Microsoft::WRL::ComPtr<NetworkCostManagerEventSinkWin> 81 cost_manager_event_sink_; 82 83 base::WeakPtrFactory<NetworkCostChangeNotifierWin> weak_ptr_factory_{this}; 84 }; 85 86 } // namespace net 87 88 #endif // NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_ 89