除了android_net_netutils.cpp 外 还有一个JNI : android_net_ethernet.cpp
1. frameworks/base/ethernet/java/android/net/ethernet/EthernetNative.java 代码会调用这个JNI
package android.net.ethernet;
/**
* Native calls for sending requests to the kernel,
* {@hide}
*/
public class EthernetNative {
public native static String getInterfaceName(int i); //get eth0, sit0
public native static int getInterfaceCnt(); //
public native static int initEthernetNative();
public native static String waitForEvent();
}
2. JNINativeMethod gEthernetMethods[]:
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}
};
3. AndroidRuntime 运行时,会注册 这个NativeMethod:
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");
}
//注册gEthernetMethods[]
return AndroidRuntime::registerNativeMethods(env,
ETH_PKG_NAME,
gEthernetMethods,
NELEM(gEthernetMethods));
}
4. waitForEvent():
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);
}
5. initEthernetNative():
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; }
6. getInterfaceName() 和 getInterfaceCnt():
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; }