EthernetDataTracker.java revision b25f48f2be76a99088426ca068dd80fbf3e6dc5f
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 17package android.net; 18 19import android.content.Context; 20import android.net.NetworkInfo.DetailedState; 21import android.os.Handler; 22import android.os.IBinder; 23import android.os.INetworkManagementService; 24import android.os.Message; 25import android.os.RemoteException; 26import android.os.ServiceManager; 27import android.util.Log; 28 29import java.util.concurrent.atomic.AtomicBoolean; 30import 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 */ 38public 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 234 // if a DHCP client had previously been started for this interface, then stop it 235 NetworkUtils.stopDhcp(mIface); 236 237 reconnect(); 238 break; 239 } 240 } 241 } catch (RemoteException e) { 242 Log.e(TAG, "Could not get list of interfaces " + e); 243 } 244 245 try { 246 mNMService.registerObserver(mInterfaceObserver); 247 } catch (RemoteException e) { 248 Log.e(TAG, "Could not register InterfaceObserver " + e); 249 } 250 } 251 252 /** 253 * Disable connectivity to a network 254 * TODO: do away with return value after making MobileDataStateTracker async 255 */ 256 public boolean teardown() { 257 mTeardownRequested.set(true); 258 NetworkUtils.stopDhcp(mIface); 259 return true; 260 } 261 262 /** 263 * Re-enable connectivity to a network after a {@link #teardown()}. 264 */ 265 public boolean reconnect() { 266 if (mLinkUp) { 267 mTeardownRequested.set(false); 268 runDhcp(); 269 } 270 return mLinkUp; 271 } 272 273 /** 274 * Turn the wireless radio off for a network. 275 * @param turnOn {@code true} to turn the radio on, {@code false} 276 */ 277 public boolean setRadio(boolean turnOn) { 278 return true; 279 } 280 281 /** 282 * @return true - If are we currently tethered with another device. 283 */ 284 public synchronized boolean isAvailable() { 285 return mNetworkInfo.isAvailable(); 286 } 287 288 /** 289 * Tells the underlying networking system that the caller wants to 290 * begin using the named feature. The interpretation of {@code feature} 291 * is completely up to each networking implementation. 292 * @param feature the name of the feature to be used 293 * @param callingPid the process ID of the process that is issuing this request 294 * @param callingUid the user ID of the process that is issuing this request 295 * @return an integer value representing the outcome of the request. 296 * The interpretation of this value is specific to each networking 297 * implementation+feature combination, except that the value {@code -1} 298 * always indicates failure. 299 * TODO: needs to go away 300 */ 301 public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { 302 return -1; 303 } 304 305 /** 306 * Tells the underlying networking system that the caller is finished 307 * using the named feature. The interpretation of {@code feature} 308 * is completely up to each networking implementation. 309 * @param feature the name of the feature that is no longer needed. 310 * @param callingPid the process ID of the process that is issuing this request 311 * @param callingUid the user ID of the process that is issuing this request 312 * @return an integer value representing the outcome of the request. 313 * The interpretation of this value is specific to each networking 314 * implementation+feature combination, except that the value {@code -1} 315 * always indicates failure. 316 * TODO: needs to go away 317 */ 318 public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { 319 return -1; 320 } 321 322 @Override 323 public void setUserDataEnable(boolean enabled) { 324 Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")"); 325 } 326 327 @Override 328 public void setPolicyDataEnable(boolean enabled) { 329 Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")"); 330 } 331 332 /** 333 * Check if private DNS route is set for the network 334 */ 335 public boolean isPrivateDnsRouteSet() { 336 return mPrivateDnsRouteSet.get(); 337 } 338 339 /** 340 * Set a flag indicating private DNS route is set 341 */ 342 public void privateDnsRouteSet(boolean enabled) { 343 mPrivateDnsRouteSet.set(enabled); 344 } 345 346 /** 347 * Fetch NetworkInfo for the network 348 */ 349 public synchronized NetworkInfo getNetworkInfo() { 350 return mNetworkInfo; 351 } 352 353 /** 354 * Fetch LinkProperties for the network 355 */ 356 public synchronized LinkProperties getLinkProperties() { 357 return new LinkProperties(mLinkProperties); 358 } 359 360 /** 361 * A capability is an Integer/String pair, the capabilities 362 * are defined in the class LinkSocket#Key. 363 * 364 * @return a copy of this connections capabilities, may be empty but never null. 365 */ 366 public LinkCapabilities getLinkCapabilities() { 367 return new LinkCapabilities(mLinkCapabilities); 368 } 369 370 /** 371 * Fetch default gateway address for the network 372 */ 373 public int getDefaultGatewayAddr() { 374 return mDefaultGatewayAddr.get(); 375 } 376 377 /** 378 * Check if default route is set 379 */ 380 public boolean isDefaultRouteSet() { 381 return mDefaultRouteSet.get(); 382 } 383 384 /** 385 * Set a flag indicating default route is set for the network 386 */ 387 public void defaultRouteSet(boolean enabled) { 388 mDefaultRouteSet.set(enabled); 389 } 390 391 /** 392 * Return the system properties name associated with the tcp buffer sizes 393 * for this network. 394 */ 395 public String getTcpBufferSizesPropName() { 396 return "net.tcp.buffersize.wifi"; 397 } 398 399 public void setDependencyMet(boolean met) { 400 // not supported on this network 401 } 402} 403