1. 背景
最近在做一個需求,需要native守護(hù)進(jìn)程需要跟app進(jìn)行通訊畜挨,App作為服務(wù)端蝌蹂,而native程序作為客戶端,正常app與app之前通信都是通過binder方式通信,但基于此背景临扮,肯定不合適论矾,故首選應(yīng)該通過socket方式
2. 編碼
2.1 方案選型
采用Java LocalServerSocket/LocalSocket進(jìn)行通訊,目前framework層APP僅支持LocalSocketAddress.Namespace.ABSTRACT杆勇,也是LocalServerSocket默認(rèn)的類型贪壳,傳入一個名稱即可。LocalSocketAddress.Namespace.RESERVED這個只允許是init創(chuàng)建的類型蚜退,也可以選擇LocalSocketAddress.Namespace.FILESYSTEM類型闰靴,但是沒有公開,是不是也可以用呢钻注,故想挑戰(zhàn)下自己
2.2 編寫代碼
具體查看LocalSocketAddress類無法直接設(shè)置FILESYSTEM類型的LocalSocketAddress蚂且,只能傳入name或者一個文件描述符,fd從哪里來幅恋,選擇從jni直接創(chuàng)建socket杏死,返回fd,然后反射設(shè)置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的時候報權(quán)限錯誤淑翼,就開始排查,最終定位/system/core/libcutils/socket_local_client_unix.c中的函數(shù)int socket_make_sockaddr_un(const char *name, int namespaceId, struct sockaddr_un *p_addr, socklen_t *alen)品追,這里的默認(rèn)sun_family為AF_LOCAL類型窒舟,修改之后bind正常
2.3.2 坑二
偶爾能bind成功,但是很多時候是地址已綁定錯誤诵盼,最終不創(chuàng)建UDSpath對應(yīng)的文件修復(fù)