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,一经查实,立即删除!

相关文章

随心玩玩(十三)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没有单独显示器可以给…

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…

什么是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…

力扣-刷MySQL(详细解析)

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

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

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

如何在Eclipse IDE中安装TestNG插件

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

JVM-Arthas高效的监控工具

一、arthas介绍 3.选择监控哪个进程 4.进入具体进程 二、arthas的基础命令与基本操作 1.查询包含Java的系统属性: 命令:sysprop |grep java 1.查询不含Java的系统属性: 命令:sysprop | grep -v java 3.打印历史命令 命令&#…

C语言从入门到实战——结构体与位段

结构体与位段 前言一、结构体类型的声明1.1 结构体1.1.1 结构的声明1.1.2 结构体变量的创建和初始化 1.2 结构的特殊声明1.3 结构的自引用 二、 结构体内存对齐2.1 对齐规则2.2 为什么存在内存对齐2.3 修改默认对齐数 三、结构体传参四、 结构体实现位段4.1 什么是位段4.2 位段…

基于springboot的流浪动物救助管理系统

🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅一 、设计说明 1.1研究背景 随着…

windows平台高dpi介绍

flutter在windows平台如何自定义dpi设置 系统层级的支持(windows平台对高dpi的支持) 主要有两点: 设置系统的缩放比例 (系统及系统自带的app会根据这个设置来进行缩放;自己的app需要结合自己设置的dpi awareness来实现对应的dpi支持)设置进程的dpi aw…

BIOS知识枝桠——RAID 磁盘阵列

文章目录 前言一、RAID介绍二、RAID等级分类1.RAID02.RAID13.RAID24.RAID3和RAID45.RAID5和RAID66.RAID77.RAID10 BIOS下组建RAID 前言 假设存在多块磁盘,如果不组建阵列,磁盘与磁盘之间是没有任何关系的。磁盘A和B,放在A中的文件与B磁盘没有…

vue中使用component中的is渲染组件如何使用,:is 等价 v-if渲染组件。

动态组件顾名思义动态加载不同的组件&#xff0c;is属性用于加载不同组件&#xff0c;传参使用属性传递 1、使用v-for遍历component&#xff0c;组件都会执行 <componentv-for"(item, index) in TAB_PANE":key"index":is"item.componentName"…

Java多线程——并发和并行、实现方法

多线程 并发和并行 实现方法 代码演示 方式一 package com.qiong.thread1;public class MyThread extends Thread{Overridepublic void run() {for (int i 0; i < 20; i) {System.out.println(getName() "Hello World");}} }package com.qiong.thread1;public…

运筹说 第65期 | 动态规划的基本概念和基本原理

20世纪50年代初&#xff0c;美国数学家R. Bellman 等人在解决多阶段决策优化问题时提出了一种高效的求解方法——动态规划&#xff08;Dynamic Programming&#xff09;&#xff0c;该方法基于多阶段决策优化问题的特点&#xff0c;把多阶段问题转换为一系列互相联系的单阶段问…