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