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     private String mHwAddr;
     53 
     54     /* For sending events to connectivity service handler */
     55     private Handler mCsHandler;
     56     private Context mContext;
     57 
     58     private static EthernetDataTracker sInstance;
     59     private static String sIfaceMatch = "";
     60     private static String mIface = "";
     61 
     62     private INetworkManagementService mNMService;
     63 
     64     private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
     65         private EthernetDataTracker mTracker;
     66 
     67         InterfaceObserver(EthernetDataTracker tracker) {
     68             super();
     69             mTracker = tracker;
     70         }
     71 
     72         public void interfaceStatusChanged(String iface, boolean up) {
     73             Log.d(TAG, "Interface status changed: " + iface + (up ? "up" : "down"));
     74         }
     75 
     76         public void interfaceLinkStateChanged(String iface, boolean up) {
     77             if (mIface.equals(iface) && mLinkUp != up) {
     78                 Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
     79                 mLinkUp = up;
     80                 mTracker.mNetworkInfo.setIsAvailable(up);
     81 
     82                 // use DHCP
     83                 if (up) {
     84                     mTracker.reconnect();
     85                 } else {
     86                     mTracker.disconnect();
     87                 }
     88             }
     89         }
     90 
     91         public void interfaceAdded(String iface) {
     92             mTracker.interfaceAdded(iface);
     93         }
     94 
     95         public void interfaceRemoved(String iface) {
     96             mTracker.interfaceRemoved(iface);
     97         }
     98 
     99         public void limitReached(String limitName, String iface) {
    100             // Ignored.
    101         }
    102     }
    103 
    104     private EthernetDataTracker() {
    105         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
    106         mLinkProperties = new LinkProperties();
    107         mLinkCapabilities = new LinkCapabilities();
    108     }
    109 
    110     private void interfaceAdded(String iface) {
    111         if (!iface.matches(sIfaceMatch))
    112             return;
    113 
    114         Log.d(TAG, "Adding " + iface);
    115 
    116         synchronized(this) {
    117             if(!mIface.isEmpty())
    118                 return;
    119             mIface = iface;
    120         }
    121 
    122         // we don't get link status indications unless the iface is up - bring it up
    123         try {
    124             mNMService.setInterfaceUp(iface);
    125         } catch (Exception e) {
    126             Log.e(TAG, "Error upping interface " + iface + ": " + e);
    127         }
    128 
    129         mNetworkInfo.setIsAvailable(true);
    130         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
    131         msg.sendToTarget();
    132     }
    133 
    134     public void disconnect() {
    135 
    136         NetworkUtils.stopDhcp(mIface);
    137 
    138         mLinkProperties.clear();
    139         mNetworkInfo.setIsAvailable(false);
    140         mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
    141 
    142         Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
    143         msg.sendToTarget();
    144 
    145         msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
    146         msg.sendToTarget();
    147 
    148         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    149         INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
    150         try {
    151             service.clearInterfaceAddresses(mIface);
    152         } catch (Exception e) {
    153             Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
    154         }
    155     }
    156 
    157     private void interfaceRemoved(String iface) {
    158         if (!iface.equals(mIface))
    159             return;
    160 
    161         Log.d(TAG, "Removing " + iface);
    162         disconnect();
    163         mIface = "";
    164     }
    165 
    166     private void runDhcp() {
    167         Thread dhcpThread = new Thread(new Runnable() {
    168             public void run() {
    169                 DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
    170                 if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
    171                     Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
    172                     return;
    173                 }
    174                 mLinkProperties = dhcpInfoInternal.makeLinkProperties();
    175                 mLinkProperties.setInterfaceName(mIface);
    176 
    177                 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
    178                 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
    179                 msg.sendToTarget();
    180             }
    181         });
    182         dhcpThread.start();
    183     }
    184 
    185     public static synchronized EthernetDataTracker getInstance() {
    186         if (sInstance == null) sInstance = new EthernetDataTracker();
    187         return sInstance;
    188     }
    189 
    190     public Object Clone() throws CloneNotSupportedException {
    191         throw new CloneNotSupportedException();
    192     }
    193 
    194     public void setTeardownRequested(boolean isRequested) {
    195         mTeardownRequested.set(isRequested);
    196     }
    197 
    198     public boolean isTeardownRequested() {
    199         return mTeardownRequested.get();
    200     }
    201 
    202     /**
    203      * Begin monitoring connectivity
    204      */
    205     public void startMonitoring(Context context, Handler target) {
    206         mContext = context;
    207         mCsHandler = target;
    208 
    209         // register for notifications from NetworkManagement Service
    210         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    211         mNMService = INetworkManagementService.Stub.asInterface(b);
    212 
    213         mInterfaceObserver = new InterfaceObserver(this);
    214 
    215         // enable and try to connect to an ethernet interface that
    216         // already exists
    217         sIfaceMatch = context.getResources().getString(
    218             com.android.internal.R.string.config_ethernet_iface_regex);
    219         try {
    220             final String[] ifaces = mNMService.listInterfaces();
    221             for (String iface : ifaces) {
    222                 if (iface.matches(sIfaceMatch)) {
    223                     mIface = iface;
    224                     mNMService.setInterfaceUp(iface);
    225                     InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
    226                     mLinkUp = config.isActive();
    227                     if (config != null && mHwAddr == null) {
    228                         mHwAddr = config.getHardwareAddress();
    229                         if (mHwAddr != null) {
    230                             mNetworkInfo.setExtraInfo(mHwAddr);
    231                         }
    232                     }
    233                     reconnect();
    234                     break;
    235                 }
    236             }
    237         } catch (RemoteException e) {
    238             Log.e(TAG, "Could not get list of interfaces " + e);
    239         }
    240 
    241         try {
    242             mNMService.registerObserver(mInterfaceObserver);
    243         } catch (RemoteException e) {
    244             Log.e(TAG, "Could not register InterfaceObserver " + e);
    245         }
    246     }
    247 
    248     /**
    249      * Disable connectivity to a network
    250      * TODO: do away with return value after making MobileDataStateTracker async
    251      */
    252     public boolean teardown() {
    253         mTeardownRequested.set(true);
    254         NetworkUtils.stopDhcp(mIface);
    255         return true;
    256     }
    257 
    258     /**
    259      * Re-enable connectivity to a network after a {@link #teardown()}.
    260      */
    261     public boolean reconnect() {
    262         if (mLinkUp) {
    263             mTeardownRequested.set(false);
    264             runDhcp();
    265         }
    266         return mLinkUp;
    267     }
    268 
    269     /**
    270      * Turn the wireless radio off for a network.
    271      * @param turnOn {@code true} to turn the radio on, {@code false}
    272      */
    273     public boolean setRadio(boolean turnOn) {
    274         return true;
    275     }
    276 
    277     /**
    278      * @return true - If are we currently tethered with another device.
    279      */
    280     public synchronized boolean isAvailable() {
    281         return mNetworkInfo.isAvailable();
    282     }
    283 
    284     /**
    285      * Tells the underlying networking system that the caller wants to
    286      * begin using the named feature. The interpretation of {@code feature}
    287      * is completely up to each networking implementation.
    288      * @param feature the name of the feature to be used
    289      * @param callingPid the process ID of the process that is issuing this request
    290      * @param callingUid the user ID of the process that is issuing this request
    291      * @return an integer value representing the outcome of the request.
    292      * The interpretation of this value is specific to each networking
    293      * implementation+feature combination, except that the value {@code -1}
    294      * always indicates failure.
    295      * TODO: needs to go away
    296      */
    297     public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
    298         return -1;
    299     }
    300 
    301     /**
    302      * Tells the underlying networking system that the caller is finished
    303      * using the named feature. The interpretation of {@code feature}
    304      * is completely up to each networking implementation.
    305      * @param feature the name of the feature that is no longer needed.
    306      * @param callingPid the process ID of the process that is issuing this request
    307      * @param callingUid the user ID of the process that is issuing this request
    308      * @return an integer value representing the outcome of the request.
    309      * The interpretation of this value is specific to each networking
    310      * implementation+feature combination, except that the value {@code -1}
    311      * always indicates failure.
    312      * TODO: needs to go away
    313      */
    314     public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
    315         return -1;
    316     }
    317 
    318     @Override
    319     public void setUserDataEnable(boolean enabled) {
    320         Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
    321     }
    322 
    323     @Override
    324     public void setPolicyDataEnable(boolean enabled) {
    325         Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
    326     }
    327 
    328     /**
    329      * Check if private DNS route is set for the network
    330      */
    331     public boolean isPrivateDnsRouteSet() {
    332         return mPrivateDnsRouteSet.get();
    333     }
    334 
    335     /**
    336      * Set a flag indicating private DNS route is set
    337      */
    338     public void privateDnsRouteSet(boolean enabled) {
    339         mPrivateDnsRouteSet.set(enabled);
    340     }
    341 
    342     /**
    343      * Fetch NetworkInfo for the network
    344      */
    345     public synchronized NetworkInfo getNetworkInfo() {
    346         return mNetworkInfo;
    347     }
    348 
    349     /**
    350      * Fetch LinkProperties for the network
    351      */
    352     public synchronized LinkProperties getLinkProperties() {
    353         return new LinkProperties(mLinkProperties);
    354     }
    355 
    356    /**
    357      * A capability is an Integer/String pair, the capabilities
    358      * are defined in the class LinkSocket#Key.
    359      *
    360      * @return a copy of this connections capabilities, may be empty but never null.
    361      */
    362     public LinkCapabilities getLinkCapabilities() {
    363         return new LinkCapabilities(mLinkCapabilities);
    364     }
    365 
    366     /**
    367      * Fetch default gateway address for the network
    368      */
    369     public int getDefaultGatewayAddr() {
    370         return mDefaultGatewayAddr.get();
    371     }
    372 
    373     /**
    374      * Check if default route is set
    375      */
    376     public boolean isDefaultRouteSet() {
    377         return mDefaultRouteSet.get();
    378     }
    379 
    380     /**
    381      * Set a flag indicating default route is set for the network
    382      */
    383     public void defaultRouteSet(boolean enabled) {
    384         mDefaultRouteSet.set(enabled);
    385     }
    386 
    387     /**
    388      * Return the system properties name associated with the tcp buffer sizes
    389      * for this network.
    390      */
    391     public String getTcpBufferSizesPropName() {
    392         return "net.tcp.buffersize.wifi";
    393     }
    394 
    395     public void setDependencyMet(boolean met) {
    396         // not supported on this network
    397     }
    398 }
    399