Netd和framework层的通信,主要解释socket

xiaoxiao2021-02-28  106

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的接口。
转载请注明原文地址: https://www.6miu.com/read-22780.html

最新回复(0)