android localsocket 实现app与linux通讯,Android : App通过LocalSocket 与 HAL间通信

LocalSocket其通信方式与Socket差不多,只是LocalSocket没有跨越网络边界。对于*nix系统来说,“一切皆为文件”,Socket也不例外,Socket按照收发双方的媒介来说有三种类型:

1,通过网络端口:即通过本地回环接口(即LoopBack)127.0.0.1来收发数据;

2,通过文件系统: 通过文件作为收发数据的中转站;

3,通过内存映射文件:在内存中开辟一块区域作为收发数据的中转站,此区域仍然使用文件读写API进行访问;

LocalSocket支持方式2和方式3。

以下通过HAL层(c)作为server,App端(java)作为client,进行LocalSocket通信演示(核心部分代码):

C代码:

J_U8* sName="nano_server_socket";

J_Int server_sockfd, client_sockfd;

J_Int server_len, client_len;

J_Int reuse= 1;

J_Int err;struct sockaddr_un server_address; /*声明一个UNIX域套接字结构*/

structsockaddr_un client_address;

unlink (sName);/*删除原有server_socket对象*/

/*创建 socket, 通信协议为AF_LOCAL, SOCK_STREAM 数据方式*/server_sockfd= socket(AF_LOCAL, SOCK_STREAM, 0);if(server_sockfd < 0){

ALOGE("server_sockfd error : %s\n",strerror(errno));return;

}/*配置服务器信息(socket对象路径)*/

//Check with length +1 for the *initial* '\0'.

if ((strlen(sName) + 1) > sizeof(server_address.sun_path)) {

ALOGE("name too long\n");gotoEXIT;

}/** Note: The path in this case is *not* supposed to be

* '\0'-terminated. ("man 7 unix" for the gory details.)*/server_address.sun_path[0] = 0;

memcpy(server_address.sun_path+ 1, sName, strlen(sName));/*配置服务器信息(通信协议)*/server_address.sun_family=AF_LOCAL;/*默认设置resue FLAG*/

if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {

ALOGE("reuse error\n");gotoEXIT;

}/*配置服务器信息(服务器地址长度)*/client_len= server_len = strlen(sName) + offsetof(struct sockaddr_un, sun_path) + 1;/*绑定 socket 对象*/bind (server_sockfd, (struct sockaddr *)&server_address, server_len);/*监听网络,队列数为1*/

if(listen(server_sockfd,1)<0){

ALOGE("listen error : %s\n",strerror(errno));gotoEXIT;

}

/*接受客户端请求; 第2个参数用来存储客户端地址; 第3个参数用来存储客户端地址的大小*/

/*建立(返回)一个到客户端的文件描述符,用以对客户端的读写操作*/client_sockfd =accept (server_sockfd, (struct sockaddr *)&client_address, (socklen_t *)&client_len);

if (client_sockfd == -1) {

ALOGE("accept error : %s\n",strerror(errno)); gotoEXIT; } else if (client_sockfd>FD_SETSIZE){ ALOGE("accept reach max\n"); close(client_sockfd); gotoEXIT; }

/*start read loop*/

while(1) {

char buf[1024]={0};

ssize_t res=read(client_socketfd,buf,sizeof(buf));

ALOGD("server get data : %s", buf);

if(res <=0){

if(errno == EAGAIN)

continue;

ALOGE("errno %s\n",strerror(errno));

close(client_socketfd);

return;

}

}

EXIT:

close(server_sockfd);

HAL层可具体参考Android源码的system\bt\osi\src\socket_utils\ 目录下的 socket_local_client.cc 和 socket_local_server.cc 代码(Android 8.0),

直接调用如下封装好的接口即可:

/***********/

/***服务端***/

/**********/

/*(1)创建server socket接收client端数据*/server_sockfd= osi_socket_local_server("server_socket",ANDROID_SOCKET_NAMESPACE_ABSTRACT,SOCK_STREAM);/*(2)等待client端连接*/client_sockfd= accept (server_sockfd, NULL, NULL);/*(3)数据读取线程*/

while(1){

ssize_t res=read(client_sockfd ,buf,sizeof(buf));

}/***********/

/***客户端***/

/**********/

/*(1)创建client socket*/client_sockfd= osi_socket_local_client("client_socket",ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);/*(2)发送数据到server端*/write(client_sockfd,"hello", strlen("hello"));

JAVA代码:

packagecom.example.administrator.localsocket;importandroid.net.LocalServerSocket;importandroid.net.LocalSocket;importandroid.net.LocalSocketAddress;importandroid.os.Bundle;importandroid.os.RemoteException;importandroid.support.design.widget.FloatingActionButton;importandroid.support.design.widget.Snackbar;importandroid.support.v7.app.AppCompatActivity;importandroid.support.v7.widget.Toolbar;importandroid.util.Log;importandroid.view.View;importandroid.view.Menu;importandroid.view.MenuItem;importandroid.widget.Toast;importjava.io.IOException;import staticandroid.widget.Toast.LENGTH_SHORT;public class MainActivity extendsAppCompatActivity {private static final String SOCKET_ADDRESS = "nano_server_socket"; //和HAL层统一地址名称LocalSocket client_socket= null;

LocalSocketAddress addr;

@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

client_socket = newLocalSocket(); //创建socket对象

addr= newLocalSocketAddress(SOCKET_ADDRESS,LocalSocketAddress.Namespace.ABSTRACT); //使用虚空间地址try{

client_socket.connect(addr);  //请求连接

}catch(IOException e) {

e.printStackTrace();

}findViewById(R.id.sendMsg).setOnClickListener(newView.OnClickListener() {

@Overridepublic voidonClick(View v) {try{//发送数据

String data="hello";

client_socket.getOutputStream().write(data.getBytes());

}catch(IOException e) {

e.printStackTrace();

}

}

});}

@Overrideprotected voidonStop() {super.onStop();try{

client_socket.close();

}catch(IOException e) {

e.printStackTrace();

}

}}

注:Android8.0版本验证app端要用LocalSocket,需要两个条件:

2.需要给platform_app增加selinux权限,修改xxx\sepolicy\platform_app.te,添加如下两条规则:

typeattribute platform_app mlstrustedsubject;

allow platform_app audioserver:unix_stream_socket connectto;

测试结果:

a5842847d898afe0e8f1dc7ec588b7a0.png

你可能感兴趣的:(android,localsocket,实现app与linux通讯)