Netd和framework层的通信
这两者的通信时通过unix domain socket来完成的。
系统初始化的时候会从init.rc里面读取并创建socket,名字叫netd
service netd /system/bin/netd
class main
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
1. 先来看一下socket的创建过程
手机开机的时候执行init.c的main函数
int main(int argc, char **argv)
{
………
restorecon("/dev");
restorecon("/dev/socket");//创建的socket文件在这个目录下
……...
init_parse_config_file("/init.rc");
………
}
init_parse_config_file调用init_parse.c的parse_config函数里处理init.rc的数据。
Socket的处理是在parse_line_service里面,保存socketinfo到一个链表里面
static void parse_line_service(struct parse_state *state, int nargs, char **args)
{
case K_socket: {/* name type perm [ uid gid ] */
struct socketinfo *si;
if (nargs < 4) {
parse_error(state, "socket option requires name, type, perm arguments\n");
break;
}
if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")
&& strcmp(args[2],"seqpacket")) {
parse_error(state, "socket type must be 'dgram', 'stream' or 'seqpacket'\n");
break;
}
si = calloc(1, sizeof(*si));
if (!si) {
parse_error(state, "out of memory\n");
break;
}
si->name = args[1];
si->type = args[2];
si->perm = strtoul(args[3], 0, 8);
if (nargs > 4)
si->uid = decode_uid(args[4]);//userID
if (nargs > 5)
si->gid = decode_uid(args[5]);//groupID
si->next = svc->sockets;
svc->sockets = si;
break;
}
Socket真正的创建过程是在启动service的时候,即调用函数service_start的时候
void service_start(struct service *svc, const char *dynamic_args)
{
……….
for (si = svc->sockets; si; si = si->next) {
int socket_type = (!strcmp(si->type, "stream") ? SOCK_STREAM : (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid);
if (s >= 0) {
publish_socket(si->name, s);
}
}
…………
}
这里做了两个操作,create_socket是创建socket,push_socket是把socket和socketname存储到一个数组里面。
Create_socket
/*
* create_socket - creates a Unix domain socket in ANDROID_SOCKET_DIR
* ("/dev/socket") as dictated in init.rc. This socket is inherited by the
* daemon. We communicate the file descriptor's value via the environment
* variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
*/
int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
{
struct sockaddr_un addr;
int fd, ret;
#ifdef HAVE_SELINUX
char *secon;
#endif
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
return -1;
}
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
//这里的sun_path就是socket的文件路径
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",name);
ret = unlink(addr.sun_path);
if (ret != 0 && errno != ENOENT) {
ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
goto out_close;
}
#ifdef HAVE_SELINUX
secon = NULL;
if (sehandle) {
ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
if (ret == 0)
setfscreatecon(secon);
}
#endif
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
if (ret) {
ERROR("Failed to bind socket '%s': %s\n", name, strerror(errno));
goto out_unlink;
}
#ifdef HAVE_SELINUX
setfscreatecon(NULL);
freecon(secon);
#endif
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
addr.sun_path, perm, uid, gid);
return fd;
out_unlink:
unlink(addr.sun_path);
out_close:
close(fd);
return -1;
}
Publish_socket
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
char val[64];
strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
name,
sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
snprintf(val, sizeof(val), "%d", fd);
add_environment(key, val);
/* make sure we don't close-on-exec */
fcntl(fd, F_SETFD, 0);
}
这里的fd就是刚才新建socket的fd,name是在parse_line_service设置的name,即netd。最后调用add_environment(key, val)以key=value的字符串形式存储到数组ENV里面。
在service_start函数的最后
execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
这里把env当做环境变量集传了进去
2. Netd里面获取socket
先看Netd里面CommandListener的构造函数,这个类是继承自FrameworkListener,从名字就可以看出来是跟framework打交道的
CommandListener::CommandListener() :
FrameworkListener("netd", true) {
………………
}
再看FrmameworkListener对应的构造函数
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
init(socketName, withSeq);
}
SocketListener的构造函数
SocketListener::SocketListener(const char *socketName, bool listen, bool useCmdNum) {
init(socketName, -1, listen, useCmdNum);
}
void SocketListener::init(const char *socketName, int socketFd, bool listen, bool useCmdNum) {
mListen = listen;
mSocketName = socketName;
mSock = socketFd;
mUseCmdNum = useCmdNum;
pthread_mutex_init(&mClientsLock, NULL);
mClients = new SocketClientCollection();
}
下面在startListener里面获取socket的fd
int SocketListener::startListener() {
if (!mSocketName && mSock == -1) {
SLOGE("Failed to start unbound listener");
errno = EINVAL;
return -1;
} else if (mSocketName) {
if ((mSock = android_get_control_socket(mSocketName)) < 0) {
return -1;
}
SLOGV("got mSock = %d for %s", mSock, mSocketName);
}
if (mListen && listen(mSock, 4) < 0) {
SLOGE("Unable to listen on socket (%s)", strerror(errno));
return -1;
} else if (!mListen)
mClients->push_back(new SocketClient(mSock, false, mUseCmdNum));
if (pipe(mCtrlPipe)) {
SLOGE("pipe failed (%s)", strerror(errno));
return -1;
}
if (pthread_create(&mThread, NULL, SocketListener::threadStart, this)) {
SLOGE("pthread_create (%s)", strerror(errno));
return -1;
}
return 0;
}
android_get_control_socket去找到name对应的fd static inline int android_get_control_socket(const char *name) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; const char *val; int fd; /* build our environment variable, counting cycles like a wolf ... */ #if HAVE_STRLCPY strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); #else //包装成init里面设置的key,价格前缀,变成ANDROID_SOCKET_netd strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); key[sizeof(key)-1] = '\0'; #endif val = getenv(key);//从环境变量里面获取key对应的value if (!val) return -1; errno = 0; fd = strtol(val, NULL, 10); if (errno) return -1; return fd; } 现在netd作为一个socket的server以及开始listen了。 3. Framework部分 从NetworkManagermentService开始 private NetworkManagementService(Context context) { mContext = context; mConnector = new NativeDaemonConnector( new NetdCallbackReceiver(), "netd", 10, NETD_TAG, 160); mThread = new Thread(mConnector, NETD_TAG); // Add ourself to the Watchdog monitors. Watchdog.getInstance().addMonitor(this); } 这里初始化一个NativeDaemonConnector来和netd通信,NativeDaemonConnector在listenToSocket函数里面会connect到netd的socket private void listenToSocket() throws IOException { socket = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); socket.connect(address); …….. } 重点是connect函数 LocalSocket.java public void connect(LocalSocketAddress endpoint) throws IOException { synchronized (this) { if (isConnected) { throw new IOException("already connected"); } implCreateIfNeeded();//新建一个local socket if needed impl.connect(endpoint, 0); isConnected = true; isBound = true; } } 调用的是LocalSocketImpl的connect函数 protected void connect(LocalSocketAddress address, int timeout) throws IOException { connectLocal(fd, address.getName(), address.getNamespace().getId()); } connectLocal是个JNI方法,在android_net_LocalSocketImpl.cpp里面定义,对应socket_connect_local static void socket_connect_local(JNIEnv *env, jobject object, jobject fileDescriptor, jstring name, jint namespaceId) { int ret; const char *nameUtf8; int fd; nameUtf8 = env->GetStringUTFChars(name, NULL); fd = jniGetFDFromFileDescriptor(env, fileDescriptor); ret = socket_local_client_connect(fd,nameUtf8,namespaceId,SOCK_STREAM); env->ReleaseStringUTFChars(name, nameUtf8); if (ret < 0) { jniThrowIOException(env, errno); return; } } socket_local_client_connect在system/core/libcutils/socket_local_client.c int socket_local_client_connect(int fd, const char *name, int namespaceId, int type) { struct sockaddr_un addr; socklen_t alen; size_t namelen; int err; //Namespace=RESERVED=1 err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen); if(connect(fd, (struct sockaddr *) &addr, alen) < 0) { goto error; } return fd; error: return -1; } socket_make_sockaddr_un函数 int socket_make_sockaddr_un(const char *name, int namespaceId, struct sockaddr_un *p_addr, socklen_t *alen) memset (p_addr, 0, sizeof (*p_addr)); size_t namelen; switch (namespaceId) { case ANDROID_SOCKET_NAMESPACE_RESERVED: namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX); /* unix_path_max appears to be missing on linux */ if (namelen > sizeof(*p_addr) - offsetof(struct sockaddr_un, sun_path) - 1) { goto error; } //结果是dev/socket/netd即socket文件的路径代替网络socket的地址 strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX); strcat(p_addr->sun_path, name); break; p_addr->sun_family = AF_LOCAL; *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; return 0; 现在Framework这边已经连上了netd的socket,两者就可以开始通信了。 Framework层还有一个LocalSocket作为server的接口。