Android localsocket 的基础和使用实践: 01

前言:介绍一种使用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资源

定义一个自己的服务,并命名为自己的 SOCKET_NAME                                          [参照: 附录 android init language: 详细设置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 构建编译框架:

我们可以参考android里面的例子,
在your_android_folder/hardware/ril/libril/ril.cpp
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);
    }


一个运用的例子如下:
android_get_control_socket 定义在如下文件
#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服务器,在里面我们调用


  1. cli_fd = android_get_control_socket("server");
  2. retval = listen(cli_fd, backlog);
  3. 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/


本帖原创,请务必注明转载地址,谢谢!!!



你可能感兴趣的:(Android localsocket 的基础和使用实践: 01)