Android应用跨进程通信-Unix domain socke
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对应的文件修复