xref: /aosp_15_r20/external/cronet/net/android/network_change_notifier_android.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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 ////////////////////////////////////////////////////////////////////////////////
6 // Threading considerations:
7 //
8 // This class is designed to meet various threading guarantees starting from the
9 // ones imposed by NetworkChangeNotifier:
10 // - The notifier can be constructed on any thread.
11 // - GetCurrentConnectionType() can be called on any thread.
12 //
13 // The fact that this implementation of NetworkChangeNotifier is backed by a
14 // Java side singleton class (see NetworkChangeNotifier.java) adds another
15 // threading constraint:
16 // - The calls to the Java side (stateful) object must be performed from a
17 //   single thread. This object happens to be a singleton which is used on the
18 //   application side on the main thread. Therefore all the method calls from
19 //   the native NetworkChangeNotifierAndroid class to its Java counterpart are
20 //   performed on the main thread.
21 //
22 // This leads to a design involving the following native classes:
23 // 1) NetworkChangeNotifierFactoryAndroid ('factory')
24 // 2) NetworkChangeNotifierDelegateAndroid ('delegate')
25 // 3) NetworkChangeNotifierAndroid ('notifier')
26 //
27 // The factory constructs and owns the delegate. The factory is constructed and
28 // destroyed on the main thread which makes it construct and destroy the
29 // delegate on the main thread too. This guarantees that the calls to the Java
30 // side are performed on the main thread.
31 // Note that after the factory's construction, the factory's creation method can
32 // be called from any thread since the delegate's construction (performing the
33 // JNI calls) already happened on the main thread (when the factory was
34 // constructed).
35 //
36 ////////////////////////////////////////////////////////////////////////////////
37 // Propagation of network change notifications:
38 //
39 // When the factory is requested to create a new instance of the notifier, the
40 // factory passes the delegate to the notifier (without transferring ownership).
41 // Note that there is a one-to-one mapping between the factory and the
42 // delegate as explained above. But the factory naturally creates multiple
43 // instances of the notifier. That means that there is a one-to-many mapping
44 // between delegate and notifier (i.e. a single delegate can be shared by
45 // multiple notifiers).
46 // At construction the notifier (which is also an observer) subscribes to
47 // notifications fired by the delegate. These notifications, received by the
48 // delegate (and forwarded to the notifier(s)), are sent by the Java side
49 // notifier (see NetworkChangeNotifier.java) and are initiated by the Android
50 // platform.
51 // Notifications from the Java side always arrive on the main thread. The
52 // delegate then forwards these notifications to the threads of each observer
53 // (network change notifier). The network change notifier then processes the
54 // state change, and notifies each of its observers on their threads.
55 //
56 // This can also be seen as:
57 // Android platform -> NetworkChangeNotifier (Java) ->
58 // NetworkChangeNotifierDelegateAndroid -> NetworkChangeNotifierAndroid.
59 
60 #include "net/android/network_change_notifier_android.h"
61 
62 #include <string>
63 #include <unordered_set>
64 
65 #include "base/android/build_info.h"
66 #include "base/functional/bind.h"
67 #include "base/functional/callback_helpers.h"
68 #include "base/metrics/histogram_macros.h"
69 #include "base/task/sequenced_task_runner.h"
70 #include "base/task/task_traits.h"
71 #include "base/task/thread_pool.h"
72 #include "base/threading/thread.h"
73 #include "net/base/address_tracker_linux.h"
74 
75 namespace net {
76 
77 // Expose handles::kInvalidNetworkHandle out to Java as NetId.INVALID. The
78 // notion of a NetID is an Android framework one, see android.net.Network.netId.
79 // NetworkChangeNotifierAndroid implements handles::NetworkHandle to simply be
80 // the NetID.
81 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
82 enum NetId {
83   // Cannot use |handles::kInvalidNetworkHandle| here as the Java generator
84   // fails, instead enforce their equality with CHECK in
85   // NetworkChangeNotifierAndroid().
86   INVALID = -1
87 };
88 
89 // Thread on which we can run DnsConfigService, which requires a TYPE_IO
90 // message loop to monitor /system/etc/hosts.
91 class NetworkChangeNotifierAndroid::BlockingThreadObjects {
92  public:
BlockingThreadObjects()93   BlockingThreadObjects()
94       : address_tracker_(
95             base::DoNothing(),
96             base::DoNothing(),
97             // We're only interested in tunnel interface changes.
98             base::BindRepeating(NotifyNetworkChangeNotifierObservers),
99             std::unordered_set<std::string>()) {}
100   BlockingThreadObjects(const BlockingThreadObjects&) = delete;
101   BlockingThreadObjects& operator=(const BlockingThreadObjects&) = delete;
102 
Init()103   void Init() {
104     address_tracker_.Init();
105   }
106 
NotifyNetworkChangeNotifierObservers()107   static void NotifyNetworkChangeNotifierObservers() {
108     NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
109     NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange();
110   }
111 
112  private:
113   // Used to detect tunnel state changes.
114   internal::AddressTrackerLinux address_tracker_;
115 };
116 
~NetworkChangeNotifierAndroid()117 NetworkChangeNotifierAndroid::~NetworkChangeNotifierAndroid() {
118   ClearGlobalPointer();
119   delegate_->UnregisterObserver(this);
120 }
121 
122 NetworkChangeNotifier::ConnectionType
GetCurrentConnectionType() const123 NetworkChangeNotifierAndroid::GetCurrentConnectionType() const {
124   return delegate_->GetCurrentConnectionType();
125 }
126 
127 NetworkChangeNotifier::ConnectionCost
GetCurrentConnectionCost()128 NetworkChangeNotifierAndroid::GetCurrentConnectionCost() {
129   return delegate_->GetCurrentConnectionCost();
130 }
131 
132 NetworkChangeNotifier::ConnectionSubtype
GetCurrentConnectionSubtype() const133 NetworkChangeNotifierAndroid::GetCurrentConnectionSubtype() const {
134   return delegate_->GetCurrentConnectionSubtype();
135 }
136 
GetCurrentMaxBandwidthAndConnectionType(double * max_bandwidth_mbps,ConnectionType * connection_type) const137 void NetworkChangeNotifierAndroid::GetCurrentMaxBandwidthAndConnectionType(
138     double* max_bandwidth_mbps,
139     ConnectionType* connection_type) const {
140   delegate_->GetCurrentMaxBandwidthAndConnectionType(max_bandwidth_mbps,
141                                                      connection_type);
142 }
143 
ForceNetworkHandlesSupportedForTesting()144 void NetworkChangeNotifierAndroid::ForceNetworkHandlesSupportedForTesting() {
145   force_network_handles_supported_for_testing_ = true;
146 }
147 
AreNetworkHandlesCurrentlySupported() const148 bool NetworkChangeNotifierAndroid::AreNetworkHandlesCurrentlySupported() const {
149   // Notifications for API using handles::NetworkHandles and querying using
150   // handles::NetworkHandles only implemented for Android versions >= L.
151   return force_network_handles_supported_for_testing_ ||
152          (base::android::BuildInfo::GetInstance()->sdk_int() >=
153               base::android::SDK_VERSION_LOLLIPOP &&
154           !delegate_->RegisterNetworkCallbackFailed());
155 }
156 
GetCurrentConnectedNetworks(NetworkChangeNotifier::NetworkList * networks) const157 void NetworkChangeNotifierAndroid::GetCurrentConnectedNetworks(
158     NetworkChangeNotifier::NetworkList* networks) const {
159   delegate_->GetCurrentlyConnectedNetworks(networks);
160 }
161 
162 NetworkChangeNotifier::ConnectionType
GetCurrentNetworkConnectionType(handles::NetworkHandle network) const163 NetworkChangeNotifierAndroid::GetCurrentNetworkConnectionType(
164     handles::NetworkHandle network) const {
165   return delegate_->GetNetworkConnectionType(network);
166 }
167 
GetCurrentDefaultNetwork() const168 handles::NetworkHandle NetworkChangeNotifierAndroid::GetCurrentDefaultNetwork()
169     const {
170   return delegate_->GetCurrentDefaultNetwork();
171 }
172 
OnConnectionTypeChanged()173 void NetworkChangeNotifierAndroid::OnConnectionTypeChanged() {
174   BlockingThreadObjects::NotifyNetworkChangeNotifierObservers();
175 }
176 
OnConnectionCostChanged()177 void NetworkChangeNotifierAndroid::OnConnectionCostChanged() {
178   NetworkChangeNotifier::NotifyObserversOfConnectionCostChange();
179 }
180 
OnMaxBandwidthChanged(double max_bandwidth_mbps,ConnectionType type)181 void NetworkChangeNotifierAndroid::OnMaxBandwidthChanged(
182     double max_bandwidth_mbps,
183     ConnectionType type) {
184   NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps,
185                                                              type);
186 }
187 
OnNetworkConnected(handles::NetworkHandle network)188 void NetworkChangeNotifierAndroid::OnNetworkConnected(
189     handles::NetworkHandle network) {
190   NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
191       NetworkChangeType::kConnected, network);
192 }
193 
OnNetworkSoonToDisconnect(handles::NetworkHandle network)194 void NetworkChangeNotifierAndroid::OnNetworkSoonToDisconnect(
195     handles::NetworkHandle network) {
196   NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
197       NetworkChangeType::kSoonToDisconnect, network);
198 }
199 
OnNetworkDisconnected(handles::NetworkHandle network)200 void NetworkChangeNotifierAndroid::OnNetworkDisconnected(
201     handles::NetworkHandle network) {
202   NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
203       NetworkChangeType::kDisconnected, network);
204 }
205 
OnNetworkMadeDefault(handles::NetworkHandle network)206 void NetworkChangeNotifierAndroid::OnNetworkMadeDefault(
207     handles::NetworkHandle network) {
208   NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
209       NetworkChangeType::kMadeDefault, network);
210 }
211 
OnDefaultNetworkActive()212 void NetworkChangeNotifierAndroid::OnDefaultNetworkActive() {
213   NetworkChangeNotifier::NotifyObserversOfDefaultNetworkActive();
214 }
215 
NetworkChangeNotifierAndroid(NetworkChangeNotifierDelegateAndroid * delegate)216 NetworkChangeNotifierAndroid::NetworkChangeNotifierAndroid(
217     NetworkChangeNotifierDelegateAndroid* delegate)
218     : NetworkChangeNotifier(NetworkChangeCalculatorParamsAndroid()),
219       delegate_(delegate),
220       blocking_thread_objects_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {
221   static_assert(NetId::INVALID == handles::kInvalidNetworkHandle,
222                 "handles::kInvalidNetworkHandle doesn't match NetId::INVALID");
223   delegate_->RegisterObserver(this);
224   // Since Android P, ConnectivityManager's signals include VPNs so we don't
225   // need to use AddressTrackerLinux.
226   if (base::android::BuildInfo::GetInstance()->sdk_int() <
227       base::android::SDK_VERSION_P) {
228     // |blocking_thread_objects_| will live on this runner.
229     scoped_refptr<base::SequencedTaskRunner> blocking_thread_runner =
230         base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
231     blocking_thread_objects_ =
232         std::unique_ptr<BlockingThreadObjects, base::OnTaskRunnerDeleter>(
233             new BlockingThreadObjects(),
234             // Ensure |blocking_thread_objects_| lives on
235             // |blocking_thread_runner| to prevent races where
236             // NetworkChangeNotifierAndroid outlives
237             // TaskEnvironment. https://crbug.com/938126
238             base::OnTaskRunnerDeleter(blocking_thread_runner));
239     blocking_thread_runner->PostTask(
240         FROM_HERE,
241         base::BindOnce(&BlockingThreadObjects::Init,
242                        // The Unretained pointer is safe here because it's
243                        // posted before the deleter can post.
244                        base::Unretained(blocking_thread_objects_.get())));
245   }
246 }
247 
248 // static
249 NetworkChangeNotifier::NetworkChangeCalculatorParams
NetworkChangeCalculatorParamsAndroid()250 NetworkChangeNotifierAndroid::NetworkChangeCalculatorParamsAndroid() {
251   NetworkChangeCalculatorParams params;
252   // IPAddressChanged is produced immediately prior to ConnectionTypeChanged
253   // so delay IPAddressChanged so they get merged with the following
254   // ConnectionTypeChanged signal.
255   params.ip_address_offline_delay_ = base::Seconds(1);
256   params.ip_address_online_delay_ = base::Seconds(1);
257   params.connection_type_offline_delay_ = base::Seconds(0);
258   params.connection_type_online_delay_ = base::Seconds(0);
259   return params;
260 }
261 
IsDefaultNetworkActiveInternal()262 bool NetworkChangeNotifierAndroid::IsDefaultNetworkActiveInternal() {
263   return delegate_->IsDefaultNetworkActive();
264 }
265 
DefaultNetworkActiveObserverAdded()266 void NetworkChangeNotifierAndroid::DefaultNetworkActiveObserverAdded() {
267   delegate_->DefaultNetworkActiveObserverAdded();
268 }
269 
DefaultNetworkActiveObserverRemoved()270 void NetworkChangeNotifierAndroid::DefaultNetworkActiveObserverRemoved() {
271   delegate_->DefaultNetworkActiveObserverRemoved();
272 }
273 
274 }  // namespace net
275