Binder 机制 javanative

         

一:Binder介绍

Binder是一套ipc通信方案

Binder框架定义了四个角色: Server ,Client,ServiceManager (以后简称SMgr)以及Binder驱动。其中Server ,Client,SMgr运行于用户空间,驱动运行于内核空间。这四个角色的关系和互联网类似: Server是服务器, Client是客户终端, SMgr是域名服务器(DNS),驱动是路由器。 在网络通信中域名服务器的地址是一个固定的地址,所以很方便的通过这个固定地址拿到。那么在Binder中, SMgr 是一个进程, Server是另一个进程, Server向SMgr注册Binder必然会涉及进程间通信。当前实现的是进程间通信却 又要用到进程间通信,这就好象蛋可以孵出鸡前提却是要找只鸡来孵蛋。 Binder的实现比较巧妙:预先创造一只鸡来 孵蛋: SMgr和其它进程同样采用Binder通信, SMgr是Server端,有自己的Binder对象(实体),其它进程都是 Client,需要通过这个Binder的引用来实现Binder的注册,查询和获取。 SMgr提供的Binder比较特殊,它没有名字 也不需要注册,当一个进程使用BINDER_SET_CONTEXT_MGR命令将自己注册成SMgr时Binder驱动会自动为它创建 Binder实体(这就是那只预先造好的鸡)。其次这个Binder的引用在所有Client中都固定为0而无须通过其它手段获得。也就是说, 一个Server若要向SMgr注册自己Binder就必需通过0这个引用号和SMgr的Binder通信。类比网络通信, 0号引用就好比域名服务器的地址,你必须预先手工或动态配置好。要注意这里说的Client是相对SMgr而言的,一个应用程序可能是个提供服务的Server,但对SMgr来说它仍然是个Client。

BInder通信的流程梳理:

1. 首先, 一个进程使用 BINDERSETCONTEXT_MGR 命令通过 Binder 驱动将自己注册成为 ServiceManager;

2. Server 通过驱动向 ServiceManager 中注册 Binder( Server 中的 Binder 实体),表明可以对外提供服务。驱动为这个 Binder 创建位于内核中的实体节点以及 ServiceManager 对实体的引用,将名字以及新建的引用打包传给 ServiceManager ,ServiceManger 将其填入查找表。

3. Client 通过名字,在 Binder 驱动的帮助下从 ServiceManager 中获取到对 Binder 实体的引用。

4. 通过这个Binder实体引用, Client实现和 Server 进程的通信。

二:Binder的创建

总的来说, Binder的初始化是在进程已创建就完成了。创建进程后会第一时间为这个进程打开一个binder驱 动,并调用mmap接口向Binder驱动中申请内核空间的内存。

三:AIDL原理

.aidl文件

-----------------------

interface IServer {

int testFunction(String s);

}

远程服务

----------------------

public class RemoteTestService extends Service {

private IServer.Stub serverBinder = new IServer.Stub() {

@Override public int testFunction(String s) throws RemoteException {

Log.i("test","testFunction s= " + s);

return 0;

}

};

@Nullable @Override

public IBinder onBind(Intent intent) {

return serverBinder;

}

}

客户端

------------

public class MainActivity extends AppCompatActivity {

private IServer iServer;

private ServiceConnection serviceConnection = new ServiceConnection() {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

iServer = IServer.Stub.asInterface(service);

System.out.println("onServiceConnected");

try {

int a = iServer.testFunction("test string");

Log.i("test", "after testFunction a:" + a);

} catch (Exception e) {

e.printStackTrace();

}

}

@Override

public void onServiceDisconnected(ComponentName name) {

Log.i("test", "onServiceDisconnected");

}

};

@Override

protected void onCreate( Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Intent intent = new Intent(MainActivity.this, RemoteTestService.class);

bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

}

}

------------------------------------

aidl文件自动生成的Java文件如下:

通过aidl文件生成了Java文件,这个类的静态内部类Stub(继承了 Binder,实现了接口方法),主要逻辑在方法asInterface,如下图

