Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / android / network_change_notifier_android.cc
blob982923507d8a1b2321b49771e8390e66ae350f32
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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.
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.
22 // This leads to a design involving the following native classes:
23 // 1) NetworkChangeNotifierFactoryAndroid ('factory')
24 // 2) NetworkChangeNotifierDelegateAndroid ('delegate')
25 // 3) NetworkChangeNotifierAndroid ('notifier')
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).
36 ////////////////////////////////////////////////////////////////////////////////
37 // Propagation of network change notifications:
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 than processes the
54 // state change, and notifies each of its observers on their threads.
56 // This can also be seen as:
57 // Android platform -> NetworkChangeNotifier (Java) ->
58 // NetworkChangeNotifierDelegateAndroid -> NetworkChangeNotifierAndroid.
60 #include "net/android/network_change_notifier_android.h"
62 #include "base/threading/thread.h"
63 #include "net/base/address_tracker_linux.h"
64 #include "net/dns/dns_config_service_posix.h"
66 namespace net {
68 // Thread on which we can run DnsConfigService, which requires a TYPE_IO
69 // message loop to monitor /system/etc/hosts.
70 class NetworkChangeNotifierAndroid::DnsConfigServiceThread
71 : public base::Thread,
72 public NetworkChangeNotifier::NetworkChangeObserver {
73 public:
74 DnsConfigServiceThread(const DnsConfig* dns_config_for_testing)
75 : base::Thread("DnsConfigService"),
76 dns_config_for_testing_(dns_config_for_testing),
77 creation_time_(base::Time::Now()),
78 address_tracker_(base::Bind(base::DoNothing),
79 base::Bind(base::DoNothing),
80 // We're only interested in tunnel interface changes.
81 base::Bind(NotifyNetworkChangeNotifierObservers),
82 base::hash_set<std::string>()) {}
84 ~DnsConfigServiceThread() override {
85 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
86 Stop();
89 void InitAfterStart() {
90 DCHECK(IsRunning());
91 NetworkChangeNotifier::AddNetworkChangeObserver(this);
94 void Init() override {
95 address_tracker_.Init();
96 dns_config_service_.reset(new internal::DnsConfigServicePosix());
97 if (dns_config_for_testing_)
98 dns_config_service_->SetDnsConfigForTesting(dns_config_for_testing_);
99 dns_config_service_->WatchConfig(
100 base::Bind(&DnsConfigServiceThread::DnsConfigChangeCallback,
101 base::Unretained(this)));
104 void CleanUp() override { dns_config_service_.reset(); }
106 static void NotifyNetworkChangeNotifierObservers() {
107 NetworkChangeNotifier::NotifyObserversOfIPAddressChange();
108 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange();
111 private:
112 void DnsConfigChangeCallback(const DnsConfig& config) {
113 DCHECK(task_runner()->BelongsToCurrentThread());
114 if (dns_config_service_->SeenChangeSince(creation_time_)) {
115 NetworkChangeNotifier::SetDnsConfig(config);
116 } else {
117 NetworkChangeNotifier::SetInitialDnsConfig(config);
121 // NetworkChangeNotifier::NetworkChangeObserver implementation:
122 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
123 task_runner()->PostTask(
124 FROM_HERE,
125 base::Bind(&internal::DnsConfigServicePosix::OnNetworkChanged,
126 base::Unretained(dns_config_service_.get()), type));
129 const DnsConfig* dns_config_for_testing_;
130 const base::Time creation_time_;
131 scoped_ptr<internal::DnsConfigServicePosix> dns_config_service_;
132 // Used to detect tunnel state changes.
133 internal::AddressTrackerLinux address_tracker_;
135 DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread);
138 NetworkChangeNotifierAndroid::~NetworkChangeNotifierAndroid() {
139 delegate_->RemoveObserver(this);
142 NetworkChangeNotifier::ConnectionType
143 NetworkChangeNotifierAndroid::GetCurrentConnectionType() const {
144 return delegate_->GetCurrentConnectionType();
147 double NetworkChangeNotifierAndroid::GetCurrentMaxBandwidth() const {
148 return delegate_->GetCurrentMaxBandwidth();
151 void NetworkChangeNotifierAndroid::OnConnectionTypeChanged() {
152 DnsConfigServiceThread::NotifyNetworkChangeNotifierObservers();
155 void NetworkChangeNotifierAndroid::OnMaxBandwidthChanged(
156 double max_bandwidth_mbps) {
157 NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(
158 max_bandwidth_mbps);
161 // static
162 bool NetworkChangeNotifierAndroid::Register(JNIEnv* env) {
163 return NetworkChangeNotifierDelegateAndroid::Register(env);
166 NetworkChangeNotifierAndroid::NetworkChangeNotifierAndroid(
167 NetworkChangeNotifierDelegateAndroid* delegate,
168 const DnsConfig* dns_config_for_testing)
169 : NetworkChangeNotifier(NetworkChangeCalculatorParamsAndroid()),
170 delegate_(delegate),
171 dns_config_service_thread_(
172 new DnsConfigServiceThread(dns_config_for_testing)) {
173 delegate_->AddObserver(this);
174 dns_config_service_thread_->StartWithOptions(
175 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
176 // Wait until Init is called on the DNS config thread before
177 // calling InitAfterStart.
178 dns_config_service_thread_->WaitUntilThreadStarted();
179 dns_config_service_thread_->InitAfterStart();
182 // static
183 NetworkChangeNotifier::NetworkChangeCalculatorParams
184 NetworkChangeNotifierAndroid::NetworkChangeCalculatorParamsAndroid() {
185 NetworkChangeCalculatorParams params;
186 // IPAddressChanged is produced immediately prior to ConnectionTypeChanged
187 // so delay IPAddressChanged so they get merged with the following
188 // ConnectionTypeChanged signal.
189 params.ip_address_offline_delay_ = base::TimeDelta::FromSeconds(1);
190 params.ip_address_online_delay_ = base::TimeDelta::FromSeconds(1);
191 params.connection_type_offline_delay_ = base::TimeDelta::FromSeconds(0);
192 params.connection_type_online_delay_ = base::TimeDelta::FromSeconds(0);
193 return params;
196 } // namespace net