Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net;
     18 
     19 import android.content.Context;
     20 import android.net.NetworkInfo.DetailedState;
     21 import android.os.Handler;
     22 import android.os.IBinder;
     23 import android.os.INetworkManagementService;
     24 import android.os.Message;
     25 import android.os.RemoteException;
     26 import android.os.ServiceManager;
     27 import android.util.Log;
     28 
     29 import java.util.concurrent.atomic.AtomicBoolean;
     30 import java.util.concurrent.atomic.AtomicInteger;
     31 
     32 /**
     33  * This class tracks the data connection associated with Ethernet
     34  * This is a singleton class and an instance will be created by
     35  * ConnectivityService.
     36  * @hide
     37  */
     38 public class EthernetDataTracker implements NetworkStateTracker {
     39     private static final String NETWORKTYPE = "ETHERNET";
     40     private static final String TAG = "Ethernet";
     41 
     42     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     43     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     44     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
     45     private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
     46 
     47     private static boolean mLinkUp;
     48     private LinkProperties mLinkProperties;
     49     private LinkCapabilities mLinkCapabilities;
     50     private NetworkInfo mNetworkInfo;
     51     private InterfaceObserver mInterfaceObserver;
     52 
     53     /* For sending events to connectivity service handler */
     54     private Handler mCsHandler;
     55     private Context mContext;
     56 
     57     private static EthernetDataTracker sInstance;
     58     private static String sIfaceMatch = "";
     59     private static String mIface = "";
     60 
     61     private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
     62         private EthernetDataTracker mTracker;
     63 
     64         InterfaceObserver(EthernetDataTracker tracker) {
     65             super();
     66             mTracker = tracker;
     67         }
     68 
     69         public void interfaceStatusChanged(String iface, boolean up) {
     70             Log.d(TAG, "Interface status changed: " + iface + (up ? "up" : "down"));
     71         }
     72 
     73         public void interfaceLinkStateChanged(String iface, boolean up) {
     74             if (mIface.equals(iface) && mLinkUp != up) {
     75                 Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
     76                 mLinkUp = up;
     77 
     78                 // use DHCP
     79                 if (up) {
     80                     mTracker.reconnect();
     81                 } else {
     82                     NetworkUtils.stopDhcp(mIface);
     83                     mTracker.mNetworkInfo.setIsAvailable(false);
     84                     mTracker.mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED,
     85                                                            null, null);
     86                 }
     87             }
     88         }
     89 
     90         public void interfaceAdded(String iface) {
     91             mTracker.interfaceAdded(iface);
     92         }
     93 
     94         public void interfaceRemoved(String iface) {
     95             mTracker.interfaceRemoved(iface);
     96         }
     97 
     98         public void limitReached(String limitName, String iface) {
     99             // Ignored.
    100         }
    101     }
    102 
    103     private EthernetDataTracker() {
    104         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
    105         mLinkProperties = new LinkProperties();
    106         mLinkCapabilities = new LinkCapabilities();
    107         mLinkUp = false;
    108 
    109         mNetworkInfo.setIsAvailable(false);
    110         setTeardownRequested(false);
    111     }
    112 
    113     private void interfaceAdded(String iface) {
    114         if (!iface.matches(sIfaceMatch))
    115             return;
    116 
    117         Log.d(TAG, "Adding " + iface);
    118 
    119         synchronized(mIface) {
    120             if(!mIface.isEmpty())
    121                 return;
    122             mIface = iface;
    123         }
    124 
    125         mNetworkInfo.setIsAvailable(true);
    126         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
    127         msg.sendToTarget();
    128 
    129         runDhcp();
    130     }
    131 
    132     private void interfaceRemoved(String iface) {
    133         if (!iface.equals(mIface))
    134             return;
    135 
    136         Log.d(TAG, "Removing " + iface);
    137 
    138         NetworkUtils.stopDhcp(mIface);
    139 
    140         mLinkProperties.clear();
    141         mNetworkInfo.setIsAvailable(false);
    142         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
    143 
    144         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
    145         msg.sendToTarget();
    146 
    147         msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
    148         msg.sendToTarget();
    149 
    150         mIface = "";
    151     }
    152 
    153     private void runDhcp() {
    154         Thread dhcpThread = new Thread(new Runnable() {
    155             public void run() {
    156                 DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
    157                 if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
    158                     Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
    159                     return;
    160                 }
    161                 mLinkProperties = dhcpInfoInternal.makeLinkProperties();
    162                 mLinkProperties.setInterfaceName(mIface);
    163 
    164                 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
    165                 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
    166                 msg.sendToTarget();
    167             }
    168         });
    169         dhcpThread.start();
    170     }
    171 
    172     public static synchronized EthernetDataTracker getInstance() {
    173         if (sInstance == null) sInstance = new EthernetDataTracker();
    174         return sInstance;
    175     }
    176 
    177     public Object Clone() throws CloneNotSupportedException {
    178         throw new CloneNotSupportedException();
    179     }
    180 
    181     public void setTeardownRequested(boolean isRequested) {
    182         mTeardownRequested.set(isRequested);
    183     }
    184 
    185     public boolean isTeardownRequested() {
    186         return mTeardownRequested.get();
    187     }
    188 
    189     /**
    190      * Begin monitoring connectivity
    191      */
    192     public void startMonitoring(Context context, Handler target) {
    193         mContext = context;
    194         mCsHandler = target;
    195 
    196         // register for notifications from NetworkManagement Service
    197         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    198         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
    199 
    200         mInterfaceObserver = new InterfaceObserver(this);
    201 
    202         // enable and try to connect to an ethernet interface that
    203         // already exists
    204         sIfaceMatch = context.getResources().getString(
    205             com.android.internal.R.string.config_ethernet_iface_regex);
    206         try {
    207             final String[] ifaces = service.listInterfaces();
    208             for (String iface : ifaces) {
    209                 if (iface.matches(sIfaceMatch)) {
    210                     mIface = iface;
    211                     InterfaceConfiguration config = service.getInterfaceConfig(iface);
    212                     mLinkUp = config.isActive();
    213                     reconnect();
    214                     break;
    215                 }
    216             }
    217         } catch (RemoteException e) {
    218             Log.e(TAG, "Could not get list of interfaces " + e);
    219         }
    220 
    221         try {
    222             service.registerObserver(mInterfaceObserver);
    223         } catch (RemoteException e) {
    224             Log.e(TAG, "Could not register InterfaceObserver " + e);
    225         }
    226     }
    227 
    228     /**
    229      * Disable connectivity to a network
    230      * TODO: do away with return value after making MobileDataStateTracker async
    231      */
    232     public boolean teardown() {
    233         mTeardownRequested.set(true);
    234         NetworkUtils.stopDhcp(mIface);
    235         return true;
    236     }
    237 
    238     /**
    239      * Re-enable connectivity to a network after a {@link #teardown()}.
    240      */
    241     public boolean reconnect() {
    242         mTeardownRequested.set(false);
    243         runDhcp();
    244         return true;
    245     }
    246 
    247     /**
    248      * Turn the wireless radio off for a network.
    249      * @param turnOn {@code true} to turn the radio on, {@code false}
    250      */
    251     public boolean setRadio(boolean turnOn) {
    252         return true;
    253     }
    254 
    255     /**
    256      * @return true - If are we currently tethered with another device.
    257      */
    258     public synchronized boolean isAvailable() {
    259         return mNetworkInfo.isAvailable();
    260     }
    261 
    262     /**
    263      * Tells the underlying networking system that the caller wants to
    264      * begin using the named feature. The interpretation of {@code feature}
    265      * is completely up to each networking implementation.
    266      * @param feature the name of the feature to be used
    267      * @param callingPid the process ID of the process that is issuing this request
    268      * @param callingUid the user ID of the process that is issuing this request
    269      * @return an integer value representing the outcome of the request.
    270      * The interpretation of this value is specific to each networking
    271      * implementation+feature combination, except that the value {@code -1}
    272      * always indicates failure.
    273      * TODO: needs to go away
    274      */
    275     public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
    276         return -1;
    277     }
    278 
    279     /**
    280      * Tells the underlying networking system that the caller is finished
    281      * using the named feature. The interpretation of {@code feature}
    282      * is completely up to each networking implementation.
    283      * @param feature the name of the feature that is no longer needed.
    284      * @param callingPid the process ID of the process that is issuing this request
    285      * @param callingUid the user ID of the process that is issuing this request
    286      * @return an integer value representing the outcome of the request.
    287      * The interpretation of this value is specific to each networking
    288      * implementation+feature combination, except that the value {@code -1}
    289      * always indicates failure.
    290      * TODO: needs to go away
    291      */
    292     public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
    293         return -1;
    294     }
    295 
    296     @Override
    297     public void setUserDataEnable(boolean enabled) {
    298         Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
    299     }
    300 
    301     @Override
    302     public void setPolicyDataEnable(boolean enabled) {
    303         Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
    304     }
    305 
    306     /**
    307      * Check if private DNS route is set for the network
    308      */
    309     public boolean isPrivateDnsRouteSet() {
    310         return mPrivateDnsRouteSet.get();
    311     }
    312 
    313     /**
    314      * Set a flag indicating private DNS route is set
    315      */
    316     public void privateDnsRouteSet(boolean enabled) {
    317         mPrivateDnsRouteSet.set(enabled);
    318     }
    319 
    320     /**
    321      * Fetch NetworkInfo for the network
    322      */
    323     public synchronized NetworkInfo getNetworkInfo() {
    324         return mNetworkInfo;
    325     }
    326 
    327     /**
    328      * Fetch LinkProperties for the network
    329      */
    330     public synchronized LinkProperties getLinkProperties() {
    331         return new LinkProperties(mLinkProperties);
    332     }
    333 
    334    /**
    335      * A capability is an Integer/String pair, the capabilities
    336      * are defined in the class LinkSocket#Key.
    337      *
    338      * @return a copy of this connections capabilities, may be empty but never null.
    339      */
    340     public LinkCapabilities getLinkCapabilities() {
    341         return new LinkCapabilities(mLinkCapabilities);
    342     }
    343 
    344     /**
    345      * Fetch default gateway address for the network
    346      */
    347     public int getDefaultGatewayAddr() {
    348         return mDefaultGatewayAddr.get();
    349     }
    350 
    351     /**
    352      * Check if default route is set
    353      */
    354     public boolean isDefaultRouteSet() {
    355         return mDefaultRouteSet.get();
    356     }
    357 
    358     /**
    359      * Set a flag indicating default route is set for the network
    360      */
    361     public void defaultRouteSet(boolean enabled) {
    362         mDefaultRouteSet.set(enabled);
    363     }
    364 
    365     /**
    366      * Return the system properties name associated with the tcp buffer sizes
    367      * for this network.
    368      */
    369     public String getTcpBufferSizesPropName() {
    370         return "net.tcp.buffersize.wifi";
    371     }
    372 
    373     public void setDependencyMet(boolean met) {
    374         // not supported on this network
    375     }
    376 }
    377