asInterface方法之后也就能调用服务端端方法了,testFunction()方法进行数据的传递,有同步和异步之分。aidl接口中定义的方法都是在实现BInder的线程池中执行。详见 :aidl中的oneWay的语法解释

客户端:持有proxy

服务端:持有stub

stub是类IServer的静态内部类,proxy是stub的静态内部类通过构造方法持有stub引用

服务端和客户端同一进程:客户端可以直接使用stub类

服务端和客户端非同一进程:客户端需要获取接口类型的stub也就是Proxy,而Proxy持有stub,这个接口就是aidl

aidl通信的基本步骤如下:

1. Client通过ServiceConnection获取到Server的Binder,并且封装成一个Proxy。

2. 通过Proxy来同步调用IPC方法(

testFunction),同时通过Parcel将参数传给Binder,最终触发Binder的

transact方法。

3. Binder的transact方法最终会触发到Server上Stub的onTransact方法。

4. Server上Stub的onTransact方法中,会先从Parcel中解析中参数,然后将参数带入真正的方法中执行,然后将

结果写入Parcel后传回。

5. 请注意: Client的Ipc方法中,执行Binder的transact时,是阻塞等待的, 一直到Server逻辑执行结束后才会继

续执行。当然,如果IPC方法是oneWay的方式,那么就是非阻塞的等待。

6. 当Server返回结果后, Client从Parcel中取出返回值,于是实现了一次IPC调用。

所以, aidl 文件会生成一个java文件,这个java文件的意义在于将核心的binder驱动封装成为java层可以直接调用的

代码,同时也处理了将java层的数据格式转换为Parcel格式数据进行跨进程传递的一个功能。所以, aidl是一个使用binder的标准方案,该方案的代码同样的可以通过用户自己编写的方式完成

四:BindService的原理

1,client(客户端进程)

2,service (远端服务进程)

3,ams(systemservicer进程)

4,serviceManager(进程)

具体流程如下:

1)Activity作为Client发起bindService,最终会调度到AMS 去执行bindService。在这个过程中, Client要去调用

AMS的代码,所以此时就会涉及到跨进程调度,基于第三章的Binder通信模型我们不难知道, Client会先和

ServiceManager通信,从ServiceManager中拿到AMS的IBinder。

2)Activity拿到AMS的IBinder后,跨进程执行AMS的BindService函数;

3)由于AMS管理所有的应用进程,因此AMS中持有了应用进程的Binder,所以此时AMS可以发起第4步也就是跨进

程调度scheduleBindService();

4)Server端会在收到AMS的bindService的请求后,会将自己的IBinder发送给client,但是Server必须通过AMS才能

将Binder对象传过去,所以此时需要跨进程从ServiceManager中去拿到AMS的binder;

5)Server端通过AMS的binder直接调用AMS的代码publishService(),将service的Binder发送给AMS;

6)经过层层调用,最终AMS讲Server端的binder通过回调connect函数传递给了Client端的Activity;

以上就是bindService的全流程,这个流程主要的目的是将Server端的Binder对象发送给Client端。从此以后, Client端就可以通过Server端的binder与Server端像调用自己的代码一样完成跨进程通信了。

五:Binder的优点

高效:数据拷贝一次,通过mmap(内存映射)提高数据传递效率

内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间反之内核空间对这段区域的修改也能直接反应到用户空间

安全:内核添加身份识别

稳定:c/s架构

六:Java& Native层面 Binder相互转化

因此我们必须研究一下Java framework层与Native层之间的相互调动。

1)Client端通过ServiceManager 拿到Server端服务的Binder 代理,也就是BinderProxy(是Server端Binder的一个 代理);

2)这个BinderProxy的访问需要经过JNI层的Android_util_binder类将请求转交给native的BpBinder(p代表代理的意思);

3) BpBinder会通过ioctl将请求转交给Binder驱动设备;

4)在服务端注册了一个监听请求的回调函数, 一旦驱动层收到BpBinder 的调用,就会回调BBInder注册的回调函 数,于是,就将请求转给了BBinder;

5) BBinder拿到请求后,会进行一些数据的处理,然后通过JNI将请求转交给了java类;

