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 = ;
J_Int err;
struct sockaddr_un server_address; /*声明一个UNIX域套接字结构*/
struct sockaddr_un client_address; unlink (sName); /*删除原有server_socket对象*/ /*创建 socket, 通信协议为AF_LOCAL, SOCK_STREAM 数据方式*/
server_sockfd = socket(AF_LOCAL, SOCK_STREAM, );
if(server_sockfd < ){
ALOGE("server_sockfd error : %s\n",strerror(errno));
return;
} /*配置服务器信息(socket对象路径)*/
// Check with length +1 for the *initial* '\0'.
if ((strlen(sName) + ) > sizeof(server_address.sun_path)) {
ALOGE("name too long\n");
goto EXIT;
} /*
* Note: The path in this case is *not* supposed to be
* '\0'-terminated. ("man 7 unix" for the gory details.)
*/
server_address.sun_path[] = ;
memcpy(server_address.sun_path + , sName, strlen(sName)); /*配置服务器信息(通信协议)*/
server_address.sun_family = AF_LOCAL; /*默认设置resue FLAG*/
if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < ) {
ALOGE("reuse error\n");
goto EXIT;
} /*配置服务器信息(服务器地址长度)*/
client_len = server_len = strlen(sName) + offsetof(struct sockaddr_un, sun_path) + ; /*绑定 socket 对象*/
bind (server_sockfd, (struct sockaddr *)&server_address, server_len); /*监听网络,队列数为1*/
if(listen(server_sockfd,)<){
ALOGE("listen error : %s\n",strerror(errno));
goto EXIT;
}
/*接受客户端请求; 第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));
goto EXIT;
}
else if (client_sockfd> FD_SETSIZE){
ALOGE("accept reach max\n");
close(client_sockfd);
goto EXIT;
}
/*start read loop*/
while() {
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(){
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代码:
package com.example.administrator.localsocket; import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast; import java.io.IOException; import static android.widget.Toast.LENGTH_SHORT; public class MainActivity extends AppCompatActivity { private static final String SOCKET_ADDRESS = "nano_server_socket"; //和HAL层统一地址名称 LocalSocket client_socket = null;
LocalSocketAddress addr; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); client_socket = new LocalSocket(); //创建socket对象
addr = new LocalSocketAddress(SOCKET_ADDRESS,LocalSocketAddress.Namespace.ABSTRACT); //使用虚空间地址
try {
client_socket.connect(addr); //请求连接
} catch (IOException e) {
e.printStackTrace();
} findViewById(R.id.sendMsg).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
//发送数据
String data="hello";
client_socket.getOutputStream().write(data.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onStop() {
super.onStop();
try {
client_socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注:Android8.0版本验证app端要用LocalSocket,需要两个条件:
1.apk需要签名成platform_app; (方法可参考: https://www.cnblogs.com/blogs-of-lxl/p/9233285.html )
2.需要给platform_app增加selinux权限,修改xxx\sepolicy\platform_app.te,添加如下两条规则:
typeattribute platform_app mlstrustedsubject;
allow platform_app audioserver:unix_stream_socket connectto;
测试结果:

Android : App通过LocalSocket 与 HAL间通信的更多相关文章
- 源码分析Android Handler是如何实现线程间通信的
源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...
- Android进程间通信之LocalSocket通信
LocalSocket,在Unix域名空间创建的一个套接字(非服务端). 是对Linux中Socket进行了封装,采用JNI方式调用,实现进程间通信. 具体就是Native层Server和Framew ...
- Android 组件间通信--事件驱动
在android中,组件间通信常用的方式: 1.使用广播机制:在主页面中监听特定的广播事件,进行业务逻辑的操作,其他页面只需要根据需求发送广播即可 例如:常用app结构中,左边通常为菜单栏,点击菜单栏 ...
- Android线程间通信机制——深入理解 Looper、Handler、Message
在Android中,经常使用Handler来实现线程间通信,必然要理解Looper , Handler , Message和MessageQueue的使用和原理,下面说一下Looper , Handl ...
- js判断是否安装某个android app,没有安装下载该应用(websocket通信,监听窗口失去焦点事件)
现在经常有写场景需要提示用户下载app, 但是如果用户已经安装,我们希望是直接打开app. 实际上,js是没有判断app是否已经安装的方法的,我们只能曲线救国. 首先,我们需要有call起app的sc ...
- 背水一战 Windows 10 (101) - 应用间通信: 通过协议打开指定的 app 并传递数据以及获取返回数据, 将本 app 沙盒内的文件共享给其他 app 使用
[源码下载] 背水一战 Windows 10 (101) - 应用间通信: 通过协议打开指定的 app 并传递数据以及获取返回数据, 将本 app 沙盒内的文件共享给其他 app 使用 作者:weba ...
- Android Service、IntentService,Service和组件间通信
Service组件 Service 和Activity 一样同为Android 的四大组件之一,并且他们都有各自的生命周期,要想掌握Service 的用法,那就要了解Service 的生命周期有哪些方 ...
- Android App 安全的HTTPS 通信
漏洞描述 对于数字证书相关概念.Android 里 https 通信代码就不再复述了,直接讲问题.缺少相应的安全校验很容易导致中间人攻击,而漏洞的形式主要有以下3种: 自定义X509TrustMana ...
- Android : App客户端与后台服务的AIDL通信以及后台服务的JNI接口实现
一.APP客户端进程与后台服务进程的AIDL通信 AIDL(Android Interface definition language-“接口定义语言”) 是 Android 提供的一种进程间通信 ( ...
随机推荐
- 池建强 Mac Tips
摘自<MacTalk 人生元编程>,原文有130条,从中摘录出7条:大部分与 Terminal 相关 1. 终端说英语 在终端输入 " say hello" ,Mac ...
- G.711是一种由国际电信联盟(ITU-T)制定的音频编码方式
http://zh.wikipedia.org/zh-cn/G.711 ITU-T G.711 page ITU-T G.191 software tools for speech and audio ...
- Python中字典和集合的用法
本人开始学习python 希望能够慢慢的记录下去 写下来只是为了害怕自己忘记. python中的字典和其他语言一样 也是key-value的形式 利用空间换时间 可以进行快速的查找 key 是唯一的 ...
- 浅谈微服务架构、容器技术与K8S
关注嘉为科技,获取运维新知 企业应用系统:从单体应用走向微服务架构:从裸金属走向容器. 如果在诸多热门云计算技术诸如容器.微服务.DevOps.OpenStack等之中,找出一个最火的方向,那么可能非 ...
- p1218 Superprime Rib
深搜,添加数字后如果仍为质数,继续递归. #include <iostream> #include <cstdio> #include <cmath> #inclu ...
- 一个项目中既有移动端,同时也有PC端的代码,并且 他们的代码分开写的,那么如何实现在手机跳转手机页面,pc点击跳转pc页面
将以下代码放入pc首页即可 <script type="text/javascript"> function mobile_device_detect(url) { v ...
- github入门书籍总结
目录 第一章 由来 第二章 基本知识简介 第三章 初始操作 3.1 注册账号 3.2 创建仓库 第四章 具体实际操作 4.1 初始化仓库及相关操作 4.2 分支操作 4.3 消除冲突 4.4 压缩历史 ...
- Html Email 邮件html页编写指南
前言 写过邮件的html的童学应该都知道,邮件的html一般都用table来布局,为什么呢?原因是大多数的邮件客户端(比如Outlook和Gmail),会过滤HTML设置,让邮件面目全非. 经过多次的 ...
- 洛谷P1101 单词方针
题目描述 给一 n×n 的字母方阵,内可能蕴含多个“yizhong”单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着 88 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉, ...
- h5手机端禁止缩放问题
最近测试html5页面,发现默认都允许用户缩放页面,或者在屏幕双击放大或缩小.即相当于这样设置 <meta name="viewport" content="wid ...