Add support for USB Ethernet adapters
Change-Id: I6ae34a32d0e1b6f21c484b8639c3e7ce086e568d
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cab8ed2..491c73a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -224,9 +224,9 @@
/** {@hide} */
public static final int TYPE_ETHERNET = 9;
/** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_RADIO_TYPE = TYPE_DUMMY;
+ public static final int MAX_RADIO_TYPE = TYPE_ETHERNET;
/** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_NETWORK_TYPE = TYPE_DUMMY;
+ public static final int MAX_NETWORK_TYPE = TYPE_ETHERNET;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
new file mode 100644
index 0000000..df5fdd0
--- /dev/null
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.DhcpInfoInternal;
+import android.net.LinkAddress;
+import android.net.LinkCapabilities;
+import android.net.LinkProperties;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkStateTracker;
+import android.net.NetworkUtils;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This class tracks the data connection associated with Ethernet
+ * This is a singleton class and an instance will be created by
+ * ConnectivityService.
+ * @hide
+ */
+public class EthernetDataTracker implements NetworkStateTracker {
+ private static final String NETWORKTYPE = "ETHERNET";
+ private static final String TAG = "Ethernet";
+
+ private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
+ private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
+ private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
+ private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
+
+ private LinkProperties mLinkProperties;
+ private LinkCapabilities mLinkCapabilities;
+ private NetworkInfo mNetworkInfo;
+ private InterfaceObserver mInterfaceObserver;
+
+ /* For sending events to connectivity service handler */
+ private Handler mCsHandler;
+ private Context mContext;
+
+ private static EthernetDataTracker sInstance;
+ private static String mIface = "";
+
+ private static class InterfaceObserver extends INetworkManagementEventObserver.Stub {
+ private EthernetDataTracker mTracker;
+
+ InterfaceObserver(EthernetDataTracker tracker) {
+ super();
+ mTracker = tracker;
+ }
+
+ public void interfaceLinkStatusChanged(String iface, boolean up) {
+ Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
+ }
+
+ public void interfaceAdded(String iface) {
+ mTracker.interfaceAdded(iface);
+ }
+
+ public void interfaceRemoved(String iface) {
+ mTracker.interfaceRemoved(iface);
+ }
+ }
+
+ private EthernetDataTracker() {
+ mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
+ mLinkProperties = new LinkProperties();
+ mLinkCapabilities = new LinkCapabilities();
+
+ mNetworkInfo.setIsAvailable(false);
+ setTeardownRequested(false);
+ }
+
+ private void interfaceAdded(String iface) {
+ if (!iface.matches("eth\\d"))
+ return;
+
+ Log.d(TAG, "Adding " + iface);
+
+ synchronized(mIface) {
+ if(!mIface.isEmpty())
+ return;
+ mIface = iface;
+ }
+
+ mNetworkInfo.setIsAvailable(true);
+ Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+
+ runDhcp();
+ }
+
+ private void interfaceRemoved(String iface) {
+ if (!iface.equals(mIface))
+ return;
+
+ Log.d(TAG, "Removing " + iface);
+
+ NetworkUtils.stopDhcp(mIface);
+
+ mLinkProperties.clear();
+ mNetworkInfo.setIsAvailable(false);
+ mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+
+ Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+
+ msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+
+ mIface = "";
+ }
+
+ private void runDhcp() {
+ Thread dhcpThread = new Thread(new Runnable() {
+ public void run() {
+ DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
+ if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
+ Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+ return;
+ }
+ mLinkProperties = dhcpInfoInternal.makeLinkProperties();
+ mLinkProperties.setInterfaceName(mIface);
+
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+ }
+ });
+ dhcpThread.start();
+ }
+
+ public static synchronized EthernetDataTracker getInstance() {
+ if (sInstance == null) sInstance = new EthernetDataTracker();
+ return sInstance;
+ }
+
+ public Object Clone() throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+
+ public void setTeardownRequested(boolean isRequested) {
+ mTeardownRequested.set(isRequested);
+ }
+
+ public boolean isTeardownRequested() {
+ return mTeardownRequested.get();
+ }
+
+ /**
+ * Begin monitoring connectivity
+ */
+ public void startMonitoring(Context context, Handler target) {
+ mContext = context;
+ mCsHandler = target;
+
+ // register for notifications from NetworkManagement Service
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ mInterfaceObserver = new InterfaceObserver(this);
+ try {
+ service.registerObserver(mInterfaceObserver);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not register InterfaceObserver " + e);
+ }
+ }
+
+ /**
+ * Disable connectivity to a network
+ * TODO: do away with return value after making MobileDataStateTracker async
+ */
+ public boolean teardown() {
+ mTeardownRequested.set(true);
+ NetworkUtils.stopDhcp(mIface);
+ return true;
+ }
+
+ /**
+ * Re-enable connectivity to a network after a {@link #teardown()}.
+ */
+ public boolean reconnect() {
+ mTeardownRequested.set(false);
+ runDhcp();
+ return true;
+ }
+
+ /**
+ * Turn the wireless radio off for a network.
+ * @param turnOn {@code true} to turn the radio on, {@code false}
+ */
+ public boolean setRadio(boolean turnOn) {
+ return true;
+ }
+
+ /**
+ * @return true - If are we currently tethered with another device.
+ */
+ public synchronized boolean isAvailable() {
+ return mNetworkInfo.isAvailable();
+ }
+
+ /**
+ * Tells the underlying networking system that the caller wants to
+ * begin using the named feature. The interpretation of {@code feature}
+ * is completely up to each networking implementation.
+ * @param feature the name of the feature to be used
+ * @param callingPid the process ID of the process that is issuing this request
+ * @param callingUid the user ID of the process that is issuing this request
+ * @return an integer value representing the outcome of the request.
+ * The interpretation of this value is specific to each networking
+ * implementation+feature combination, except that the value {@code -1}
+ * always indicates failure.
+ * TODO: needs to go away
+ */
+ public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) {
+ return -1;
+ }
+
+ /**
+ * Tells the underlying networking system that the caller is finished
+ * using the named feature. The interpretation of {@code feature}
+ * is completely up to each networking implementation.
+ * @param feature the name of the feature that is no longer needed.
+ * @param callingPid the process ID of the process that is issuing this request
+ * @param callingUid the user ID of the process that is issuing this request
+ * @return an integer value representing the outcome of the request.
+ * The interpretation of this value is specific to each networking
+ * implementation+feature combination, except that the value {@code -1}
+ * always indicates failure.
+ * TODO: needs to go away
+ */
+ public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) {
+ return -1;
+ }
+
+ /**
+ * @param enabled
+ */
+ public void setDataEnable(boolean enabled) {
+ Log.d(TAG, "setDataEnabled: IGNORING enabled=" + enabled);
+ }
+
+ /**
+ * Check if private DNS route is set for the network
+ */
+ public boolean isPrivateDnsRouteSet() {
+ return mPrivateDnsRouteSet.get();
+ }
+
+ /**
+ * Set a flag indicating private DNS route is set
+ */
+ public void privateDnsRouteSet(boolean enabled) {
+ mPrivateDnsRouteSet.set(enabled);
+ }
+
+ /**
+ * Fetch NetworkInfo for the network
+ */
+ public synchronized NetworkInfo getNetworkInfo() {
+ return mNetworkInfo;
+ }
+
+ /**
+ * Fetch LinkProperties for the network
+ */
+ public synchronized LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
+ }
+
+ /**
+ * A capability is an Integer/String pair, the capabilities
+ * are defined in the class LinkSocket#Key.
+ *
+ * @return a copy of this connections capabilities, may be empty but never null.
+ */
+ public LinkCapabilities getLinkCapabilities() {
+ return new LinkCapabilities(mLinkCapabilities);
+ }
+
+ /**
+ * Fetch default gateway address for the network
+ */
+ public int getDefaultGatewayAddr() {
+ return mDefaultGatewayAddr.get();
+ }
+
+ /**
+ * Check if default route is set
+ */
+ public boolean isDefaultRouteSet() {
+ return mDefaultRouteSet.get();
+ }
+
+ /**
+ * Set a flag indicating default route is set for the network
+ */
+ public void defaultRouteSet(boolean enabled) {
+ mDefaultRouteSet.set(enabled);
+ }
+
+ /**
+ * Return the system properties name associated with the tcp buffer sizes
+ * for this network.
+ */
+ public String getTcpBufferSizesPropName() {
+ return "net.tcp.buffersize.wifi";
+ }
+}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index fcb4c23..b1552a8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -24,6 +24,7 @@
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.DummyDataStateTracker;
+import android.net.EthernetDataTracker;
import android.net.IConnectivityManager;
import android.net.LinkProperties;
import android.net.MobileDataStateTracker;
@@ -420,6 +421,10 @@
mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
mNetTrackers[netType].startMonitoring(context, mHandler);
break;
+ case ConnectivityManager.TYPE_ETHERNET:
+ mNetTrackers[netType] = EthernetDataTracker.getInstance();
+ mNetTrackers[netType].startMonitoring(context, mHandler);
+ break;
default:
loge("Trying to create a DataStateTracker for an unknown radio type " +
mNetAttributes[netType].mRadio);