diff options
author | Kejun ZHOU <kejun.zhou@linaro.org> | 2012-01-11 10:14:02 +0800 |
---|---|---|
committer | Bernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org> | 2012-03-29 09:41:15 +0200 |
commit | 76ee573c836df42ca14441eed8064407f810187e (patch) | |
tree | eec5fd62ff3915cf79de3da3165ea709f334f6b8 | |
parent | 44cd45974b5feab47ee093b3cca82cd71511a7b1 (diff) | |
download | base-76ee573c836df42ca14441eed8064407f810187e.tar.gz |
update ECM for 4.0.3
Change-Id: I39e0a20947c7f0f5f0d8be9b12fc7980d1082a81
Signed-off-by: Kejun ZHOU <kejun.zhou@linaro.org>
29 files changed, 2455 insertions, 2 deletions
diff --git a/Android.mk b/Android.mk index 83c4b5b1fe4e..fbb8a84544b3 100644 --- a/Android.mk +++ b/Android.mk @@ -196,6 +196,7 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/IWapPushManager.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl \ wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \ + ethernet/java/android/net/ethernet/IEthernetManager.aidl \ telephony/java/com/android/internal/telephony/IExtendedNetworkService.aidl \ voip/java/android/net/sip/ISipSession.aidl \ voip/java/android/net/sip/ISipSessionListener.aidl \ diff --git a/api/current.txt b/api/current.txt index 68fb4bc0e7d4..db8768c1de66 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5109,6 +5109,7 @@ package android.content { field public static final java.lang.String DEVICE_POLICY_SERVICE = "device_policy"; field public static final java.lang.String DOWNLOAD_SERVICE = "download"; field public static final java.lang.String DROPBOX_SERVICE = "dropbox"; + field public static final java.lang.String ETHERNET_SERVICE = "ethernet"; field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method"; field public static final java.lang.String KEYGUARD_SERVICE = "keyguard"; field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater"; @@ -11968,6 +11969,61 @@ package android.net { } +package android.net.ethernet { + + public class name EthernetDevInfo implements android.os.Parcelable { + + ctor public android.net.ethernet.EthernetDevInfo EthernetDevInfo (); + method public int describeContents(); + method public java.lang.String getConnectMode(); + method public java.lang.String getDnsAddr(); + method public java.lang.String getIfName(); + method public java.lang.String getIpAddress(); + method public java.lang.String getNetMask(); + method public java.lang.String getRouteAddr(); + method public boolean setConnectMode(); + method public void setDnsAddr(); + method public void setIfName(java.lang.String); + method public void setIpAddress(java.lang.String); + method public void setNetMask(java.lang.String); + method public void setRouteAddr(java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + method public static final java.lang.String ETHERNET_CONN_MODE_DHCP() = dhcp; + field public static final java.lang.String ETHERNET_CONN_MODE_MANUAL = manual; + } + + public class EthernetManager { + ctor public android.net.ethernet.EthernetManager EthernetManager(android.net.ethernet.IEthernetManager, android.os.Handler) + method public java.lang.String[] getDeviceNameList(); + method public android.net.ethernet.EthernetDevInfo getSavedConfig(); + method public int getState(); + method public int getTotalInterface(); + method public boolean isConfigured(); + method public void updateDevInfo(android.net.ethernet.EthernetDevInfo); + field public static final int ETHERNET_DEVICE_SCAN_RESULT_READY = 0; + field public static final java.lang.String ETHERNET_STATE_CHANGED_ACTION = android.net.ethernet.ETHERNET_STATE_CHANGED; + field public static final int ETHERNET_STATE_DISABLED = 1; + field public static final int ETHERNET_STATE_ENABLED = 2; + field public static final int ETHERNET_STATE_UNKNOWN = 0; + field public static final java.lang.String EXTRA_ETHERNET_STATE = ETHERNET_state; + field public static final java.lang.String EXTRA_NETWORK_INFO = networkInfo; + field public static final java.lang.String EXTRA_PREVIOUS_ETHERNET_STATE = previous_ETHERNET_state; + field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = android.net.ethernet.STATE_CHANGE; + field public static final java.lang.String TAG = EthernetManager; + } + + public interface IEthernetManager implements android.os.IInterface { + method public abstract java.lang.String[] getDeviceNameList(); + method public abstract android.net.ethernet.EthernetDevInfo getSavedConfig() throws android.os.RemoteException; + method public abstract int getState() throws android.os.RemoteException; + method public abstract int getTotalInterface() android.os.RemoteException; + method public abstract boolean isConfigured(i) android.os.RemoteException; + method public abstract void setMode(java.lang.String) throws android.os.RemoteException; + method public abstract void setState(int) throws android.os.RemoteException; + method public abstract void updateDevInfo(android.net.ethernet.EthernetDevInfo) thows android.os.RemoteException; + } +} + package android.net.http { public final class AndroidHttpClient implements org.apache.http.client.HttpClient { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 2bf1fb712304..c31ff0586e99 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -61,6 +61,8 @@ import android.net.wifi.IWifiManager; import android.net.wifi.WifiManager; import android.net.wifi.p2p.IWifiP2pManager; import android.net.wifi.p2p.WifiP2pManager; +import android.net.ethernet.IEthernetManager; +import android.net.ethernet.EthernetManager; import android.nfc.NfcManager; import android.os.Binder; import android.os.Bundle; @@ -448,6 +450,13 @@ class ContextImpl extends Context { return new WifiP2pManager(service); }}); + registerService(ETHERNET_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(ETHERNET_SERVICE); + IEthernetManager service = IEthernetManager.Stub.asInterface(b); + return new EthernetManager(service, ctx.mMainThread.getHandler()); + }}); + registerService(WINDOW_SERVICE, new ServiceFetcher() { public Object getService(ContextImpl ctx) { return WindowManagerImpl.getDefault(ctx.mPackageInfo.mCompatibilityInfo); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index bfbd0ac5ed05..e2c85cedf5b7 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1461,6 +1461,16 @@ public abstract class Context { */ public static final String WINDOW_SERVICE = "window"; + /** + * Use with {@link #getSystemService} to retrieve a {@link + * android.net.ethernet.EthernetManager} for handling management of + * Ethernet access. + * + * @see #getSystemService + * @see android.net.ethernet.EthernetManager + */ + public static final String ETHERNET_SERVICE = "ethernet"; + /** * Use with {@link #getSystemService} to retrieve a * {@link android.view.LayoutInflater} for inflating layout resources in this diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index d39e741efddc..daa8d3574cce 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -102,6 +102,18 @@ public class NetworkUtils { */ public native static String getDhcpError(); + public static boolean configureInterface(String interfaceName, DhcpInfo ipInfo) { + return configureNative(interfaceName, + ipInfo.ipAddress, + netmaskIntToPrefixLength(ipInfo.netmask), + ipInfo.gateway, + ipInfo.dns1, + ipInfo.dns2); + } + + private native static boolean configureNative( + String interfaceName, int ipAddress, int prefixLength, int gateway, int dns1, int dns2); + /** * Convert a IPv4 address from an integer to an InetAddress. * @param hostAddress an int corresponding to the IPv4 address in network byte order diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d7fab37ed604..702487150b4a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3169,6 +3169,18 @@ public final class Settings { "wifi_mobile_data_transition_wakelock_timeout_ms"; /** + * Ethernet related configurations + */ + public static final String ETHERNET_ON = "ethernet_on"; + public static final String ETHERNET_MODE = "ethernet_mode"; + public static final String ETHERNET_IP = "ethernet_ip"; + public static final String ETHERNET_MASK = "ethernet_netmask"; + public static final String ETHERNET_DNS = "ethernet_dns"; + public static final String ETHERNET_ROUTE = "ethernet_iproute"; + public static final String ETHERNET_CONF = "ethernet_conf"; + public static final String ETHERNET_IFNAME = "ethernet_ifname"; + + /** * Whether background data usage is allowed by the user. See * ConnectivityManager for more info. */ diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 71c5d2662292..1e94bafb9df4 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES:= \ android_net_NetUtils.cpp \ android_net_TrafficStats.cpp \ android_net_wifi_Wifi.cpp \ + android_net_ethernet.cpp \ android_nio_utils.cpp \ android_nfc_NdefMessage.cpp \ android_nfc_NdefRecord.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index c00e6c9a09fa..814570d3c386 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -146,6 +146,7 @@ extern int register_android_net_LocalSocketImpl(JNIEnv* env); extern int register_android_net_NetworkUtils(JNIEnv* env); extern int register_android_net_TrafficStats(JNIEnv* env); extern int register_android_net_wifi_WifiManager(JNIEnv* env); +extern int register_android_net_ethernet_EthernetManager(JNIEnv* env); extern int register_android_text_AndroidCharacter(JNIEnv *env); extern int register_android_text_AndroidBidi(JNIEnv *env); extern int register_android_text_KeyCharacterMap(JNIEnv *env); @@ -1159,6 +1160,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_net_NetworkUtils), REG_JNI(register_android_net_TrafficStats), REG_JNI(register_android_net_wifi_WifiManager), + REG_JNI(register_android_net_ethernet_EthernetManager), REG_JNI(register_android_nfc_NdefMessage), REG_JNI(register_android_nfc_NdefRecord), REG_JNI(register_android_os_MemoryFile), diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index d9bd50eaa335..e2b5e5c8397b 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -26,7 +26,9 @@ extern "C" { int ifc_enable(const char *ifname); int ifc_disable(const char *ifname); +int ifc_remove_default_route(const char *ifname); int ifc_reset_connections(const char *ifname, int reset_mask); +int ifc_configure(const char *ifname, in_addr_t ipaddr, uint32_t prefixLength, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2); int dhcp_do_request(const char *ifname, const char *ipaddr, @@ -90,6 +92,16 @@ static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstri return (jint)result; } +static jint android_net_utils_removeDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname) +{ + int result; + + const char *nameStr = env->GetStringUTFChars(ifname, NULL); + result = ::ifc_remove_default_route(nameStr); + env->ReleaseStringUTFChars(ifname, nameStr); + return (jint)result; +} + static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstring ifname, jint mask) { @@ -165,6 +177,24 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr return (jboolean)(result == 0); } +static jboolean android_net_utils_configureInterface(JNIEnv* env, + jobject clazz, + jstring ifname, + jint ipaddr, + jint prefixLength, + jint gateway, + jint dns1, + jint dns2) +{ + int result; + uint32_t lease; + + const char *nameStr = env->GetStringUTFChars(ifname, NULL); + result = ::ifc_configure(nameStr, ipaddr, prefixLength, gateway, dns1, dns2); + env->ReleaseStringUTFChars(ifname, nameStr); + return (jboolean)(result == 0); +} + static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info) { return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false); @@ -217,6 +247,7 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp }, { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, + { "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface }, }; int register_android_net_NetworkUtils(JNIEnv* env) diff --git a/core/jni/android_net_ethernet.cpp b/core/jni/android_net_ethernet.cpp new file mode 100644 index 000000000000..d18e6a100e2b --- /dev/null +++ b/core/jni/android_net_ethernet.cpp @@ -0,0 +1,419 @@ +/* + * Copyright 2010, The Android-x86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +#define LOG_TAG "ethernet" + +#include "jni.h" +#include <inttypes.h> +#include <utils/misc.h> +#include <android_runtime/AndroidRuntime.h> +#include <utils/Log.h> +#include <asm/types.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <poll.h> +#include <net/if_arp.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <dirent.h> + + +#define ETH_PKG_NAME "android/net/ethernet/EthernetNative" +#define NL_SOCK_INV -1 +#define RET_STR_SZ 4096 +#define NL_POLL_MSG_SZ 8*1024 +#define SYSFS_PATH_MAX 256 + +namespace android { + static struct fieldIds { + jclass dhcpInfoClass; + jmethodID constructorId; + jfieldID ipaddress; + jfieldID gateway; + jfieldID netmask; + jfieldID dns1; + jfieldID dns2; + jfieldID serverAddress; + jfieldID leaseDuration; + } dhcpInfoFieldIds; + + struct interface_info_t { + unsigned int i; /* interface index */ + char *name; /* name (eth0, eth1, ...) */ + struct interface_info_t *next; + }; + + interface_info_t *interfaces = NULL; + int total_int = 0; + static const char SYSFS_CLASS_NET[] = "/sys/class/net"; + static int nl_socket_msg = NL_SOCK_INV; + static struct sockaddr_nl addr_msg; + static int nl_socket_poll = NL_SOCK_INV; + static struct sockaddr_nl addr_poll; + static int getinterfacename(int index, char *name, size_t len); + + static interface_info_t *find_info_by_index(unsigned int index) + { + interface_info_t *info = interfaces; + while (info) { + if (info->i == index) + break; + info = info->next; + } + return info; + } + + static jstring android_net_ethernet_waitForEvent(JNIEnv *env, jobject clazz) + { + char *buff; + struct nlmsghdr *nh; + struct ifinfomsg *einfo; + struct iovec iov; + struct msghdr msg; + char *result = NULL; + char rbuf[4096]; + unsigned int left; + interface_info_t *info; + int len; + + LOGV("Poll events from ethernet devices"); + /* + *wait on uevent netlink socket for the ethernet device + */ + buff = (char *)malloc(NL_POLL_MSG_SZ); + if (!buff) { + LOGE("Allocate poll buffer failed"); + goto error; + } + + iov.iov_base = buff; + iov.iov_len = NL_POLL_MSG_SZ; + msg.msg_name = (void *)&addr_msg; + msg.msg_namelen = sizeof(addr_msg); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + if ((len = recvmsg(nl_socket_poll, &msg, 0)) >= 0) { + LOGV("recvmsg get data"); + result = rbuf; + left = 4096; + rbuf[0] = '\0'; + for (nh = (struct nlmsghdr *) buff; NLMSG_OK (nh, len); + nh = NLMSG_NEXT (nh, len)) { + + if (nh->nlmsg_type == NLMSG_DONE) { + LOGE("Did not find useful eth interface information"); + goto error; + } + + if (nh->nlmsg_type == NLMSG_ERROR) { + /* Do some error handling. */ + LOGE("Read device name failed"); + goto error; + } + + LOGV(" event :%d found", nh->nlmsg_type); + einfo = (struct ifinfomsg *)NLMSG_DATA(nh); + LOGV("the device flag :%X", einfo->ifi_flags); + if (nh->nlmsg_type == RTM_DELLINK || + nh->nlmsg_type == RTM_NEWLINK || + nh->nlmsg_type == RTM_DELADDR || + nh->nlmsg_type == RTM_NEWADDR) { + int type = nh->nlmsg_type; + if (type == RTM_NEWLINK && + (!(einfo->ifi_flags & IFF_LOWER_UP))) { + type = RTM_DELLINK; + } + if ((info = find_info_by_index + (((struct ifinfomsg*) NLMSG_DATA(nh))->ifi_index)) != NULL) + snprintf(result,left, "%s:%d:",info->name,type); + left = left - strlen(result); + result =(char *)(result+ strlen(result)); + } + + } + LOGV("Done parsing"); + rbuf[4096 - left] = '\0'; + LOGV("poll state :%s, left:%d", rbuf, left); + } + + + error: + free(buff); + return env->NewStringUTF(rbuf); + } + + static int netlink_send_dump_request(int sock, int type, int family) + { + int ret; + char buf[4096]; + struct sockaddr_nl snl; + struct nlmsghdr *nlh; + struct rtgenmsg *g; + + memset(&snl, 0, sizeof(snl)); + snl.nl_family = AF_NETLINK; + + memset(buf, 0, sizeof(buf)); + nlh = (struct nlmsghdr *)buf; + g = (struct rtgenmsg *)(buf + sizeof(struct nlmsghdr)); + + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); + nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; + nlh->nlmsg_type = type; + g->rtgen_family = family; + + ret = sendto(sock, buf, nlh->nlmsg_len, 0, (struct sockaddr *)&snl, + sizeof(snl)); + if (ret < 0) { + perror("netlink_send_dump_request sendto"); + return -1; + } + + return ret; + } + + static void free_int_list() + { + interface_info_t *tmp = interfaces; + while (tmp) { + if (tmp->name) + free(tmp->name); + interfaces = tmp->next; + free(tmp); + tmp = interfaces; + total_int--; + } + if (total_int) { + LOGE("Wrong interface count found"); + total_int = 0; + } + } + + static void add_int_to_list(interface_info_t *node) + { + /* Todo: Lock here!!!! */ + node->next = interfaces; + interfaces = node; + total_int++; + } + + static int netlink_init_interfaces_list(void) + { + int ret = -1; + DIR *netdir; + struct dirent *de; + char path[SYSFS_PATH_MAX]; + interface_info_t *intfinfo; + int index; + FILE *ifidx; + #define MAX_FGETS_LEN 4 + char idx[MAX_FGETS_LEN+1]; + + if ((netdir = opendir(SYSFS_CLASS_NET)) != NULL) { + while ((de = readdir(netdir))) { + if ((de->d_name[0] == '.') || (!strcmp(de->d_name, "lo")) || + (!strcmp(de->d_name, "wmaster0")) || (!strcmp(de->d_name, "pan0"))) + continue; + snprintf(path, SYSFS_PATH_MAX,"%s/%s/phy80211", SYSFS_CLASS_NET, de->d_name); + if (!access(path, F_OK)) + continue; + snprintf(path, SYSFS_PATH_MAX,"%s/%s/wireless", SYSFS_CLASS_NET, de->d_name); + if (!access(path, F_OK)) + continue; + + snprintf(path, SYSFS_PATH_MAX,"%s/%s/ifindex", SYSFS_CLASS_NET, de->d_name); + if ((ifidx = fopen(path, "r")) != NULL) { + memset(idx, 0, MAX_FGETS_LEN + 1); + if (fgets(idx,MAX_FGETS_LEN, ifidx) != NULL) { + index = strtoimax(idx, NULL, 10); + } else { + LOGE("Can not read %s", path); + continue; + } + } else { + LOGE("Can not open %s for read", path); + continue; + } + /* make some room! */ + intfinfo = (interface_info_t *)malloc(sizeof(interface_info_t)); + if (intfinfo == NULL) { + LOGE("malloc in netlink_init_interfaces_table"); + goto error; + } + /* copy the interface name (eth0, eth1, ...) */ + intfinfo->name = strndup((char *) de->d_name, SYSFS_PATH_MAX); + intfinfo->i = index; + LOGI("interface %s:%d found", intfinfo->name, intfinfo->i); + add_int_to_list(intfinfo); + } + closedir(netdir); + } + ret = 0; + + error: + return ret; + } + + /* + * The netlink socket + */ + + static jint android_net_ethernet_initEthernetNative(JNIEnv *env, + jobject clazz) + { + int ret = -1; + + LOGI("==>%s",__FUNCTION__); + memset(&addr_msg, 0, sizeof(sockaddr_nl)); + addr_msg.nl_family = AF_NETLINK; + memset(&addr_poll, 0, sizeof(sockaddr_nl)); + addr_poll.nl_family = AF_NETLINK; + addr_poll.nl_pid = 0;//getpid(); + addr_poll.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; + + /* + *Create connection to netlink socket + */ + nl_socket_msg = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE); + if (nl_socket_msg <= 0) { + LOGE("Can not create netlink msg socket"); + goto error; + } + if (bind(nl_socket_msg, (struct sockaddr *)(&addr_msg), + sizeof(struct sockaddr_nl))) { + LOGE("Can not bind to netlink msg socket"); + goto error; + } + + nl_socket_poll = socket(AF_NETLINK,SOCK_RAW,NETLINK_ROUTE); + if (nl_socket_poll <= 0) { + LOGE("Can not create netlink poll socket"); + goto error; + } + + errno = 0; + if (bind(nl_socket_poll, (struct sockaddr *)(&addr_poll), + sizeof(struct sockaddr_nl))) { + LOGE("Can not bind to netlink poll socket,%s", strerror(errno)); + + goto error; + } + + if ((ret = netlink_init_interfaces_list()) < 0) { + LOGE("Can not collect the interface list"); + goto error; + } + LOGE("%s exited with success", __FUNCTION__); + return ret; + + error: + LOGE("%s exited with error", __FUNCTION__); + if (nl_socket_msg > 0) + close(nl_socket_msg); + if (nl_socket_poll > 0) + close(nl_socket_poll); + return ret; + } + + static jstring android_net_ethernet_getInterfaceName(JNIEnv *env, + jobject clazz, + jint index) + { + int i = 0; + interface_info_t *info; + LOGI("User ask for device name on %d, list:%X, total:%d", + index, (unsigned int)interfaces, total_int); + info = interfaces; + if (total_int != 0 && index <= (total_int - 1)) { + while (info) { + if (index == i) { + LOGV("Found: %s", info->name); + return env->NewStringUTF(info->name); + } + info = info->next; + i++; + } + } + LOGI("No device name found"); + return env->NewStringUTF(NULL); + } + + + static jint android_net_ethernet_getInterfaceCnt() + { + return total_int; + } + + static JNINativeMethod gEthernetMethods[] = { + {"waitForEvent", "()Ljava/lang/String;", + (void *)android_net_ethernet_waitForEvent}, + {"getInterfaceName", "(I)Ljava/lang/String;", + (void *)android_net_ethernet_getInterfaceName}, + {"initEthernetNative", "()I", + (void *)android_net_ethernet_initEthernetNative}, + {"getInterfaceCnt","()I", + (void *)android_net_ethernet_getInterfaceCnt} + }; + + int register_android_net_ethernet_EthernetManager(JNIEnv* env) + { + jclass eth = env->FindClass(ETH_PKG_NAME); + LOGI("Loading ethernet jni class"); + LOG_FATAL_IF(eth == NULL, "Unable to find class " ETH_PKG_NAME); + dhcpInfoFieldIds.dhcpInfoClass = + env->FindClass("android/net/DhcpInfo"); + + if (dhcpInfoFieldIds.dhcpInfoClass != NULL) { + dhcpInfoFieldIds.constructorId = + env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, + "<init>", "()V"); + dhcpInfoFieldIds.ipaddress = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "ipAddress", "I"); + dhcpInfoFieldIds.gateway = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "gateway", "I"); + dhcpInfoFieldIds.netmask = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "netmask", "I"); + dhcpInfoFieldIds.dns1 = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I"); + dhcpInfoFieldIds.dns2 = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I"); + dhcpInfoFieldIds.serverAddress = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "serverAddress", "I"); + dhcpInfoFieldIds.leaseDuration = + env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, + "leaseDuration", "I"); + } + + return AndroidRuntime::registerNativeMethods(env, + ETH_PKG_NAME, + gEthernetMethods, + NELEM(gEthernetMethods)); + } + +} diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 24afe15c0372..8debc35cba6c 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -34,6 +34,7 @@ <item><xliff:g id="id">mute</xliff:g></item> <item><xliff:g id="id">volume</xliff:g></item> <item><xliff:g id="id">wifi</xliff:g></item> + <item><xliff:g id="id">ethernet</xliff:g></item> <item><xliff:g id="id">cdma_eri</xliff:g></item> <item><xliff:g id="id">data_connection</xliff:g></item> <item><xliff:g id="id">phone_evdo_signal</xliff:g></item> @@ -114,6 +115,7 @@ <item>"mobile_mms,2,0,2,60000,true"</item> <item>"mobile_supl,3,0,2,60000,true"</item> <item>"mobile_hipri,5,0,3,60000,true"</item> + <item>"ethernet,9,9,1,-1,ture"</item> <item>"mobile_fota,10,0,2,60000,true"</item> <item>"mobile_ims,11,0,2,60000,true"</item> <item>"mobile_cbs,12,0,2,60000,true"</item> @@ -136,6 +138,7 @@ <string-array translatable="false" name="radioAttributes"> <item>"1,1"</item> <item>"0,1"</item> + <item>"9,1"</item> </string-array> <!-- Set of NetworkInfo.getType() that reflect data usage. --> diff --git a/ethernet/java/android/net/ethernet/EthernetDevInfo.aidl b/ethernet/java/android/net/ethernet/EthernetDevInfo.aidl new file mode 100644 index 000000000000..0f2c965bcbdf --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetDevInfo.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2010, The Android-x86 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.ethernet; + +parcelable EthernetDevInfo; diff --git a/ethernet/java/android/net/ethernet/EthernetDevInfo.java b/ethernet/java/android/net/ethernet/EthernetDevInfo.java new file mode 100644 index 000000000000..058eb822c613 --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetDevInfo.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2010 The Android-X86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + + +package android.net.ethernet; + +import android.net.ethernet.EthernetDevInfo; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.Parcelable.Creator; + +/** + * Describes the state of any Ethernet connection that is active or + * is in the process of being set up. + */ + +public class EthernetDevInfo implements Parcelable { + /** + * The ethernet interface is configured by dhcp + */ + public static final String ETHERNET_CONN_MODE_DHCP= "dhcp"; + /** + * The ethernet interface is configured manually + */ + public static final String ETHERNET_CONN_MODE_MANUAL = "manual"; + + private String dev_name; + private String ipaddr; + private String netmask; + private String route; + private String dns; + private String mode; + + public EthernetDevInfo () { + dev_name = null; + ipaddr = null; + dns = null; + route = null; + netmask = null; + mode = ETHERNET_CONN_MODE_DHCP; + } + + /** + * save interface name into the configuration + */ + public void setIfName(String ifname) { + this.dev_name = ifname; + } + + /** + * Returns the interface name from the saved configuration + * @return interface name + */ + public String getIfName() { + return this.dev_name; + } + + public void setIpAddress(String ip) { + this.ipaddr = ip; + } + + public String getIpAddress( ) { + return this.ipaddr; + } + + public void setNetMask(String ip) { + this.netmask = ip; + } + + public String getNetMask( ) { + return this.netmask; + } + + public void setRouteAddr(String route) { + this.route = route; + } + + public String getRouteAddr() { + return this.route; + } + + public void setDnsAddr(String dns) { + this.dns = dns; + } + + public String getDnsAddr( ) { + return this.dns; + } + + /** + * Set ethernet configuration mode + * @param mode {@code ETHERNET_CONN_MODE_DHCP} for dhcp {@code ETHERNET_CONN_MODE_MANUAL} for manual configure + * @return + */ + public boolean setConnectMode(String mode) { + if (mode.equals(ETHERNET_CONN_MODE_DHCP) || mode.equals(ETHERNET_CONN_MODE_MANUAL)) { + this.mode = mode; + return true; + } + return false; + } + + public String getConnectMode() { + return this.mode; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.dev_name); + dest.writeString(this.ipaddr); + dest.writeString(this.netmask); + dest.writeString(this.route); + dest.writeString(this.dns); + dest.writeString(this.mode); + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<EthernetDevInfo> CREATOR = new Creator<EthernetDevInfo>() { + public EthernetDevInfo createFromParcel(Parcel in) { + EthernetDevInfo info = new EthernetDevInfo(); + info.setIfName(in.readString()); + info.setIpAddress(in.readString()); + info.setNetMask(in.readString()); + info.setRouteAddr(in.readString()); + info.setDnsAddr(in.readString()); + info.setConnectMode(in.readString()); + return info; + } + + public EthernetDevInfo[] newArray(int size) { + return new EthernetDevInfo[size]; + } + }; +} diff --git a/ethernet/java/android/net/ethernet/EthernetManager.java b/ethernet/java/android/net/ethernet/EthernetManager.java new file mode 100644 index 000000000000..ac480c236586 --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetManager.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2010 The Android-X86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +package android.net.ethernet; + +import java.util.List; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Slog; + +/** + * This class provides the primary API for managing all aspects of Ethernet + * connectivity. Get an instance of this class by calling + * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.ETHERNET_SERVICE)}. + * + * This is the API to use when performing Ethernet specific operations. To + * perform operations that pertain to network connectivity at an abstract + * level, use {@link android.net.ConnectivityManager}. + */ +public class EthernetManager { + public static final String TAG = "EthernetManager"; + public static final int ETHERNET_DEVICE_SCAN_RESULT_READY = 0; + public static final String ETHERNET_STATE_CHANGED_ACTION = + "android.net.ethernet.ETHERNET_STATE_CHANGED"; + public static final String NETWORK_STATE_CHANGED_ACTION = + "android.net.ethernet.STATE_CHANGE"; + public static final String LINK_CONFIGURATION_CHANGED_ACTION = + "android.net.ethernet.LINK_CONFIGURATION_CHANGED"; + + public static final String EXTRA_NETWORK_INFO = "networkInfo"; + public static final String EXTRA_ETHERNET_STATE = "ETHERNET_state"; + public static final String EXTRA_PREVIOUS_ETHERNET_STATE = "previous_ETHERNET_state"; + + public static final int ETHERNET_STATE_UNKNOWN = 0; + public static final int ETHERNET_STATE_DISABLED = 1; + public static final int ETHERNET_STATE_ENABLED = 2; + + public static final int DATA_ACTIVITY_NONE = 0x00; + public static final int DATA_ACTIVITY_IN = 0x01; + public static final int DATA_ACTIVITY_OUT = 0x02; + public static final int DATA_ACTIVITY_INOUT = 0x03; + + IEthernetManager mService; + Handler mHandler; + + public EthernetManager(IEthernetManager service, Handler handler) { + Slog.i(TAG, "Init Ethernet Manager, service: " +service); + mService = service; + mHandler = handler; + } + + /** + * check if the ethernet service has been configured. + * @return {@code true} if configured {@code false} otherwise + */ + public boolean isConfigured() { + try { + return mService.isConfigured(); + } catch (RemoteException e) { + Slog.i(TAG, "Can not check eth config state"); + } + return false; + } + + /** + * Return the saved ethernet configuration + * @return ethernet interface configuration on success, {@code null} on failure + */ + public EthernetDevInfo getSavedConfig() { + try { + return mService.getSavedConfig(); + } catch (RemoteException e) { + Slog.i(TAG, "Can not get eth config"); + } + return null; + } + + /** + * update a ethernet interface information + * @param info the interface infomation + */ + public void updateDevInfo(EthernetDevInfo info) { + try { + mService.updateDevInfo(info); + } catch (RemoteException e) { + Slog.i(TAG, "Can not update ethernet device info"); + } + } + + /** + * get all the ethernet device names + * @return interface name list on success, {@code null} on failure + */ + public String[] getDeviceNameList() { + try { + return mService.getDeviceNameList(); + } catch (RemoteException e) { + return null; + } + } + /** + * Enable or Disable a ethernet service + * @param enable {@code true} to enable, {@code false} to disable + * @hide + */ + public void setEnabled(boolean enable) { + try { + mService.setState(enable ? ETHERNET_STATE_ENABLED:ETHERNET_STATE_DISABLED); + } catch (RemoteException e) { + Slog.i(TAG,"Can not set new state"); + } + } + + /** + * Get ethernet service state + * @return the state of the ethernet service + */ + public int getState( ) { + try { + return mService.getState(); + } catch (RemoteException e) { + return 0; + } + } + + /** + * get the number of ethernet interfaces in the system + * @return the number of ethernet interfaces + */ + public int getTotalInterface() { + try { + return mService.getTotalInterface(); + } catch (RemoteException e) { + return 0; + } + } + + /** + * @hide + */ + public void setDefaultConf() { + try { + mService.setMode(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP); + } catch (RemoteException e) { + } + } + + public boolean startEthernet() { + try { + mService.startEthernet(); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean stopEthernet() { + try { + mService.stopEthernet(); + return true; + } catch (RemoteException e) { + return false; + } + } + + public boolean reconnect() { + try { + mService.reconnect(); + return true; + } catch (RemoteException e) { + return false; + } + } + +} diff --git a/ethernet/java/android/net/ethernet/EthernetMonitor.java b/ethernet/java/android/net/ethernet/EthernetMonitor.java new file mode 100644 index 000000000000..a5c7d6297d8a --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetMonitor.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 The Android-X86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +package android.net.ethernet; + +import java.util.regex.Matcher; + +import android.net.NetworkInfo; +import android.util.Config; +import android.util.Slog; +import java.util.StringTokenizer; + +/** + * Listens for events from kernel, and passes them on + * to the {@link EtherentStateTracker} for handling. Runs in its own thread. + * + * @hide + */ +public class EthernetMonitor { + private static final String TAG = "EthernetMonitor"; + private static final int CONNECTED = 1; + private static final int DISCONNECTED = 2; + private static final int PHYUP = 3; + private static final String connectedEvent = "CONNECTED"; + private static final String disconnectedEvent = "DISCONNECTED"; + private static final int ADD_ADDR = 20; + private static final int RM_ADDR = 21; + private static final int NEW_LINK = 16; + private static final int DEL_LINK = 17; + private static final boolean localLOGV = false; + + private EthernetStateTracker mEthernetStateTracker; + + public EthernetMonitor(EthernetStateTracker tracker) { + mEthernetStateTracker = tracker; + } + + public void startMonitoring() { + new MonitorThread().start(); + } + + class MonitorThread extends Thread { + public MonitorThread() { + super("EthMonitor"); + } + + public void run() { + //noinspection InfiniteLoopStatement + for (;;) { + int index; + int i; + int cmd; + String dev; + + if (localLOGV) Slog.v(TAG, "go poll events"); + + String eventName = EthernetNative.waitForEvent(); + + if (eventName == null) { + continue; + } + + if (localLOGV) Slog.v(TAG, "get event " + eventName); + + /* + * Map event name into event enum + */ + i = 0; + while (i < eventName.length()) { + index = eventName.substring(i).indexOf(":"); + if (index == -1) + break; + dev = eventName.substring(i, index); + i += index + 1; + index = eventName.substring(i).indexOf(":"); + if (index == -1) + break; + cmd = Integer.parseInt(eventName.substring(i, i+index)); + i += index + 1; + if (localLOGV) Slog.v(TAG, "dev: " + dev + " ev " + cmd); + switch (cmd) { + case DEL_LINK: + handleEvent(dev, DISCONNECTED); + break; + case ADD_ADDR: + handleEvent(dev, CONNECTED); + break; + case NEW_LINK: + handleEvent(dev, PHYUP); + break; + } + } + } + } + + /** + * Handle all supplicant events except STATE-CHANGE + * @param event the event type + * @param remainder the rest of the string following the + * event name and " — " + */ + void handleEvent(String ifname,int event) { + switch (event) { + case DISCONNECTED: + mEthernetStateTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.DISCONNECTED); + break; + case CONNECTED: + mEthernetStateTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.CONNECTED); + break; + case PHYUP: + mEthernetStateTracker.notifyPhyConnected(ifname); + break; + default: + mEthernetStateTracker.notifyStateChange(ifname,NetworkInfo.DetailedState.FAILED); + break; + } + } + } +} diff --git a/ethernet/java/android/net/ethernet/EthernetNative.java b/ethernet/java/android/net/ethernet/EthernetNative.java new file mode 100644 index 000000000000..7f3a083e89be --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetNative.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 The Android-X86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +package android.net.ethernet; + +/** + * Native calls for sending requests to the kernel, + * {@hide} + */ +public class EthernetNative { + public native static String getInterfaceName(int i); + public native static int getInterfaceCnt(); + public native static int initEthernetNative(); + public native static String waitForEvent(); +} diff --git a/ethernet/java/android/net/ethernet/EthernetStateMachine.java b/ethernet/java/android/net/ethernet/EthernetStateMachine.java new file mode 100644 index 000000000000..2a3054057ac9 --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetStateMachine.java @@ -0,0 +1,471 @@ +/* + * 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.ethernet; + +import java.net.UnknownHostException; + +import static android.net.ethernet.EthernetManager.ETHERNET_STATE_DISABLED; +import static android.net.ethernet.EthernetManager.ETHERNET_STATE_ENABLED; +import static android.net.ethernet.EthernetManager.ETHERNET_STATE_UNKNOWN; + +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.ServiceManager; +import android.os.WorkSource; + +import android.R; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkStateTracker; +import android.net.NetworkUtils; +import android.net.ProxyProperties; +import android.net.RouteInfo; +import android.net.LinkAddress; +import android.net.DhcpInfo; +import android.net.DhcpInfoInternal; +import android.net.DhcpStateMachine; +import android.net.LinkCapabilities; +import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.os.SystemProperties; +import android.util.*; +import java.util.Iterator; + +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; + +import android.net.DnsPinger; +import java.util.concurrent.atomic.AtomicBoolean; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; + +public class EthernetStateMachine extends StateMachine { + + private static final String TAG = "EthernetStateMachine"; + private static final String NETWORKTYPE = "ETHERNET"; + private static final boolean DBG = true; + + public static final int EVENT_DHCP_START = 0; + public static final int EVENT_INTERFACE_CONFIGURATION_SUCCEEDED = 1; + public static final int EVENT_INTERFACE_CONFIGURATION_FAILED = 2; + public static final int EVENT_HW_CONNECTED = 3; + public static final int EVENT_HW_DISCONNECTED = 4; + public static final int EVENT_HW_PHYCONNECTED = 5; + private static final int NOTIFY_ID = 6; + private static final boolean localLOGV = true; + + + private EthernetManager mEthernetManager; + + private INetworkManagementService mNwService; + private ConnectivityManager mCm; + + private DhcpHandler mDhcpTarget; + private Handler mTrackerTarget; + private String mInterfaceName; + + private LinkCapabilities mLinkCapabilities; + + private Context mContext; + + private DhcpInfo mDhcpInfo; + private DhcpInfoInternal mDhcpInfoInternal; + private String[] sDnsPropNames; + private NetworkInfo mNetworkInfo; + private DhcpStateMachine mDhcpStateMachine; + + private boolean mStackConnected; + private boolean mHWConnected; + private boolean mInterfaceStopped; + private boolean mStartingDhcp; + + private static final int DEFAULT_MAX_DHCP_RETRIES = 9; + + + /** + * One of {@link EthernetManager#ETHERNET_STATE_DISABLED}, + * {@link EthernetManager#ETHERNET_STATE_ENABLED}, + * {@link EthernetManager#ETHERNET_STATE_UNKNOWN} + * + */ + private final AtomicInteger mEthernetState = new AtomicInteger(ETHERNET_STATE_DISABLED); + + /** + * Keep track of whether ETHERNET is running. + */ + private boolean mIsRunning = false; + + /** + * Keep track of whether we last told the battery stats we had started. + */ + private boolean mReportedRunning = false; + + /** + * Most recently set source of starting ETHERNET. + */ + private final WorkSource mRunningEthernetUids = new WorkSource(); + + /** + * The last reported UIDs that were responsible for starting ETHERNET. + */ + private final WorkSource mLastRunningEthernetUids = new WorkSource(); + + private boolean mNextEthernetActionExplicit = false; + private int mLastExplicitNetworkId; + private long mLastNetworkChoiceTime; + private static final long EXPLICIT_CONNECT_ALLOWED_DELAY_MS = 2 * 60 * 1000; + + + public EthernetStateMachine(Context context, String ethInterface) { + super(TAG); + + mDhcpInfo = new DhcpInfo(); + + mContext = context; + mInterfaceName = ethInterface; + + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, ""); + + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNwService = INetworkManagementService.Stub.asInterface(b); + + HandlerThread dhcpThread = new HandlerThread("DHCP Handler Thread"); + dhcpThread.start(); + mDhcpTarget = new DhcpHandler(dhcpThread.getLooper()); + + mNetworkInfo.setIsAvailable(false); + + if (DBG) setDbg(true); + + //start the state machine +// start(); + } + + + public void setEthernetEnabled(boolean enable) { + } + + public int syncGetEthernetState() { + return mEthernetState.get(); + } + + public String syncGetEthernetStateByName() { + switch (mEthernetState.get()) { + case ETHERNET_STATE_DISABLED: + return "disabled"; + case ETHERNET_STATE_ENABLED: + return "enabled"; + case ETHERNET_STATE_UNKNOWN: + return "unknown state"; + default: + return "[invalid state]"; + } + } + + public DhcpInfo syncGetDhcpInfo() { + synchronized (mDhcpInfoInternal) { + return mDhcpInfoInternal.makeDhcpInfo(); + } + } + + + /********************************************************* + * Internal private functions + ********************************************************/ + + private void checkAndSetConnectivityInstance() { + if (mCm == null) { + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + } + } + + + /** + * Fetch LinkProperties for the network + */ + public void startMonitoring(Context context) { + mContext = context; + + Slog.v(TAG,"start to monitor the ethernet devices"); + mEthernetManager = (EthernetManager)mContext.getSystemService(Context.ETHERNET_SERVICE); + int state = mEthernetManager.getState(); + if (state != mEthernetManager.ETHERNET_STATE_DISABLED) { + if (state == mEthernetManager.ETHERNET_STATE_UNKNOWN) { + // maybe this is the first time we run, enable it if ethernet devices exist + mEthernetManager.setEnabled(mEthernetManager.getDeviceNameList() != null); + } else { + try { + Slog.e(TAG, "startMonitoring resetInterface()"); + resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong ethernet configuration"); + } + } + } + + IntentFilter filter = new IntentFilter(); + filter.addAction(EthernetManager.NETWORK_STATE_CHANGED_ACTION); + } + + private boolean configureInterface(EthernetDevInfo info) throws UnknownHostException { + + LinkProperties linkProperties = getLinkProperties(); + + mStackConnected = false; + mHWConnected = false; + mInterfaceStopped = false; + mStartingDhcp = true; + if (info.getConnectMode().equals(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP)) { + if (localLOGV) Slog.i(TAG, "trigger dhcp for device " + info.getIfName()); + sDnsPropNames = new String[] { + "dhcp." + mInterfaceName + ".dns1", + "dhcp." + mInterfaceName + ".dns2" + }; + + mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START); + } else { + int event; + sDnsPropNames = new String[] { + "net." + mInterfaceName + ".dns1", + "net." + mInterfaceName + ".dns2" + }; + + mDhcpInfo.ipAddress = lookupHost(info.getIpAddress()); + mDhcpInfo.gateway = lookupHost(info.getRouteAddr()); + mDhcpInfo.netmask = lookupHost(info.getNetMask()); + mDhcpInfo.dns1 = lookupHost(info.getDnsAddr()); + mDhcpInfo.dns2 = 0; + + NetworkUtils.resetConnections(info.getIfName(), NetworkUtils.RESET_ALL_ADDRESSES); + + if (NetworkUtils.configureInterface(info.getIfName(), mDhcpInfo)) { + event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; + SystemProperties.set("net.dns1", info.getDnsAddr()); + SystemProperties.set("net." + info.getIfName() + ".dns1", info.getDnsAddr()); + SystemProperties.set("net." + info.getIfName() + ".dns2", "0.0.0.0"); + if (localLOGV) Slog.v(TAG, "Static IP configuration succeeded"); + } else { + event = EVENT_INTERFACE_CONFIGURATION_FAILED; + if (localLOGV) Slog.w(TAG, "Static IP configuration failed"); + } + sendMessage(event); + } + return true; + } + + + /** + * reset ethernet interface + * @return true + * @throws UnknownHostException + */ + public boolean resetInterface() throws UnknownHostException { + /* + * This will guide us to enabled the enabled device + */ + if (mEthernetManager != null) { + EthernetDevInfo info = mEthernetManager.getSavedConfig(); + if (info != null && mEthernetManager.isConfigured()) { + synchronized (this) { + mInterfaceName = info.getIfName(); + Slog.i(TAG, "reset device " + mInterfaceName); + NetworkUtils.resetConnections(mInterfaceName, NetworkUtils.RESET_ALL_ADDRESSES); + + // Stop DHCP + if (mDhcpTarget != null) { + mDhcpTarget.removeMessages(EVENT_DHCP_START); + } + + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + Slog.w(TAG, "Could not stop DHCP"); + } + configureInterface(info); + } + } + } + return true; + } + + /** + * Stop etherent interface + * @param suspend {@code false} disable the interface {@code true} only reset the connection without disable the interface + * @return true + */ + public boolean stopInterface(boolean suspend) { + if (mEthernetManager != null) { + EthernetDevInfo info = mEthernetManager.getSavedConfig(); + if (info != null && mEthernetManager.isConfigured()) { + synchronized (mDhcpTarget) { + mInterfaceStopped = true; + Slog.i(TAG, "stop dhcp and interface"); + mDhcpTarget.removeMessages(EVENT_DHCP_START); + String ifname = info.getIfName(); + + if (!NetworkUtils.stopDhcp(ifname)) { + Slog.w(TAG, "Could not stop DHCP"); + } + NetworkUtils.resetConnections(ifname, NetworkUtils.RESET_ALL_ADDRESSES); + if (!suspend) + NetworkUtils.disableInterface(ifname); + } + } + } + return true; + } + + + private void postNotification(int event) { + String ns = Context.NOTIFICATION_SERVICE; + Intent intent = new Intent(EthernetManager.ETHERNET_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(EthernetManager.EXTRA_ETHERNET_STATE, event); + mContext.sendStickyBroadcast(intent); + } + + private void setState(boolean state, int event) { + if (mNetworkInfo.isConnected() != state) { + if (state) { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + } else { + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); + stopInterface(true); + } + mNetworkInfo.setIsAvailable(state); + postNotification(event); + } + } + + public void handleMessage(Message msg) { + + synchronized (this) { + switch (msg.what) { + case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED: + if (localLOGV) Slog.i(TAG, "received configured succeeded, stack=" + mStackConnected + " HW=" + mHWConnected); + mStackConnected = true; + if (mHWConnected) + setState(true, msg.what); + break; + case EVENT_INTERFACE_CONFIGURATION_FAILED: + mStackConnected = false; + //start to retry ? + break; + case EVENT_HW_CONNECTED: + if (localLOGV) Slog.i(TAG, "received HW connected, stack=" + mStackConnected + " HW=" + mHWConnected); + mHWConnected = true; + if (mStackConnected) + setState(true, msg.what); + break; + case EVENT_HW_DISCONNECTED: + if (localLOGV) Slog.i(TAG, "received disconnected events, stack=" + mStackConnected + " HW=" + mHWConnected); + setState(mHWConnected = false, msg.what); + break; + case EVENT_HW_PHYCONNECTED: + if (localLOGV) Slog.i(TAG, "interface up event, kick off connection request"); + if (!mStartingDhcp) { + int state = mEthernetManager.getState(); + if (state != mEthernetManager.ETHERNET_STATE_DISABLED) { + EthernetDevInfo info = mEthernetManager.getSavedConfig(); + if (info != null && mEthernetManager.isConfigured()) { + try { + configureInterface(info); + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + //e.printStackTrace(); + Slog.e(TAG, "Cannot configure interface"); + } + } + } + } + break; + } + } + } + + private class DhcpHandler extends Handler { + public DhcpHandler(Looper looper) { + super(looper); + } + + public void handleMessage(Message msg) { + int event; + + switch (msg.what) { + case EVENT_DHCP_START: + synchronized (mDhcpTarget) { + if (!mInterfaceStopped) { + Slog.d(TAG, "DhcpHandler: DHCP request started"); + DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); + if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) { + event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; + Slog.d(TAG, "DhcpHandler: DHCP request succeeded: " + dhcpInfoInternal.toString()); + } else { + event = EVENT_INTERFACE_CONFIGURATION_FAILED; + Slog.e(TAG, "DhcpHandler: DHCP request failed: " + NetworkUtils.getDhcpError()); + } + // sendMessage(event); + } else { + mInterfaceStopped = false; + } + mStartingDhcp = false; + } + break; + } + } + } + + static LinkProperties getLinkProperties() { + return new LinkProperties(); + } + + public void reconnectCommand() { +// sendMessage(CMD_RECONNECT); + } + + private static int lookupHost(String hostname) { + InetAddress inetAddress; + try { + inetAddress = InetAddress.getByName(hostname); + } catch (UnknownHostException e) { + return -1; + } + byte[] addrBytes; + int addr; + addrBytes = inetAddress.getAddress(); + addr = ((addrBytes[3] & 0xff) << 24) + | ((addrBytes[2] & 0xff) << 16) + | ((addrBytes[1] & 0xff) << 8) + | (addrBytes[0] & 0xff); + return addr; + } +} + diff --git a/ethernet/java/android/net/ethernet/EthernetStateTracker.java b/ethernet/java/android/net/ethernet/EthernetStateTracker.java new file mode 100644 index 000000000000..afcb119eb7bc --- /dev/null +++ b/ethernet/java/android/net/ethernet/EthernetStateTracker.java @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2010 The Android-X86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +package android.net.ethernet; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import android.R; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.bluetooth.BluetoothHeadset; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkStateTracker; +import android.net.NetworkUtils; +import android.net.ProxyProperties; +import android.net.RouteInfo; +import android.net.LinkAddress; +import android.net.DhcpInfoInternal; +import android.net.LinkCapabilities; +import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Parcel; +import android.os.SystemProperties; +import android.util.*; +import java.util.Iterator; + +import android.net.DnsPinger; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Track the state of Ethernet connectivity. All event handling is done here, + * and all changes in connectivity state are initiated here. + * + * @hide + */ + +public class EthernetStateTracker implements NetworkStateTracker { + private static final String NETWORKTYPE = "ETHERNET"; + private static final String TAG = "EthernetStateTracker"; + + private static final boolean localLOGV = true; + + public static final int EVENT_DHCP_START = 0; + public static final int EVENT_INTERFACE_CONFIGURATION_SUCCEEDED = 1; + public static final int EVENT_INTERFACE_CONFIGURATION_FAILED = 2; + public static final int EVENT_HW_CONNECTED = 3; + public static final int EVENT_HW_DISCONNECTED = 4; + public static final int EVENT_HW_PHYCONNECTED = 5; + private static final int NOTIFY_ID = 6; + + private EthernetManager mEthernetManager; + + private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); + private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); + private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); + + private LinkProperties mLinkProperties; + private LinkCapabilities mLinkCapabilities; + private NetworkInfo mNetworkInfo; + + private DnsPinger mDnsPinger; + + private boolean mStackConnected; + private boolean mHWConnected; + private boolean mInterfaceStopped; + private DhcpHandler mDhcpTarget; + private String mInterfaceName ; + private DhcpInfoInternal mDhcpInfoInternal; + private EthernetMonitor mMonitor; + private String[] sDnsPropNames; + private boolean mStartingDhcp; + private NotificationManager mNotificationManager; + private Notification mNotification; + + private Handler mTrackerTarget; + public static EthernetStateTracker sInstance; + + /* For sending events to connectivity service handler */ + private Handler mCsHandler; + private Context mContext; + + public EthernetStateTracker(int netType, String networkName) { + if (localLOGV) Slog.v(TAG, "Starts..."); + + if (EthernetNative.initEthernetNative() != 0) { + Slog.e(TAG,"Can not init ethernet device layers"); + return; + } + + if (localLOGV) Slog.v(TAG,"Successed"); + HandlerThread dhcpThread = new HandlerThread("DHCP Handler Thread"); + dhcpThread.start(); +// mDhcpTarget = new DhcpHandler(dhcpThread.getLooper(), this); + mMonitor = new EthernetMonitor(this); + + mNetworkInfo = new NetworkInfo(netType, 0, networkName, ""); + mLinkProperties = new LinkProperties(); + mLinkCapabilities = new LinkCapabilities(); + + mNetworkInfo.setIsAvailable(false); + setTeardownRequested(false); + + } + + public void setTeardownRequested(boolean isRequested) { + mTeardownRequested.set(isRequested); + } + + public boolean isTeardownRequested() { + return mTeardownRequested.get(); + } + + public void startMonitoring(Context context, Handler target) { + mCsHandler = target; + mContext = context; + + if (localLOGV) Slog.v(TAG,"start to monitor the ethernet devices"); + mEthernetManager = (EthernetManager) mContext.getSystemService(Context.ETHERNET_SERVICE); + + int state = mEthernetManager.getState(); + if (state != mEthernetManager.ETHERNET_STATE_DISABLED) { + if (state == mEthernetManager.ETHERNET_STATE_UNKNOWN) { + // maybe this is the first time we run, enable it if ethernet devices exist + mEthernetManager.setEnabled(mEthernetManager.getDeviceNameList() != null); + } else { + try { + resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong ethernet configuration"); + } + } + } + IntentFilter filter = new IntentFilter(); + filter.addAction(EthernetManager.NETWORK_STATE_CHANGED_ACTION); + } + + /** + * Disable connectivity to a network + * TODO: do away with return value after making MobileDataStateTracker async + */ + public boolean teardown() { + mTeardownRequested.set(true); + mEthernetManager.stopEthernet(); + return true; + } + + /** + * Re-enable connectivity to a network after a {@link #teardown()}. + */ + public boolean reconnect() { + mTeardownRequested.set(false); + mEthernetManager.startEthernet(); + return true; + } + + + /** + * Stop etherent interface + * @param suspend {@code false} disable the interface {@code true} only reset the connection without disable the interface + * @return true + */ + public boolean stopInterface(boolean suspend) { + if (mEthernetManager != null) { + EthernetDevInfo info = mEthernetManager.getSavedConfig(); + if (info != null && mEthernetManager.isConfigured()) { +/* synchronized (mDhcpTarget) { + mInterfaceStopped = true; + if (localLOGV) Slog.i(TAG, "stop dhcp and interface"); + mDhcpTarget.removeMessages(EVENT_DHCP_START); + String ifname = info.getIfName(); + + if (!NetworkUtils.stopDhcp(ifname)) { + if (localLOGV) Slog.w(TAG, "Could not stop DHCP"); + } + NetworkUtils.resetConnections(ifname, NetworkUtils.RESET_ALL_ADDRESSES); + if (!suspend) + NetworkUtils.disableInterface(ifname); + } +*/ + } + } + return true; + } + + private boolean configureInterface(EthernetDevInfo info) throws UnknownHostException { + + mStackConnected = false; + mHWConnected = false; + mInterfaceStopped = false; + mStartingDhcp = true; + + DhcpInfoInternal mDhcpInfoInternal = new DhcpInfoInternal(); + LinkProperties linkProperties = getLinkProperties(); + + if (info.getConnectMode().equals(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP)) { + if (localLOGV) Slog.i(TAG, "trigger dhcp for device " + info.getIfName()); + sDnsPropNames = new String[] { + "dhcp." + mInterfaceName + ".dns1", + "dhcp." + mInterfaceName + ".dns2" + }; + + mDhcpTarget.sendEmptyMessage(EVENT_DHCP_START); + } else { + int event; + sDnsPropNames = new String[] { + "net." + mInterfaceName + ".dns1", + "net." + mInterfaceName + ".dns2" + }; + + if (linkProperties != null) { + Iterator<LinkAddress> iter = linkProperties.getLinkAddresses().iterator(); + if (iter.hasNext()) { + LinkAddress linkAddress = iter.next(); + mDhcpInfoInternal.ipAddress = linkAddress.getAddress().getHostAddress(); + for (RouteInfo route : linkProperties.getRoutes()) { + mDhcpInfoInternal.addRoute(route); + } + + mDhcpInfoInternal.prefixLength = linkAddress.getNetworkPrefixLength(); + Iterator<InetAddress> dnsIterator = linkProperties.getDnses().iterator(); + mDhcpInfoInternal.dns1 = dnsIterator.next().getHostAddress(); + + if (dnsIterator.hasNext()) { + mDhcpInfoInternal.dns2 = dnsIterator.next().getHostAddress(); + } + } + } + + + if (localLOGV) Slog.i(TAG, "set ip manually " + mDhcpInfoInternal.toString()); + NetworkUtils.resetConnections(info.getIfName(), NetworkUtils.RESET_ALL_ADDRESSES); + + if (NetworkUtils.runDhcp(info.getIfName(), mDhcpInfoInternal)) { + event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; + SystemProperties.set("net.dns1", info.getDnsAddr()); + SystemProperties.set("net." + info.getIfName() + ".dns1", info.getDnsAddr()); + SystemProperties.set("net." + info.getIfName() + ".dns2", "0.0.0.0"); + if (localLOGV) Slog.v(TAG, "Static IP configuration succeeded"); + } else { + event = EVENT_INTERFACE_CONFIGURATION_FAILED; + if (localLOGV) Slog.w(TAG, "Static IP configuration failed"); + } +// this.sendEmptyMessage(event); + } + return true; + } + + /** + * reset ethernet interface + * @return true + * @throws UnknownHostException + */ + public boolean resetInterface() throws UnknownHostException{ + /* + * This will guide us to enabled the enabled device + */ + if (mEthernetManager != null) { + EthernetDevInfo info = mEthernetManager.getSavedConfig(); + if (info != null && mEthernetManager.isConfigured()) { + synchronized (this) { + mInterfaceName = info.getIfName(); + if (localLOGV) Slog.i(TAG, "reset device " + mInterfaceName); + NetworkUtils.resetConnections(mInterfaceName, NetworkUtils.RESET_ALL_ADDRESSES); + // Stop DHCP +// if (mDhcpTarget != null) { +// mDhcpTarget.removeMessages(EVENT_DHCP_START); +// } + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + if (localLOGV) Slog.w(TAG, "Could not stop DHCP"); + } + configureInterface(info); + } + } + } + return true; + } + + public void StartPolling() { + mMonitor.startMonitoring(); + } + + public synchronized boolean isAvailable() { + // Only say available if we have interfaces and user did not disable us. + return ((mEthernetManager.getTotalInterface() != 0) && (mEthernetManager.getState() != EthernetManager.ETHERNET_STATE_DISABLED)); + } + +// @Override + public void setUserDataEnable(boolean enabled) { + Slog.w(TAG, "ignoring setUserDataEnable(" + enabled + ")"); + } + +// @Override + public void setPolicyDataEnable(boolean enabled) { + Slog.w(TAG, "ignoring setPolicyDataEnable(" + enabled + ")"); + } + +/* @Override + public boolean reconnect() { + try { + synchronized (this) { + if (mHWConnected && mStackConnected) + return true; + } + if (mEthernetManager.getState() != EthernetManager.ETHERNET_STATE_DISABLED) { + // maybe this is the first time we run, so set it to enabled + mEthernetManager.setEnabled(true); + if (!mEthernetManager.isConfigured()) { + mEthernetManager.setDefaultConf(); + } + return resetInterface(); + } + } catch (UnknownHostException e) { + e.printStackTrace(); + } + return false; + + } +*/ +// @Override + public boolean setRadio(boolean turnOn) { + return false; + } + +/* + public boolean teardown() { + return (mEthernetManager != null) ? stopInterface(false) : false; + } +*/ + private void postNotification(int event) { + String ns = Context.NOTIFICATION_SERVICE; + Intent intent = new Intent(EthernetManager.ETHERNET_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + intent.putExtra(EthernetManager.EXTRA_ETHERNET_STATE, event); + mContext.sendStickyBroadcast(intent); + } + + private void setState(boolean state, int event) { + if (mNetworkInfo.isConnected() != state) { + if (state) { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + } else { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null); + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null); + stopInterface(true); + } + mNetworkInfo.setIsAvailable(state); + postNotification(event); + } + } + + public void handleMessage(Message msg) { + + synchronized (this) { + switch (msg.what) { + case EVENT_INTERFACE_CONFIGURATION_SUCCEEDED: + if (localLOGV) Slog.i(TAG, "received configured succeeded, stack=" + mStackConnected + " HW=" + mHWConnected); + mStackConnected = true; + if (mHWConnected) + setState(true, msg.what); + break; + case EVENT_INTERFACE_CONFIGURATION_FAILED: + mStackConnected = false; + //start to retry ? + break; + case EVENT_HW_CONNECTED: + if (localLOGV) Slog.i(TAG, "received HW connected, stack=" + mStackConnected + " HW=" + mHWConnected); + mHWConnected = true; + if (mStackConnected) + setState(true, msg.what); + break; + case EVENT_HW_DISCONNECTED: + if (localLOGV) Slog.i(TAG, "received disconnected events, stack=" + mStackConnected + " HW=" + mHWConnected); + setState(mHWConnected = false, msg.what); + break; + case EVENT_HW_PHYCONNECTED: + if (localLOGV) Slog.i(TAG, "interface up event, kick off connection request"); + if (!mStartingDhcp) { + int state = mEthernetManager.getState(); + if (state != mEthernetManager.ETHERNET_STATE_DISABLED) { + EthernetDevInfo info = mEthernetManager.getSavedConfig(); + if (info != null && mEthernetManager.isConfigured()) { + try { + configureInterface(info); + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + //e.printStackTrace(); + Slog.e(TAG, "Cannot configure interface"); + } + } + } + } + break; + } + } + } + + private class DhcpHandler extends Handler { + public DhcpHandler(Looper looper, Handler target) { + super(looper); + mTrackerTarget = target; + } + + public void handleMessage(Message msg) { + int event; + + switch (msg.what) { + case EVENT_DHCP_START: + if (!mInterfaceStopped) { + if (localLOGV) Slog.d(TAG, "DhcpHandler: DHCP request started"); + + DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal(); + if (NetworkUtils.runDhcp(mInterfaceName, dhcpInfoInternal)) { + event = EVENT_INTERFACE_CONFIGURATION_SUCCEEDED; + if (localLOGV) Slog.d(TAG, "DhcpHandler: DHCP request succeeded: " + mDhcpInfoInternal.toString()); + } else { + event = EVENT_INTERFACE_CONFIGURATION_FAILED; + Slog.e(TAG, "DhcpHandler: DHCP request failed: " + NetworkUtils.getDhcpError()); + } + } else { + mInterfaceStopped = false; + } + mStartingDhcp = false; + break; + } + } + } + + public void notifyPhyConnected(String ifname) { + if (localLOGV) Slog.v(TAG, "report interface is up for " + ifname); + synchronized(this) { +// this.sendEmptyMessage(EVENT_HW_PHYCONNECTED); + } + + } + + public void notifyStateChange(String ifname,DetailedState state) { + if (localLOGV) Slog.i(TAG, "report new state " + state.toString() + " on dev " + ifname); + if (ifname.equals(mInterfaceName)) { + if (localLOGV) Slog.v(TAG, "update network state tracker"); + synchronized(this) { + // this.sendEmptyMessage(state.equals(DetailedState.CONNECTED, null, null) + // ? EVENT_HW_CONNECTED : EVENT_HW_DISCONNECTED); + + } + } + } + + + private static int lookupHost(String hostname) { + InetAddress inetAddress; + try { + inetAddress = InetAddress.getByName(hostname); + } catch (UnknownHostException e) { + return -1; + } + byte[] addrBytes; + int addr; + addrBytes = inetAddress.getAddress(); + addr = ((addrBytes[3] & 0xff) << 24) + | ((addrBytes[2] & 0xff) << 16) + | ((addrBytes[1] & 0xff) << 8) + | (addrBytes[0] & 0xff); + return addr; + } + + public void setDependencyMet(boolean met) { + // not supported on this network + } + + /** + * 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 NetworkInfo getNetworkInfo() { + return new NetworkInfo(mNetworkInfo); + } + + /** + * Fetch LinkProperties for the network + */ + public 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); + } + + /** + * 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.default"; + } + +} diff --git a/ethernet/java/android/net/ethernet/IEthernetManager.aidl b/ethernet/java/android/net/ethernet/IEthernetManager.aidl new file mode 100644 index 000000000000..df81e636c40a --- /dev/null +++ b/ethernet/java/android/net/ethernet/IEthernetManager.aidl @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2010, The Android-x86 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.ethernet; +import android.net.ethernet.EthernetDevInfo; + +interface IEthernetManager +{ + String[] getDeviceNameList(); + void setState(int state); + int getState( ); + void updateDevInfo(in EthernetDevInfo info); + boolean isConfigured(); + EthernetDevInfo getSavedConfig(); + int getTotalInterface(); + void setMode(String mode); + void reconnect(); + void startEthernet(); + void stopEthernet(); +} diff --git a/packages/SystemUI/res/drawable-hdpi/connect_creating.png b/packages/SystemUI/res/drawable-hdpi/connect_creating.png Binary files differnew file mode 100644 index 000000000000..a70572ccb3fb --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/connect_creating.png diff --git a/packages/SystemUI/res/drawable-hdpi/connect_established.png b/packages/SystemUI/res/drawable-hdpi/connect_established.png Binary files differnew file mode 100644 index 000000000000..cd8c435ab140 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/connect_established.png diff --git a/packages/SystemUI/res/drawable-hdpi/connect_no.png b/packages/SystemUI/res/drawable-hdpi/connect_no.png Binary files differnew file mode 100644 index 000000000000..ea63cdd589b1 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/connect_no.png diff --git a/packages/SystemUI/res/drawable-mdpi/connect_creating.png b/packages/SystemUI/res/drawable-mdpi/connect_creating.png Binary files differnew file mode 100644 index 000000000000..cb507da3f119 --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/connect_creating.png diff --git a/packages/SystemUI/res/drawable-mdpi/connect_established.png b/packages/SystemUI/res/drawable-mdpi/connect_established.png Binary files differnew file mode 100644 index 000000000000..6c511cbfb01f --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/connect_established.png diff --git a/packages/SystemUI/res/drawable-mdpi/connect_no.png b/packages/SystemUI/res/drawable-mdpi/connect_no.png Binary files differnew file mode 100644 index 000000000000..6f56da11d07c --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/connect_no.png diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 506dd9ac5d15..46845ddd8209 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -32,6 +32,8 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wimax.WimaxManagerConstants; +import android.net.ethernet.EthernetManager; +import android.net.ethernet.EthernetStateTracker; import android.os.Binder; import android.os.Handler; import android.os.Message; @@ -92,6 +94,7 @@ public class NetworkController extends BroadcastReceiver { String mContentDescriptionPhoneSignal; String mContentDescriptionWifi; + String mContentDescriptionEthernet; String mContentDescriptionWimax; String mContentDescriptionCombinedSignal; String mContentDescriptionDataType; @@ -120,6 +123,17 @@ public class NetworkController extends BroadcastReceiver { private int mWimaxSignal = 0; private int mWimaxState = 0; private int mWimaxExtraState = 0; + + // Ethernet + boolean mEthernetEnabled, mEthernetConnected; + int mEthernetIconId = 0; // overlay arrows for wifi direction + int mEthernetActivity = EthernetManager.DATA_ACTIVITY_NONE; + private static final int[] sEthImages = { + R.drawable.connect_established, + R.drawable.connect_no, + R.drawable.connect_creating + }; + // data connectivity (regardless of state, can we access the internet?) // state of inet connection - 0 not connected, 100 connected private int mInetCondition = 0; @@ -213,6 +227,7 @@ public class NetworkController extends BroadcastReceiver { filter.addAction(WifiManager.RSSI_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(EthernetManager.ETHERNET_STATE_CHANGED_ACTION); filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED); filter.addAction(Telephony.Intents.SPN_STRINGS_UPDATED_ACTION); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); @@ -344,6 +359,9 @@ public class NetworkController extends BroadcastReceiver { action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) { updateWimaxState(intent); refreshViews(); + } else if (action.equals(EthernetManager.ETHERNET_STATE_CHANGED_ACTION)) { + updateEth(intent); + refreshViews(); } } @@ -794,6 +812,14 @@ public class NetworkController extends BroadcastReceiver { } } + private void updateEthernetIcons() { + if (mEthernetConnected) { + mEthernetIconId = sEthImages[0]; + } else { + mEthernetIconId = sEthImages[1]; + } + } + private String huntForSsid(WifiInfo info) { String ssid = info.getSSID(); if (ssid != null) { @@ -984,6 +1010,21 @@ public class NetworkController extends BroadcastReceiver { } } + if (mEthernetConnected) { + switch (mEthernetActivity) { + case EthernetStateTracker.EVENT_HW_CONNECTED: + case EthernetStateTracker.EVENT_INTERFACE_CONFIGURATION_SUCCEEDED: + mEthernetIconId = sEthImages[0]; + break; + case EthernetStateTracker.EVENT_HW_DISCONNECTED: + case EthernetStateTracker.EVENT_INTERFACE_CONFIGURATION_FAILED: + mEthernetIconId = sEthImages[1]; + return; + default: + mEthernetIconId = sEthImages[2]; + } + } + if (mBluetoothTethered) { combinedLabel = mContext.getString(R.string.bluetooth_tethered); combinedSignalIconId = mBluetoothTetherIconId; @@ -1205,6 +1246,22 @@ public class NetworkController extends BroadcastReceiver { } } + private final void updateEth(Intent intent) { + final int event = intent.getIntExtra(EthernetManager.EXTRA_ETHERNET_STATE, EthernetManager.ETHERNET_STATE_UNKNOWN); + switch (event) { + case EthernetStateTracker.EVENT_HW_CONNECTED: + case EthernetStateTracker.EVENT_INTERFACE_CONFIGURATION_SUCCEEDED: + mEthernetIconId = sEthImages[0]; + break; + case EthernetStateTracker.EVENT_HW_DISCONNECTED: + case EthernetStateTracker.EVENT_INTERFACE_CONFIGURATION_FAILED: + mEthernetIconId = sEthImages[1]; + return; + default: + mEthernetIconId = sEthImages[2]; + } + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("NetworkController state:"); pw.println(" - telephony ------"); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b7dc4a29d4d7..11ee5a2f0c72 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -53,6 +53,7 @@ import android.net.Proxy; import android.net.ProxyProperties; import android.net.RouteInfo; import android.net.wifi.WifiStateTracker; +import android.net.ethernet.EthernetStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.Binder; import android.os.FileUtils; @@ -413,7 +414,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { n.type); continue; } - if (mRadioAttributes[n.radio] == null) { + if ((n.type != ConnectivityManager.TYPE_ETHERNET) && (mRadioAttributes[n.radio] == null)) { loge("Error in networkAttributes - ignoring attempt to use undefined " + "radio " + n.radio + " in network type " + n.type); continue; @@ -505,7 +506,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } break; case ConnectivityManager.TYPE_ETHERNET: - mNetTrackers[netType] = EthernetDataTracker.getInstance(); + mNetTrackers[netType] = new EthernetStateTracker(netType, mNetConfigs[netType].name); mNetTrackers[netType].startMonitoring(context, mHandler); break; default: diff --git a/services/java/com/android/server/EthernetService.java b/services/java/com/android/server/EthernetService.java new file mode 100644 index 000000000000..5ab66cde1ed5 --- /dev/null +++ b/services/java/com/android/server/EthernetService.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2010 The Android-x86 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. + * + * Author: Yi Sun <beyounn@gmail.com> + */ + +package com.android.server; + +import java.net.UnknownHostException; +import android.net.ethernet.EthernetNative; +import android.net.ethernet.IEthernetManager; +import android.net.ethernet.EthernetManager; +import android.net.ethernet.EthernetStateTracker; +import android.net.ethernet.EthernetDevInfo; +import android.net.ethernet.EthernetStateMachine; +import android.provider.Settings; +import android.util.Slog; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.SystemProperties; + +/** + * EthernetService handles remote Ethernet operation requests by implementing + * the IEthernetManager interface. It also creates a EtherentMonitor to listen + * for Etherent-related events. + * + * @hide + */ +public class EthernetService<syncronized> extends IEthernetManager.Stub { + private static final String TAG = "EthernetService"; + private static final int ETHERNET_HAS_CONFIG = 1; + private static final boolean localLOGV = true; + + private final EthernetStateMachine mEthernetStateMachine; + + private int mEthState= EthernetManager.ETHERNET_STATE_UNKNOWN; + private Context mContext; + private String[] DevName; + private int isEnabled ; + private String mInterfaceName; + + public EthernetService(Context context) { + mContext = context; + mInterfaceName = SystemProperties.get("ethernet.interface", "eth0"); + mEthernetStateMachine = new EthernetStateMachine(mContext, mInterfaceName); + } + + /** + * Check if Wi-Fi needs to be enabled and start + * if needed + * + * This function is used only at boot time + */ + public void checkAndStartEthernet() { + isEnabled = getPersistedState(); + if (localLOGV == true) Slog.i(TAG, "Ethernet dev enabled " + isEnabled); + getDeviceNameList(); + setState(isEnabled); + + mEthernetStateMachine.startMonitoring(mContext); + + } + + + /** + * check if the ethernet service has been configured. + * @return {@code true} if configured {@code false} otherwise + */ + public boolean isConfigured() { + final ContentResolver cr = mContext.getContentResolver(); + return (Settings.Secure.getInt(cr, Settings.Secure.ETHERNET_CONF, 0) == ETHERNET_HAS_CONFIG); + + } + + /** + * Return the saved ethernet configuration + * @return ethernet interface configuration on success, {@code null} on failure + */ + public synchronized EthernetDevInfo getSavedConfig() { + if (!isConfigured()) + return null; + + final ContentResolver cr = mContext.getContentResolver(); + EthernetDevInfo info = new EthernetDevInfo(); + info.setConnectMode(Settings.Secure.getString(cr, Settings.Secure.ETHERNET_MODE)); + info.setIfName(Settings.Secure.getString(cr, Settings.Secure.ETHERNET_IFNAME)); + info.setIpAddress(Settings.Secure.getString(cr, Settings.Secure.ETHERNET_IP)); + info.setDnsAddr(Settings.Secure.getString(cr, Settings.Secure.ETHERNET_DNS)); + info.setNetMask(Settings.Secure.getString(cr, Settings.Secure.ETHERNET_MASK)); + info.setRouteAddr(Settings.Secure.getString(cr, Settings.Secure.ETHERNET_ROUTE)); + + return info; + } + + /** + * Set the ethernet interface configuration mode + * @param mode {@code ETHERNET_CONN_MODE_DHCP} for dhcp {@code ETHERNET_CONN_MODE_MANUAL} for manual configure + */ + public synchronized void setMode(String mode) { + final ContentResolver cr = mContext.getContentResolver(); + if (DevName != null) { + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_IFNAME, DevName[0]); + Settings.Secure.putInt(cr, Settings.Secure.ETHERNET_CONF, 1); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_MODE, mode); + } + } + + /** + * update a ethernet interface information + * @param info the interface infomation + */ + public synchronized void updateDevInfo(EthernetDevInfo info) { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Secure.putInt(cr, Settings.Secure.ETHERNET_CONF, 1); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_IFNAME, info.getIfName()); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_IP, info.getIpAddress()); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_MODE, info.getConnectMode()); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_DNS, info.getDnsAddr()); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_ROUTE, info.getRouteAddr()); + Settings.Secure.putString(cr, Settings.Secure.ETHERNET_MASK, info.getNetMask()); + if (mEthState == EthernetManager.ETHERNET_STATE_ENABLED) { + try { + mEthernetStateMachine.resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong ethernet configuration"); + } + } + } + + /** + * get the number of ethernet interfaces in the system + * @return the number of ethernet interfaces + */ + public int getTotalInterface() { + return EthernetNative.getInterfaceCnt(); + } + + + private int scanDevice() { + int i, j; + if ((i = EthernetNative.getInterfaceCnt()) == 0) + return 0; + + DevName = new String[i]; + + for (j = 0; j < i; j++) { + DevName[j] = EthernetNative.getInterfaceName(j); + if (DevName[j] == null) + break; + if (localLOGV) Slog.v(TAG, "device " + j + " name " + DevName[j]); + } + + return i; + } + + /** + * get all the ethernet device names + * @return interface name list on success, {@code null} on failure + */ + public String[] getDeviceNameList() { + return (scanDevice() > 0) ? DevName : null; + } + + private int getPersistedState() { + final ContentResolver cr = mContext.getContentResolver(); + try { + return Settings.Secure.getInt(cr, Settings.Secure.ETHERNET_ON); + } catch (Settings.SettingNotFoundException e) { + return EthernetManager.ETHERNET_STATE_UNKNOWN; + } + } + + private synchronized void persistEnabled(boolean enabled) { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Secure.putInt(cr, Settings.Secure.ETHERNET_ON, enabled ? EthernetManager.ETHERNET_STATE_ENABLED : EthernetManager.ETHERNET_STATE_DISABLED); + } + + /** + * Enable or Disable a ethernet service + * @param enable {@code true} to enable, {@code false} to disable + */ + public synchronized void setState(int state) { + + if (mEthState != state) { + mEthState = state; + if (state == EthernetManager.ETHERNET_STATE_DISABLED) { + Slog.e(TAG, "EthernetManager.ETHERNET_STATE_DISABLED"); + persistEnabled(false); + mEthernetStateMachine.stopInterface(false); + } else { + Slog.e(TAG, "EthernetManager.ETHERNET_STATE_ENABLED"); + persistEnabled(true); + if (!isConfigured()) { + // If user did not configure any interfaces yet, pick the first one + // and enable it. + setMode(EthernetDevInfo.ETHERNET_CONN_MODE_DHCP); + } + try { + mEthernetStateMachine.resetInterface(); + } catch (UnknownHostException e) { + Slog.e(TAG, "Wrong ethernet configuration"); + } + } + } + } + + public void reconnect() { + mEthernetStateMachine.reconnectCommand(); + } + + /** + * Get ethernet service state + * @return the state of the ethernet service + */ + public int getState( ) { + return mEthState; + } + + + public void startEthernet() { + } + + public void stopEthernet() { + } + +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3ae62add369f..c82f6c1a7a4f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -28,6 +28,8 @@ import android.content.pm.IPackageManager; import android.content.res.Configuration; import android.media.AudioService; import android.net.wifi.p2p.WifiP2pService; +import android.net.ethernet.EthernetManager; +import android.net.ethernet.EthernetStateTracker; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; @@ -119,6 +121,7 @@ class ServerThread extends Thread { ConnectivityService connectivity = null; WifiP2pService wifiP2p = null; WifiService wifi = null; + EthernetService ethernet = null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; @@ -374,6 +377,14 @@ class ServerThread extends Thread { reportWtf("starting Wi-Fi Service", e); } + try { + Slog.i(TAG, "Ethernet Service"); + ethernet = new EthernetService(context); + ServiceManager.addService(Context.ETHERNET_SERVICE, ethernet); + } catch (Throwable e) { + reportWtf("starting Ethernt Service", e); + } + try { Slog.i(TAG, "Connectivity Service"); connectivity = new ConnectivityService( @@ -383,6 +394,7 @@ class ServerThread extends Thread { networkPolicy.bindConnectivityManager(connectivity); wifi.checkAndStartWifi(); wifiP2p.connectivityServiceReady(); + ethernet.checkAndStartEthernet(); } catch (Throwable e) { reportWtf("starting Connectivity Service", e); } |