6)java层会通过aidl中的函数将请求发送给Server端的实现者,由Server端通过stub 去调用相关的执行代码,并将 结果通过类似的路径返回。

以上只是一个大概的流程

七: ServiceManager解析

ServiceManager作为一个起始的服务,是通过init.rc 来启动的。

//system\core\rootdir\init.rc

//启动的服务 ,这里是用的服务名称。服务名称是在对应的rc文件中注册并启动的

start servicemanager

具体的服务信息是在servicemanger.rc命名并定义的

//\frameworks\native\cmds\servicemanager\servicemanager.rc

service servicemanager / system/ bin/ servicemanager

class core animation

user system

//说明以用户system身份运行

group system readproc

//说明servicemanager是系统中的关键服务,

//关键服务是不会退出的 ,如果退出了 ,系统就会重启 ,当系统重启时就会启动用onrestart关键字修饰的进程,

//比如zygote、media、 surfaceflinger等等。

critical

onrestart restart healthd

onrestart restart zygote

onrestart restart audioserver

onrestart restart media

onrestart restart surfaceflinger

onrestart restart inputflinger

onrestart restart drm

onrestart restart cameraserver

onrestart restart keystore

onrestart restart gatekeeperd

onrestart

. .

restart thermalservice

八:ServiceManager的客户端 Binder 的通信

九:ServiceManager的服务端 Binder 的通信

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/625752.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你知道什么是Java中的类型强转吗?

强制类型转换 强转存在与父转子的时候,子转父不需要进行强转,如 Object o "hello"; //String类是Object类的子类,无需进行强转类型强转分为两种情况: Ⅰ、向下转型:将父类对象引用转换为子类对象引用&am…

随心玩玩(十三)Stable Diffusion初窥门径

写在前面:时代在进步,技术在进步,赶紧跑来玩玩 文章目录 简介配置要求安装部署下载模型启动ui插件安装教程分区提示词插件Adetailer插件提示词的分步采样采样器选择采样器的收敛性UniPC采样器 高分辨率修复 (Hires. fix)图生图ControlNet介绍…

jetson nano VNC远程桌面配置及使用(nomachine)

文章目录 jetson nano VNC远程桌面配置及使用1.Nomachine介绍2.在电脑端安装Nomachine3.在Jetson Nano端安装Nomachine4.电脑端连接及使用步骤5.修改分辨率6.NoMachine常见问题6.1 黑屏6.2 白屏 jetson nano VNC远程桌面配置及使用 本节适用于Jetson Nano没有单独显示器可以给…

正则验证封装

