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