网上LocalSocket的知识可以搜到你读不完,所以它的知识本文就不介绍了。本文着重的是自己在实际使用中遇到的问题。
虽然早就经过各种代码洗礼,但是对于LocalSocket这方面还是第一次用到。但是咱不怕,发挥程序猿顶着油锅也要上的精神。巴拉巴拉把LocalSocket的基本知识过了一边。
看了看在Android中怎么用的,以及代码怎么写的。
还是先说一下背景吧,否则会凌乱哈。
本人需要在native层的sdcard应用中增加一个通信机制,可以接收到framework层传来的消息。经过一番讨论,决定使用LocalSocket。Android中有好多例子,咱不怕。
于是就开搞,我去看别的应用使用的地方是怎么办的。
以vold为例
(1)增加系统socket资源
service vold /system/bin/vold \ --blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \ --fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0 class core socket vold stream 0660 root mount socket cryptd stream 0660 root mount
上述代码在vold.rc文件中。在vold启动的时候呢,创建了两个socket资源vold和cryptd。它们可以在vold进程中使用,因为它们关联到一起了。
(2)native层服务端
通常在服务端会有如下类似代码,SOCKET_PATH就是一个字符串,可以是vold啊,或者cryptd
{
//获取已绑定socket
lsocket = android_get_control_socket(SOCKET_PATH);
listen(lsocket, 5);
//等待客户端建立连接
s = accept(lsocket, &addr, &alen);
for (;;) {
//接收数据 相当于recv
readx(s, buf, count);
execute(s, buf);
}
close(s);
}
}
(3)framework层客户端
通常客户端有如下代码
{
//创建socket
mSocket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress("vold",
LocalSocketAddress.Namespace.RESERVED);
mSocket.connect(address);
mIn = mSocket.getInputStream();
mOut = mSocket.getOutputStream();
}
其实看完上面,如果大家有实际需要的话,问题也就来了:这个应用要不是从*.rc文件中启动的怎么办呢,如何创建socket资源文件与之绑定,从而可以在代码中使用呢。
巧了,还真有,我遇到的这个问题就是。sdcard是通过vold应用在代码中启动的。
好,下面就来港货了(不一定比陆获好)。
int lsocket = socket_local_server("sdcard", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM | SOCK_CLOEXEC);
// Linux "abstract" (non-filesystem) namespace
#define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0
// Android "reserved" (/dev/socket) namespace
#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
// Normal filesystem namespace
#define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2
这里一定要用ANDROID_SOCKET_NAMESPACE_ABSTRACT,是重点啊,要划,。其实socket_local_server这个函数也很牛逼,它创建了socket之后还绑定了,连接了。
{
int err;
int s;
s = socket(AF_LOCAL, type, 0);
if (s < 0) return -1;
close(s);
return -1;
}
int ret;
close(s);
return -1;
}
}
}
其实这样就创建成功了。
然后客户端这么使用就行了。
private static boolean openCryptSocket() { try { mSocket = new LocalSocket(LocalSocket.SOCKET_STREAM); LocalSocketAddress address = new LocalSocketAddress("sdcard", LocalSocketAddress.Namespace.ABSTRACT); mSocket.connect(address); mOutputStream = mSocket.getOutputStream(); } catch (IOException ex) { Slog.w(TAG, "encrypt daemon socket open failed"); mSocket = null; return false; } return true; }
上面把问题解决了。但是一般实际应用中你还会遇到权限问题。所以要遭sdcardd.te中添加allow sdcardd vold:unix_stream_socket {connectto read write};这个是是要sdcard这个应用有对socket流的读写连接权限。我是在framework的也给服务中添加上述客户端代码的。所以还要在system_server.te文件中添加allow system_server sdcardd:unix_stream_socket {connectto read write};这句话。
好了权限问题也ok了。