正则表达式常用符号说明: .是除换行以外的所有任意符号 \s空白符号 \S除空白符号以外的任意符号 \w字母、数字、下划线 \W 除字母、数字、下划线以外的其他任意符号 \d 数字(0----9) \D 除数字以外的任意其他符号 ^ 字符串开始 $ 字符串结束 * 匹配0到无数次(匹配的是符号前边的…

2023年跨国企业如何实现跨境数据传输合规化(上)

一、什么是数据跨境传输? 首先了解一个概念,什么是数据跨境传输? 数据跨境传输简单概括就是指信息通过互联网等网络媒介,在跨国企业之间进行传递和交换的过程。 有一则官方网站关于全球化数字化的数据统计:仅2019 年…

MyBatisPlus学习笔记二

接上:MyBatisPlus学习笔记一: MyBatisPlus学习笔记一-CSDN博客 1、条件构造器 MyBatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求。 1.1、集成体系 1.2、实例 查询 lambda查询 更新 1.3、总结 2、自定义sql 我们可以利用MyB…

强化学习AI构建实战 - 基于“黄金点”游戏(二)

服务端接口 为了让大家的AI可以顺利地进行游戏,并验证我们对策略和AI的一些实现,我们需要一些基础设施来帮助我们完成一些工作。这些工作包括游戏回合的控制、参与者之间的数据同步、游戏数据的储存等功能。 为了简化这些基础工作,以便大家…

VM虚拟化——物理机迁移至虚拟化

一、安装迁移工具 VMware vCenter Converter Standalone 【安装向导】 【最终用户专利协议】 【最终用户许可协议】 【安装位置】 【安装类型】默认本地安装 【用户体验设置】 【准备安装】 二、迁移 【转换机器】 【源主机】 填ip、用户名和密码 最好是用administ…

训练营四十八天 | 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

198.打家劫舍 不要忘记空数组和数组长度为1的情况单独考虑 和前两个状态有关 代码随想录 class Solution {public int rob(int[] nums) {if(nums null && nums.length 0) return 0;if(nums.length 1) return nums[0];int[] dp new int[nums.length];//int[] dp …

易观察|2024年金融科技新趋势揭秘,大模型发展有望落地

2023年,是金融科技市场持续向好的一年,受政策和市场的双重推动,金融科技企业信心大增,未来发展信心指数平均分提升到82.8,创下近三年来的新高。而随着市场、政策和经济的企稳预期,以及GPT大模型技术的迅猛发…

【打卡】牛客网:BM90 最小覆盖子串

题目: BM65 最长公共子序列(二): 找二者的相同部分,该部分对于二者可以不连续排列的(但是是有序的)。 BM66 最长公共子串 找二者的相同部分,该部分对于二者是连续排列的。 本题:BM90 最小覆盖…

什么是DDOS高防ip?DDOS高防ip是怎么防护攻击的

随着互联网的快速发展,网络安全问题日益突出,DDoS攻击和CC攻击等网络威胁对企业和网站的正常运营造成了巨大的威胁。为了解决这些问题,高防IP作为一种网络安全服务应运而生。高防IP通过实时监测和分析流量,识别和拦截恶意流量&…

PattPatel-“Introduction to Computing Systems“(4)期末样卷题目解析:C语言递归

C语言的递归我觉得最主要的还是要把Patt&Patel的部分好好理解下(因为有和硬件结合的部分),但因为今天就考试(来不及做这样的事情),先把之前模拟卷的题目给尝试弄明白,然后考完试之后继续学习…

vue-ESlint代码规范及修复

1. 介绍 ESLint:是一个代码检查工具,用来检查你的代码是否符合指定的规则(你和你的团队可以自行约定一套规则)。 在创建项目时,我们使用的是 JavaScript Standard Style 代码风格的规则。 规范网址:https://standardjs.com/rules-zhcn.htm…

美易官方:仅差8万辆,特斯拉2023年全球销量接近奥迪

特斯拉在2023年全球销量仅差8万辆就能追平奥迪,这一消息引起了汽车行业的广泛关注。作为电动汽车市场的领头羊,特斯拉一直以创新的技术和设计引领着汽车行业的发展。而奥迪作为传统豪华汽车品牌,也在不断探索和尝试新的发展路径。 特斯拉在20…

力扣-刷MySQL(详细解析)

🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页:小小恶斯法克的博客 🎈该系列文章专栏:重拾MySQL 🍹文章作者技术和水平很有限,如果文中出现错误&am…

【五】CocosCreator-CCScheduler.js源码分析

PS:只是看源码学习过程中把认为重要的内容以笔记的形式记录下来。 【1】HashTimerEntry:用于保存指定target的事件定时器相关参数的数据结构。 【2】_hashForTimers:targetId作为key,HashTimerEntry【2】对象作为value的hash数组…

uniApp 顶部导航栏右侧添加文字按钮

{"path" : "pages/allin/MessageCenter/MessageCenter","style" : {"navigationBarTitleText": "消息中心","enablePullDownRef…

torch: 返回最大的几个值--topk()

torch.topk() 是 PyTorch 中的一个函数,用于从张量(tensor)中选取最大的 k 个值及其对应的索引。这个函数对于需要找到最大值或者对数据进行排序的场景非常有用。 函数的基本语法如下: torch.topk(input, k, dimNone, largestTrue, sortedT…

如何在Eclipse IDE中安装TestNG插件

目录 使用Eclipse Marketplace安装TestNG插件 通过输入URL安装TestNG 1.点击安装新软件 2.输入URL以安装TestNG 3.遵循正常的安装过程 4.重新启动Eclipse 在Eclipse中安装TestNG插件的视频 在这篇文章中,我们将介绍如何在Eclipse IDE中安装TestNG插件&#x…