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