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. 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 than 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 "base/threading/thread.h" 63 #include "net/base/address_tracker_linux.h" 64 #include "net/dns/dns_config_service.h" 65 66 namespace net { 67 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: 73 DnsConfigServiceThread() 74 : base::Thread("DnsConfigService"), 75 address_tracker_(base::Bind(base::DoNothing), 76 base::Bind(base::DoNothing), 77 // We're only interested in tunnel interface changes. 78 base::Bind(NotifyNetworkChangeNotifierObservers)) {} 79 80 virtual ~DnsConfigServiceThread() { 81 Stop(); 82 } 83 84 virtual void Init() OVERRIDE { 85 address_tracker_.Init(); 86 dns_config_service_ = DnsConfigService::CreateSystemService(); 87 dns_config_service_->WatchConfig( 88 base::Bind(&NetworkChangeNotifier::SetDnsConfig)); 89 } 90 91 virtual void CleanUp() OVERRIDE { 92 dns_config_service_.reset(); 93 } 94 95 static void NotifyNetworkChangeNotifierObservers() { 96 NetworkChangeNotifier::NotifyObserversOfIPAddressChange(); 97 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange(); 98 } 99 100 private: 101 scoped_ptr<DnsConfigService> dns_config_service_; 102 // Used to detect tunnel state changes. 103 internal::AddressTrackerLinux address_tracker_; 104 105 DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread); 106 }; 107 108 NetworkChangeNotifierAndroid::~NetworkChangeNotifierAndroid() { 109 delegate_->RemoveObserver(this); 110 } 111 112 NetworkChangeNotifier::ConnectionType 113 NetworkChangeNotifierAndroid::GetCurrentConnectionType() const { 114 return delegate_->GetCurrentConnectionType(); 115 } 116 117 void NetworkChangeNotifierAndroid::OnConnectionTypeChanged() { 118 DnsConfigServiceThread::NotifyNetworkChangeNotifierObservers(); 119 } 120 121 // static 122 bool NetworkChangeNotifierAndroid::Register(JNIEnv* env) { 123 return NetworkChangeNotifierDelegateAndroid::Register(env); 124 } 125 126 NetworkChangeNotifierAndroid::NetworkChangeNotifierAndroid( 127 NetworkChangeNotifierDelegateAndroid* delegate) 128 : NetworkChangeNotifier(NetworkChangeCalculatorParamsAndroid()), 129 delegate_(delegate), 130 dns_config_service_thread_(new DnsConfigServiceThread()) { 131 delegate_->AddObserver(this); 132 dns_config_service_thread_->StartWithOptions( 133 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); 134 } 135 136 // static 137 NetworkChangeNotifier::NetworkChangeCalculatorParams 138 NetworkChangeNotifierAndroid::NetworkChangeCalculatorParamsAndroid() { 139 NetworkChangeCalculatorParams params; 140 // IPAddressChanged is produced immediately prior to ConnectionTypeChanged 141 // so delay IPAddressChanged so they get merged with the following 142 // ConnectionTypeChanged signal. 143 params.ip_address_offline_delay_ = base::TimeDelta::FromSeconds(1); 144 params.ip_address_online_delay_ = base::TimeDelta::FromSeconds(1); 145 params.connection_type_offline_delay_ = base::TimeDelta::FromSeconds(0); 146 params.connection_type_online_delay_ = base::TimeDelta::FromSeconds(0); 147 return params; 148 } 149 150 } // namespace net 151