// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_
#define NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_
#include <netlistmgr.h>
#include <wrl/client.h>
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/threading/sequence_bound.h"
#include "base/win/windows_version.h"
#include "net/base/net_export.h"
#include "net/base/network_change_notifier.h"
namespace net {
class NetworkCostManagerEventSinkWin;
// Uses the `INetworkCostManager` Windows OS API to monitor the cost of the
// current connection. `INetworkCostManager` performs blocking IO and
// synchronous RPC, which must be accessed through a thread pool worker thread.
// `NetworkCostChangeNotifierWin` uses `base::SequenceBound` to prevent these
// expensive operations from happening on the UI thread.
class NET_EXPORT_PRIVATE NetworkCostChangeNotifierWin final {
public:
// `INetworkCostManager` requires Windows Build 19041 or higher. On prior
// builds, calls to the Windows OS API `IConnectionPoint::Advise()` may hang.
static constexpr base::win::Version kSupportedOsVersion =
base::win::Version::WIN10_20H1;
using CostChangedCallback =
base::RepeatingCallback<void(NetworkChangeNotifier::ConnectionCost)>;
// Constructs a new instance using a COM STA single threaded task runner.
// Posts the task that subscribes to cost change events using Windows OS APIs.
static base::SequenceBound<NetworkCostChangeNotifierWin> CreateInstance(
CostChangedCallback cost_changed_callback);
// Use `CreateInstance()` above. This constructor is public for use by
// `base::SequenceBound` only.
explicit NetworkCostChangeNotifierWin(
CostChangedCallback cost_changed_callback);
~NetworkCostChangeNotifierWin();
// Tests use this hook to provide a fake implementation of the OS APIs.
// The fake implementation enables tests to simulate different network
// conditions.
using CoCreateInstanceCallback = base::RepeatingCallback<
HRESULT(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>;
static void OverrideCoCreateInstanceForTesting(
CoCreateInstanceCallback callback_for_testing);
NetworkCostChangeNotifierWin(const NetworkCostChangeNotifierWin&) = delete;
NetworkCostChangeNotifierWin& operator=(const NetworkCostChangeNotifierWin&) =
delete;
private:
// Creates `INetworkCostManager` for `cost_manager_` and subscribe to cost
// change events.
void StartWatching();
// Stops monitoring the cost of the current connection by unsubscribing to
// `INetworkCostManager` events and releasing all members.
void StopWatching();
// Gets the current cost from `cost_manager_` and then runs
// `cost_changed_callback_`.
void HandleCostChanged();
// All members must be accessed on the sequence from `sequence_checker_`
SEQUENCE_CHECKER(sequence_checker_);
CostChangedCallback cost_changed_callback_;
Microsoft::WRL::ComPtr<INetworkCostManager> cost_manager_;
Microsoft::WRL::ComPtr<NetworkCostManagerEventSinkWin>
cost_manager_event_sink_;
base::WeakPtrFactory<NetworkCostChangeNotifierWin> weak_ptr_factory_{this};
};
} // namespace net
#endif // NET_BASE_NETWORK_COST_CHANGE_NOTIFIER_WIN_H_