美文网首页
Android应用跨进程通信-Unix domain socke

Android应用跨进程通信-Unix domain socke

作者: 学海摆渡人 | 来源:发表于2022-10-24 23:51 被阅读0次

    1. 背景

    最近在做一个需求,需要native守护进程需要跟app进行通讯,App作为服务端,而native程序作为客户端,正常app与app之前通信都是通过binder方式通信,但基于此背景,肯定不合适,故首选应该通过socket方式

    2. 编码

    2.1 方案选型

    采用Java LocalServerSocket/LocalSocket进行通讯,目前framework层APP仅支持LocalSocketAddress.Namespace.ABSTRACT,也是LocalServerSocket默认的类型,传入一个名称即可。LocalSocketAddress.Namespace.RESERVED这个只允许是init创建的类型,也可以选择LocalSocketAddress.Namespace.FILESYSTEM类型,但是没有公开,是不是也可以用呢,故想挑战下自己

    2.2 编写代码

    具体查看LocalSocketAddress类无法直接设置FILESYSTEM类型的LocalSocketAddress,只能传入name或者一个文件描述符,fd从哪里来,选择从jni直接创建socket,返回fd,然后反射设置fd初始化FileDescriptor

    #define UDS_PATH "/data/system/rms_socket"
    
    int native_get_sock_fd(JNIEnv *env) {
        struct sockaddr_un server_socket;
        int sock = 0;
        pthread_t thread;
        int opt = 1;
    
        //socket
        sock = socket(AF_UNIX, SOCK_STREAM, 0);
        if (sock < 0) {
            return -1;
        }
    
        //setopt reuse
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
        //set address
        memset(&server_socket, 0, sizeof(server_socket));
        server_socket.sun_family = AF_LOCAL;
        strcpy(server_socket.sun_path, UDS_PATH);
        socklen_t
        socklen = strlen(UDS_PATH) + offsetof(
        struct sockaddr_un, sun_path);
    
        //bind
        if (bind(sock, (struct sockaddr *) &server_socket, socklen) < 0) {
            close(sock);
            return -1;
        }
        return sock;
    }
    

    java代码部分

            FileDescriptor fileDescriptor = new FileDescriptor();
            int native_fd = NativeSock.get_sock_fd();
    
            Utils.logDebug(TAG, "init native_fd : " + native_fd);
            if (native_fd == -1) {
                return;
            }
            
            try {
                @SuppressLint("DiscouragedPrivateApi")
                Method method = fileDescriptor.getClass().getDeclaredMethod("setInt$", int.class);
                method.setAccessible(true);
                method.invoke(fileDescriptor, native_fd);
            } catch (Exception e) {
                e.printStackTrace();
                Utils.logError(TAG, "init", e);
                return;
            }
    
            try {
                mServerSocket = new LocalServerSocket(fileDescriptor);
            } catch (IOException e) {
                return;
            }
    

    2.3 填坑

    2.3.1 坑一

    刚刚c++代码server_socket.sun_family = AF_LOCAL; 写的是AF_UNIX类型,一直bind的时候报权限错误,就开始排查,最终定位/system/core/libcutils/socket_local_client_unix.c中的函数int socket_make_sockaddr_un(const char *name, int namespaceId, struct sockaddr_un *p_addr, socklen_t *alen),这里的默认sun_family为AF_LOCAL类型,修改之后bind正常

    2.3.2 坑二

    偶尔能bind成功,但是很多时候是地址已绑定错误,最终不创建UDSpath对应的文件修复

    相关文章

      网友评论

          本文标题:Android应用跨进程通信-Unix domain socke

          本文链接:https://www.haomeiwen.com/subject/tctnzrtx.html