Binder进程通信基础使用



Binder 进程通信基础使用

一、服务端进程创建 Service,Service 中创建 Binder 子类对象并于 onBind 中返回。xml 定义。

  1. 创建 Service,创建 Binder 子类对象并于 onBind 返回
class UserService : Service() {private companion object {const val TAG: String = "test_service_tag"}private val service = object : Binder() {override fun onTransact(p0: Int, p1: Parcel, p2: Parcel?, p3: Int): Boolean {p1.enforceInterface("UserService")when(p0) {0 -> {// 读取客户端传递的 int 值val readInt = p1.readInt()Log.e(TAG, "service get int : $readInt")// 写入无异常,表示这次调用没有出现问题p2?.writeNoException()p2?.writeInt(readInt * 2)return true}1 -> {// 读取客户端传递的 String 值val readString = p1.readString()Log.e(TAG, "service get String: $readString")// 写入无异常,表示这次调用没有出现问题p2?.writeNoException()p2?.writeString("service version: 1.0.0")return true}// 2的时候传的 Binder,拿到客户端 Binder 模拟跨进程回调,也就是此时随时可以双向通信2 -> {// 读取客户端传递的 Binder 对象,双向通信,直接点说就是callback回调对象val readStrongBinder = p1.readStrongBinder()Log.e(TAG, "service get binder: $readStrongBinder execute method:")val data = Parcel.obtain()val reply = Parcel.obtain()try {//确认 token 令牌data.writeInterfaceToken("UserService")data.writeInt(111)// 回调客户端,保存传来 Binder 后,随时可以回调,这里简易写一下就行readStrongBinder.transact(0 ,data, reply, 0)//这个方法必须要 reply 调了writeException 或 writeNoException,不然直接抛异常,看方法源码就看出来了reply.readException()Log.e(TAG, "service binder call back result: " + reply.readInt())} finally {data.recycle()reply.recycle()}return true}else -> {Log.d(TAG, "service unspecific value")}}return super.onTransact(p0, p1, p2, p3)}}override fun onBind(p0: Intent?): IBinder {Log.e(TAG, "service onBind Service ")return service}
}

简易说明:onTransact(p0: Int, p1: Parcel, p2: Parcel?, p3: Int)

在客户端调用传过去的 Binder.transact 方法时会回调此方法
p0: requestCode 请求码,可以用于区分不同的执行操作,类似 aidl 中不同的方法的区分
p1: data 数据,客户端传来的数据,客户端 write 写入,服务端 read 读取。
p2: reply 数据,当 p3 参数是 0时,在服务端进行 write,客户端调完方法直接 read 读取写入的值。
p3: flag 标记,0 表示这个方法有返回值,可对 reply 进行写入,然后客户端读取,1 的话表示单向,数据只从客户端到服务端,没有返回值,就算对 reply 写值,客户端也读不到。

  1. 在服务端 AndroidManifest.xml 里定义 service.
        <service android:name=".UserService" android:exported="true"android:enabled="true"android:permission="com.example.service"><intent-filter><action android:name="com.example.service.UserService" /></intent-filter></service>

简易说明:exported 外部调用开关,permission 权限限制,不设置不一定能绑定上

二、客户端绑定服务,通过返回的 Binder 执行逻辑,传递 Binder 完成跨进程回调。xml 权限及包名定义。

  1. 客户端 AndroidManifest.xml 中设定权限、包名.
    <permission android:name="com.example.service" /><uses-permission android:name="com.example.service" /><queries><package android:name="com.example.service" /></queries>

简易说明::TargetSDK > 30之后绑定非自身应用的 service 要加,里面写绑定服务的包名.
: 在服务端对 service 要求需要该权限,所以要加。

  1. 客户端绑定服务。
    private var service: IBinder? = null//这个代码是定义的 class成员变量,比较懒,就仍这儿了// 绑定服务不能只要 action,会抛异常,看了下实现,最少得加个包名val intent = Intent("com.example.service.UserService").also {it.component = ComponentName("com.example.service", "com.example.service.UserService")}Log.e(TAG," activity bind service result : " + bindService(intent, object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {Log.e(TAG, "activity onServiceConnected, service : $service")// 保存服务端传递的 Binder,就是这个this@MainActivity.service = service}override fun onServiceDisconnected(name: ComponentName?) {Log.e(TAG, "activity onServiceDisconnected, service : $service")this@MainActivity.service = null}// 最后一个参数要传 Context.BIND_AUTO_CREATE,不然有问题,啥问题可以看 ComtextImpl.bindService 的源码,里面有 flags 参数校验}, Context.BIND_AUTO_CREATE))

简易说明:就俩注意点
(1)intent 不止传 action,class 和 component 还得加上这两个其中的一个.
(2)binderService 最后一个参数 flag 需要传 Context.BIND_AUTO_CREATE.

