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