前言:介绍一种使用socket通信的方法可以使native和framework自由通信
在Android系统中,java代码和本地代码(c/c++)直接的通信一般是使用jni接口,但是这种方法一般适用于framework层调用native层的代码,但本地代码层(native)又如何把消息传递给上层呢?我们可以借鉴Android中的GSP模块的实现方式来实现native到framework的消息传递,但是比较麻烦。所以我们在这里再介绍另一种方式: socket.
1 基础:
Android是基于linux的系统,系统底层机制基本上是相同的,因为分本地代码和java代码,并且是java代码通过jni调用本地代码执行,所以我们可以把本地代码的执行看成是服务器端的执行,framework端的代码看成是客户端代码。
Tcp通信基本流程:
服务器端 客户端
1.创建socket 1.创建socket
2.bind()
3.listen()
4.accecp()
----等待客户端连接---- 2.connect()
5.读数据(recv) 3.写数据(send)
6.写数据(send) 4.读数据(recv)
7.关闭socket(closesocket()) 5.关闭socket(closesocket())
ref:
http://www.cnblogs.com/bastard/archive/2012/10/09/2717052.html
2 实践:
2.1 Java层的主要代码:
LocalSocket so = null;
LocalSocketAddress addr;
so = new LocalSocket();
addr = new LocalSocketAddress(<span style="color:#cc33cc;">SOCKET_NAME</span>, LocalSocketAddress.Namespace.RESERVED);
so.connect(addr);
如果能正常connect到addr,那就可以像一般文件操作那样进行io读写了。
2.2 native层的主要代码:
cli_fd = android_get_control_socket(<span style="color:#993399;">SOCKET_NAME</span>);
retval = listen(cli_fd, backlog);
cli_fd_cmd = accept(cli_fd, (sockaddr *)&peeraddr, &socklen);
2.2.1 SOCKET_NAME的定义:
是android 一个字符串常量,在init.rc中定义,
2.2.2 增加socket资源
即我们可以通过修改init.rc来改变socket
在android系统源代码目录树里面,有"android/system/core/rootdir/init.rc",
work01@ubuntu:~/hi3716cv200/system/core/rootdir$ ls
Android.mk init.environ.rc.in init.trace.rc ueventd.rc
etc init.rc init.usb.rc
或者 android_install_folder/out/target/product/xxxx/root
详细: ref:
http://blog.csdn.net/yellow_hill/article/details/39548165
首先
添加一个服务(service),然后,在service下添加一个option 这里就是socket
取名为vdsocketservice_01的 servcie,同时加一个同名的类型为stream的socket,
service vdsocketservice_01 /system/bin/vdsocketservice_01
socket vdsocketservice_01 stream 666
oneshot
在启动vdsocketservice_01 服务时,就会为vdsocketservice_01 分配socket文件系统资源:dev/socket/vdsocketservice_01
vdsocketservice_01 服务的Socket资源和名称vdsocketservice_01 绑定起来。
这些都是在开机初始化化init进程中启动service时完成:
init进程会根据“socket”这个类型从而调用publish_socket(),
service_start create_socket publish_socket
2.2.3 构建编译框架:
static int s_fdListen = -1;
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
if (s_fdListen < 0) {
RLOGE("Failed to get socket '" SOCKET_NAME_RIL "'");
exit(-1);
}
ret = listen(s_fdListen, 4);
if (ret < 0) {
RLOGE("Failed to listen on control socket '%d': %s",
s_fdListen, strerror(errno));
exit(-1);
}
#include <cutils/sockets.h>
int main(const int argc, const char *argv[])
{
//获取已绑定socket
lsocket = android_get_control_socket(SOCKET_PATH);
//监听socket
listen(lsocket, 5);
for (;;) {
//等待客户端建立连接
s = accept(lsocket, &addr, &alen);
for (;;) {
//接收数据 相当于recv
readx(s, buf, count);
//执行相关的操作
execute(s, buf);
}
//关闭socket
close(s);
}
}
/system/bin/vdsocketservice_01就是我们自己的native服务器,在里面我们调用
- cli_fd = android_get_control_socket("server");
- retval = listen(cli_fd, backlog);
- cli_fd_cmd = accept(cli_fd, (sockaddr *)&peeraddr, &socklen);
Java那边只需要使用普通socket API就可以和native服务器通信,但需要注意SOCKET_NAME的值必须和init.rc中的一致,我们这里的SOCKET_NAME为"server",如何编写init.rc请参考android/system/init/readme.txt.
ref:
http://blog.sina.com.cn/s/blog_82f2fc280101395m.html
附录:
1 android init language: 参照andorid的目录下自带的帮助文件 /system/core/init/readme.txt
Android Init Language
---------------------
The Android Init Language consists of four broad classes of statements,
which are Actions, Commands, Services, and Options.
服务:
Services
--------
Services are programs which init launches and (optionally) restarts
when they exit. Services take the form of:
service <name> <pathname> [ <argument> ]*
<option>
<option>
...
socket 作为option的一种,这里看看帮助文件里面socket的举例:
socket <name> <type> <perm> [ <user> [ <group> ] ]
Create a unix domain socket named /dev/socket/<name> and pass
its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
User and group default to 0.
Example init.conf
on boot
export PATH /sbin:/system/sbin:/system/bin
export LD_LIBRARY_PATH /system/lib
mkdir /dev
mkdir /proc
mkdir /sys
mount tmpfs tmpfs /dev
mkdir /dev/pts
<span style="background-color: rgb(51, 255, 51);"> mkdir /dev/socket</span>
mount devpts devpts /dev/pts
....
service usbd /system/bin/usbd -r
user usbd
group usbd
socket usbd 666
ref: 中文介绍
http://blog.csdn.net/yimiyangguang1314/article/details/6268177
2 socket stream的介绍:
Stream | Supports reliable, two-way, connection-based byte streams without the duplication of data and without preservation of boundaries. ASocket of this type communicates with a single peer and requires a remote host connection before communication can begin. Stream uses the Transmission Control Protocol (Tcp) ProtocolType and the InterNetwork AddressFamily. |
SOCK_STREAM提供面向连接的稳定数据传输,即TCP协议。SOCK_STREAM应用在C语言socket编程中,在进行网络连接前,需要用socket函数向系统申请一个通信端口。socket函数的使用方法如下
ref:
http://baike.baidu.com/view/4785427.htm
http://msdn.microsoft.com/en-us/library/system.net.sockets.sockettype(v=vs.110).aspx
3 ril 的源码和框架结构
http://en.pudn.com/downloads162/sourcecode/comm/modem/detail736165_en.html
ref:
http://calvinlee.github.io/blog/2012/04/26/android-init-socket/
本帖原创,请务必注明转载地址,谢谢!!!