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