2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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;
29 import java.util.concurrent.atomic.AtomicBoolean;
30 import java.util.concurrent.atomic.AtomicInteger;
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.
38 public class EthernetDataTracker implements NetworkStateTracker {
39 private static final String NETWORKTYPE = "ETHERNET";
40 private static final String TAG = "Ethernet";
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);
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;
54 /* For sending events to connectivity service handler */
55 private Handler mCsHandler;
56 private Context mContext;
58 private static EthernetDataTracker sInstance;
59 private static String sIfaceMatch = "";
60 private static String mIface = "";
62 private INetworkManagementService mNMService;
64 private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
65 private EthernetDataTracker mTracker;
67 InterfaceObserver(EthernetDataTracker tracker) {
72 public void interfaceStatusChanged(String iface, boolean up) {
73 Log.d(TAG, "Interface status changed: " + iface + (up ? "up" : "down"));
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"));
80 mTracker.mNetworkInfo.setIsAvailable(up);
86 mTracker.disconnect();
91 public void interfaceAdded(String iface) {
92 mTracker.interfaceAdded(iface);
95 public void interfaceRemoved(String iface) {
96 mTracker.interfaceRemoved(iface);
99 public void limitReached(String limitName, String iface) {
103 public void interfaceClassDataActivityChanged(String label, boolean active) {
108 private EthernetDataTracker() {
109 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
110 mLinkProperties = new LinkProperties();
111 mLinkCapabilities = new LinkCapabilities();
114 private void interfaceAdded(String iface) {
115 if (!iface.matches(sIfaceMatch))
118 Log.d(TAG, "Adding " + iface);
121 if(!mIface.isEmpty())
126 // we don't get link status indications unless the iface is up - bring it up
128 mNMService.setInterfaceUp(iface);
129 } catch (Exception e) {
130 Log.e(TAG, "Error upping interface " + iface + ": " + e);
133 mNetworkInfo.setIsAvailable(true);
134 Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
138 public void disconnect() {
140 NetworkUtils.stopDhcp(mIface);
142 mLinkProperties.clear();
143 mNetworkInfo.setIsAvailable(false);
144 mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
146 Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
149 msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
152 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
153 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
155 service.clearInterfaceAddresses(mIface);
156 } catch (Exception e) {
157 Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
161 private void interfaceRemoved(String iface) {
162 if (!iface.equals(mIface))
165 Log.d(TAG, "Removing " + iface);
170 private void runDhcp() {
171 Thread dhcpThread = new Thread(new Runnable() {
173 DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
174 if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
175 Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
178 mLinkProperties = dhcpInfoInternal.makeLinkProperties();
179 mLinkProperties.setInterfaceName(mIface);
181 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
182 Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
189 public static synchronized EthernetDataTracker getInstance() {
190 if (sInstance == null) sInstance = new EthernetDataTracker();
194 public Object Clone() throws CloneNotSupportedException {
195 throw new CloneNotSupportedException();
198 public void setTeardownRequested(boolean isRequested) {
199 mTeardownRequested.set(isRequested);
202 public boolean isTeardownRequested() {
203 return mTeardownRequested.get();
207 * Begin monitoring connectivity
209 public void startMonitoring(Context context, Handler target) {
213 // register for notifications from NetworkManagement Service
214 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
215 mNMService = INetworkManagementService.Stub.asInterface(b);
217 mInterfaceObserver = new InterfaceObserver(this);
219 // enable and try to connect to an ethernet interface that
221 sIfaceMatch = context.getResources().getString(
222 com.android.internal.R.string.config_ethernet_iface_regex);
224 final String[] ifaces = mNMService.listInterfaces();
225 for (String iface : ifaces) {
226 if (iface.matches(sIfaceMatch)) {
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);
238 // if a DHCP client had previously been started for this interface, then stop it
239 NetworkUtils.stopDhcp(mIface);
245 } catch (RemoteException e) {
246 Log.e(TAG, "Could not get list of interfaces " + e);
250 mNMService.registerObserver(mInterfaceObserver);
251 } catch (RemoteException e) {
252 Log.e(TAG, "Could not register InterfaceObserver " + e);
257 * Disable connectivity to a network
258 * TODO: do away with return value after making MobileDataStateTracker async
260 public boolean teardown() {
261 mTeardownRequested.set(true);
262 NetworkUtils.stopDhcp(mIface);
267 * Re-enable connectivity to a network after a {@link #teardown()}.
269 public boolean reconnect() {
271 mTeardownRequested.set(false);
278 public void captivePortalCheckComplete() {
283 * Turn the wireless radio off for a network.
284 * @param turnOn {@code true} to turn the radio on, {@code false}
286 public boolean setRadio(boolean turnOn) {
291 * @return true - If are we currently tethered with another device.
293 public synchronized boolean isAvailable() {
294 return mNetworkInfo.isAvailable();
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
310 public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
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
327 public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
332 public void setUserDataEnable(boolean enabled) {
333 Log.w(TAG, "ignoring setUserDataEnable(" + enabled + ")");
337 public void setPolicyDataEnable(boolean enabled) {
338 Log.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")");
342 * Check if private DNS route is set for the network
344 public boolean isPrivateDnsRouteSet() {
345 return mPrivateDnsRouteSet.get();
349 * Set a flag indicating private DNS route is set
351 public void privateDnsRouteSet(boolean enabled) {
352 mPrivateDnsRouteSet.set(enabled);
356 * Fetch NetworkInfo for the network
358 public synchronized NetworkInfo getNetworkInfo() {
363 * Fetch LinkProperties for the network
365 public synchronized LinkProperties getLinkProperties() {
366 return new LinkProperties(mLinkProperties);
370 * A capability is an Integer/String pair, the capabilities
371 * are defined in the class LinkSocket#Key.
373 * @return a copy of this connections capabilities, may be empty but never null.
375 public LinkCapabilities getLinkCapabilities() {
376 return new LinkCapabilities(mLinkCapabilities);
380 * Fetch default gateway address for the network
382 public int getDefaultGatewayAddr() {
383 return mDefaultGatewayAddr.get();
387 * Check if default route is set
389 public boolean isDefaultRouteSet() {
390 return mDefaultRouteSet.get();
394 * Set a flag indicating default route is set for the network
396 public void defaultRouteSet(boolean enabled) {
397 mDefaultRouteSet.set(enabled);
401 * Return the system properties name associated with the tcp buffer sizes
404 public String getTcpBufferSizesPropName() {
405 return "net.tcp.buffersize.wifi";
408 public void setDependencyMet(boolean met) {
409 // not supported on this network