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