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