Home | History | Annotate | Download | only in android
      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