Netd和framework层的通信,主要解释socket
来源:互联网 发布:epoll 高性能网络库 编辑:程序博客网 时间:2024/06/10 09:29
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的接口。
- Netd和framework层的通信,主要解释socket
- Netd和framework层的通信,主要解释socket
- Android netd和Framework以及netd和kernel之间的通信
- wpa_supplicant和framework、netd的接口调用总结
- android netd和kernel&frameworks的通信逻辑
- socket通信中select函数的使用和解释
- socket通信中select函数的使用和解释
- socket通信中select函数的使用和解释
- Android原生库和架构层通信的socket
- socket通信 端口状态的解释
- android使用socket使底层和framework通信
- android使用socket使底层和framework通信
- android使用socket使底层和framework通信
- Android使用socket使底层和framework通信
- android使用socket使底层和framework通信
- android 中使用socket使native和framework通信
- android 中使用socket使native和framework通信
- android使用socket使底层和framework通信
- vs2012布局问题
- jquery.bgiframe
- 【android】计算手机内存空间
- FTP工具类
- Android 去标题问题
- Netd和framework层的通信,主要解释socket
- 从K近邻算法、距离度量谈到KD树、SIFT+BBF算法
- 【为什么Win7分区越多越糟】
- 2013年9月30号 UFLDL tutorial之BP算法
- Linux下查看编译参数(不断补充中)
- jquery.masonry.js
- CWND * 与 HWND 转换
- SYN Cookie原理及其在Linux内核中的实现
- C#比较两个日期的大小