  1. 调用 transact 完成跨进程通信。
    private fun getServiceInfo() {Log.d(TAG, "activity getServiceInfo, service : $service")val data0 = Parcel.obtain()val reply0 = Parcel.obtain()val requestCode0 = 0try {//写入 token 令牌,这里是因为客户端写了验证 token,服务端没写就可以不加data0.writeInterfaceToken("UserService")data0.writeInt(100)service?.transact(requestCode0, data0, reply0, 0)//这个方法必须要 reply 调了writeException 或 writeNoException,不然直接抛异常,看方法源码就看出来了reply0.readException()Log.e(TAG,"activity requestCode : $requestCode0, getServiceInfo :  " + reply0.readInt())} finally {data0.recycle()reply0.recycle()}val data1 = Parcel.obtain()val reply1 = Parcel.obtain()val requestCode1 = 1try {data1.writeInterfaceToken("UserService")data1.writeString("what is service version?")service?.transact(requestCode1, data1, reply1, 0)reply1.readException()Log.e(TAG,"activity requestCode : $requestCode1, getServiceInfo :  " + reply1.readString())} finally {data1.recycle()reply1.recycle()}}

问题点:
(1)token 验证。当服务端进行 data.enforceInterface(令牌值) token验证时,调用的客户端必须写入 token data.writeInterfaceToken(令牌值)
(2)默认就有异常。客户端调完 transact() 后,如果调了 reply.readException() 那客户端必须要调用 reply.writeNoException() 或者 reply.writeException()。
(3)data(p1) 和 reply(p2)。data 是客户端写值,服务端读取,相当于 aidl 方法入参,reply 服务端写入,客户端读取,相当于 aidl 方法返回值。
(4)回调双向通信。客户端服务端在已连接情况下双方随时可向对方通信,客户端调用的 transact() 中,data(p1) 写入的时候写入 Binder 对象,服务端拿到 Binder 对象后保存,这样双方都保存了对方的 Binder,也就是随时可以通信。直接点说就是常见的 registerCallback 方式,客户端拿着 service,服务端拿着 callback。

三、记一下。。

  1. Binder 子类对象完成跨进程调用
  2. Binder.transact(p0,p1,p2,p3) 调用时回调 Binder.onTransact(p0,p1,p2,p3),p0 code 区分此次事件该做啥;p1 是传来的参数,可以读取另一边的数据;p2 是传给对方的数据,写入,p3 0时 p2有效,1时p2无效.
  3. Parcel token 验证。transact(p0,p1,p2,p3) 调用方调用前写入,onTransact(p0,p1,p2,p3) 接收方中验证。
  4. Parcel.exception 。transact(p0,p1,p2,p3) 调用方调用后读取,onTransact(p0,p1,p2,p3) 接收方执行时写入。

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

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

相关文章

BI与数据治理以及数据仓库有什么区别

你可能已经听说过BI、数据治理和数据仓库这些术语&#xff0c;它们在现代企业中起着重要的作用。虽然它们都与数据相关&#xff0c;但它们之间有着明显的区别和各自独特的功能。数聚将详细探讨BI&#xff08;商业智能&#xff09;、数据治理和数据仓库之间的区别&#xff0c;帮…

如何统计iOS产品不同渠道的下载量?

一、前言 在开发过程中&#xff0c;Android可能会打出来很多的包&#xff0c;用于标识不同的商店下载量。原来觉得苹果只有一个商店&#xff1a;AppStore&#xff0c;如何做出不同来源的统计呢&#xff1f;本篇文章就是告诉大家如何做不同渠道来源统计。 二、正文 先看一下苹…

云智研发公司面试真题

1.静态方法可以被重写吗 静态方法不能被重写。静态方法是属于类的&#xff0c;而不是属于实例的。当子类继承一个父类时&#xff0c;子类会继承父类的静态方法&#xff0c;但是子类不能重写父类的静态方法。如果子类定义了一个与父类静态方法同名的静态方法&#xff0c;那么它…

算法——快乐数

202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 由图可知&#xff0c;其实这也是一个判断循环的过程&#xff0c;要用到快慢指针&#xff0c;且相遇后&#xff0c;若在全为1的循环里&#xff0c;那么就是快乐数&#xff0c;若相遇后不为1&#xff0c;说明这不是快乐数。 …

备份数据重删

重复数据删除&#xff1a; 在计算中&#xff0c;重复数据删除是一种消除重复数据重复副本的技术。此技术用于提高存储利用率&#xff0c;还可以应用于网络数据传输以减少必须发送的字节数。在重复数据删除过程中&#xff0c;将在分析过程中识别并存储唯一的数据块或字节模式。…

MySQL入门教程

MySQL 是最流行的关系型数据库管理系统 1、什么是数据库&#xff1f; 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库。 每个数据库都有一个或多个不同的 API 用于创建&#xff0c;访问&#xff0c;管理&#xff0c;搜索和复制所保存的…

HAlcon例子

气泡思想 * This example shows the use of the operator dyn_threshold for * the segmentation of the raised dots of braille chharacters. * The operator dyn_threshold is especially usefull if the * background is inhomogeneously illuminated. In this example, *…

vue3的生命周期

1.vue3生命周期官方流程图 2.vue3中的选项式生命周期 vue3中的选项式生命周期钩子基本与vue2中的大体相同&#xff0c;它们都是定义在 vue实例的对象参数中的函数&#xff0c;它们在vue中实例的生命周期的不同阶段被调用。生命周期函数钩子会在我们的实例挂载&#xff0c;更新…

竞赛 基于机器视觉的火车票识别系统

文章目录 0 前言1 课题意义课题难点&#xff1a; 2 实现方法2.1 图像预处理2.2 字符分割2.3 字符识别部分实现代码 3 实现效果最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于机器视觉的火车票识别系统 该项目较为新颖&#xff0c;适合作为竞赛…

23下半年学习计划

大二上学期计划 现在已经是大二了&#xff0c;java只学了些皮毛&#xff0c;要学的知识还有很多&#xff0c;新的学期要找准方向&#xff0c;把要学的知识罗列&#xff0c;按部就班地完成计划&#xff0c;合理安排时间&#xff0c;按时完成学习任务。 学习node.js&#xff0c…

element-ui《input》输入框效验

目录 常用的 element-ui el-input 输入框 1. 过滤字母e&#xff0c; 2. 只能输入正整数 3. 只允许输入数字和小数 / 数字和空格 4. 只允许输入正整数且不能以0开头 4. 允许输入小数点后几位 5. 设置范围&#xff0c;最大值&#xff0c;最小值 6. form 表单中校验输入框只能…

VUE写后台管理(2)

VUE写后台管理&#xff08;2&#xff09; 1.环境2.Element界面3.Vue-Router路由后台1.左导航栏2.上面导航条 1.环境 1.下载管理node版本的工具nvm&#xff08;Node Version Manager&#xff09; 2.安装node(vue工程的环境管理工具)&#xff1a;nvm install 16.13.0 3.安装vue工…

JS for...in 和 for...of 的区别?

for...in 和for ...of的区别&#xff1f; 1. 前言2. for...in3. for...of4&#xff0c;区别5. 总结&#xff1a; 1. 前言 for...in和for...of都是JavaScript中遍历数据的方法&#xff0c;让我们来了解一下他们的区别。 2. for…in for…in是为遍历对象属性而构建的&#xff0…

运维学习之部署Grafana

sudo nohup wget https://dl.grafana.com/oss/release/grafana-10.1.1.linux-amd64.tar.gz &后台下载压缩包&#xff0c;然后按一下回车键。 ps -aux | grep 15358发现有两条记录&#xff0c;就是还在下载中。 ps -aux | grep 15358发现有一条记录&#xff0c;并且tail …

CAS(compare and swa)中的ABA问题及解决

CAS(compare and swap) CAS是&#xff08;compare and swap&#xff09;的缩写&#xff0c;字面意思是比较交换。CAS锁通常也是实现乐观锁的一种机制&#xff0c;首先会给它一个期望值&#xff0c;用期望值与老值做比较&#xff0c;如果相等就用新传入的值进行修改。但是CAS通常…

一百七十八、ClickHouse——海豚调度执行ClickHouse的.sql文件

一、目的 由于数仓的ADS层是在ClickHouse中&#xff0c;即把Hive中DWS层的结果数据同步到ClickHouse中&#xff0c;因此需要在ClickHouse中建表&#xff0c;于是需要海豚调度执行ClickHouse的.sql文件 二、实施步骤 &#xff08;一&#xff09;第一步&#xff0c;海豚建立Cl…

Python in Visual Studio Code 2023年9月更新

作者&#xff1a;Courtney Webster - Program Manager, Python Extension in Visual Studio Code 排版&#xff1a;Alan Wang 我们很高兴地宣布 Visual Studio Code 的 Python 和 Jupyter 扩展将于 2023 年 9 月发布&#xff01; 此版本包括以下内容&#xff1a; • 将 Python …

使用 Nginx 实现企业微信域名配置中的校验文件跳转

背景 在企业微信中配置业务域名时&#xff0c;通常需要在该域名的根路径下放置一个校验文件&#xff0c;以验证域名的所有权。然而&#xff0c;如果该域名是第三方的&#xff0c;你可能无法直接在根路径下放置文件。在这种情况下&#xff0c;你可以使用 Nginx 来实现校验文件的…

YOLO-NAS详细教程--如何使用该model.predict()方法进行对象检测任务

在本教程中,我们将演示如何使用该model.predict()方法进行对象检测任务。 本教程使用的模型是YOLO-NAS ,在COCO 数据集上进行预训练,其中包含 80 个对象类别。 警告:如果您在不继承任何 SuperGradients 数据集的数据集上训练模型,则在运行模型之前需要执行一些额外的步骤…

Unity 收取“运行费”引众怒,开源免费3D游戏引擎CGE(Castle Game Engine)吸引开发者关注

特征 1. 总结2. 跨平台3. 可视化编辑器4.视口与场景&#xff0c;相机&#xff0c;导航和其他组件5. 数据格式 5.1. glTF5.2. X3D5.3. 精灵表5.4. 脊柱6. 图形效果7. 图片8. 用户界面组件 8.1. 文本和字体9. 网络10. 优化和分析11. 声音12. 物理13. 平铺集成14. 粒子15. 使用现代…