仔细观察Binder和mmap;分析Android进程间通信

news2024/12/28 21:33:51

前言

Binder是Android系统中的一种IPC(进程间通信)机制,它使得不同进程中的组件能够互相交互和通信。在Binder中,一个进程中的客户端和另一个进程中的服务器之间通常通过Binder驱动程序进行通信。这种通信方式能够提供安全性和效率。

在Android中,Binder被广泛用于各种不同的场景。例如,系统服务、应用程序组件以及多进程通信等等。Binder的使用方式主要是通过调用API来完成,例如创建Binder服务、绑定Binder服务、传递数据等等。同时,也可以使用类似AIDL(Android界面描述语言)这样的工具来简化Binder的使用过程,使数据传输的过程变得更加便捷。

Binder原理

Binder其基本原理是利用Binder驱动程序,在不同进程间建立一个通道,数据可以在进程间传递。

在Binder的通信中,有三种角色:客户端、服务端和Binder驱动程序。当客户端需要和服务端通信时,它需要绑定到服务端的Binder对象上。此时,Binder驱动程序就会对象进行引用计数,并返回一个Binder代理对象(Proxy),客户端通过该代理对象来调用服务端提供的方法。通过Binder代理对象,客户端可以将请求消息发送给服务端,并等待服务端的回复。

服务端收到来自客户端的请求后,它需要将请求数据解包,并执行所需的操作。执行完操作后,服务端需要将结果打包并返回给客户端,同时,服务端还要对Binder对象自身进行引用计数的处理。当服务端不再需要该Binder对象时,它会释放掉该对象并同时通知Binder驱动程序进行相应的处理。

在Binder的消息传递中,还涉及到了Binder的底层传输机制及其相关概念,例如Binder节点、Binder线程以及Binder缓存等等。了解这些概念可以帮助开发人员更好地理解和使用Binder。

Binder使用代码示例

下面是一个简单的Binder使用示例,创建一个简单的Binder服务,通过客户端调用服务端提供的方法从而传输数据。

首先,创建一个AIDL文件,定义服务端提供的接口,例如:

//定义Binder服务端接口
interface IMyService {
    int add(int a, int b);
}

然后,实现这个接口,创建一个Binder服务端类:

public class MyService extends Service {
    private final IBinder mBinder = new MyBinder();
​
    public class MyBinder extends Binder {
        public MyService getService() {
            //返回当前服务端对象
            return MyService.this;
        }
    }
​
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
​
    //服务端实现接口方法
    public int add(int a, int b) {
        return a + b;
    }
}

最后,在客户端中绑定这个服务,并通过服务端提供的接口进行数据传输:

public class MainActivity extends AppCompatActivity {
    //定义服务端接口对象
    private IMyService myService;
​
    //定义服务端连接对象
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //获取服务端接口对象
            myService = IMyService.Stub.asInterface(iBinder);
        }
​
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            myService = null;
        }
    };
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
        //绑定服务端
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
​
        //调用服务端接口
        if (myService != null) {
            try {
                int result = myService.add(1, 2);
                Toast.makeText(this, "result=" + result, Toast.LENGTH_SHORT).show();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
​
    //解除服务端绑定
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

在这个示例中,服务端实现了IMyService接口,并提供了一个add方法,在客户端通过服务端提供的接口数据传输。在客户端中,首先绑定服务端,然后通过服务端接口调用服务端方法并传递参数,获取服务端返回的数据,并最终解除服务端的绑定。

这就是一个简单的Binder示例,展示了Binder的基本使用方式。

Binder核心函数mmap源码分析

Binder是一种IPC(进程间通信)机制,常用于Android系统中进程间通信。mmap是Binder中的一个核心函数,用于映射数据到内存中。

函数原型如下:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数说明:

  • addr:指向欲映射的内存起始地址,通常设为0,代表由操作系统自动选择新的空闲地址。
  • length:欲映射的内存大小。
  • prot:内存保护标志。PROT_READ表示页面可读取;PROT_WRITE表示页面可写入;PROT_EXEC表示页面可执行。
  • flags:内存映射标志,通常设置为MAP_SHARED或MAP_PRIVATE。MAP_SHARED表示映射后对内存的写入操作会被同步到磁盘上的文件中;MAP_PRIVATE表示映射后的修改不会同步到磁盘文件。
  • fd:需要映射到内存中的文件描述符。
  • offset:从文件开始处的偏移量。

在Binder中,mmap函数主要是用于映射Binder驱动程序中的共享内存(Shared Memory)区域。Binder驱动程序使用共享内存来缓存传输的数据,减少系统调用次数和内存拷贝次数,提高系统性能。应用程序可以通过mmap函数将共享内存映射到自己的地址空间中,以便于对其进行读写操作。

具体实现可以参考Binder驱动程序中的mmap函数实现。

在Binder大量的IPC通信中,mmap函数的调用频率非常高,因此在实现中要考虑到内存的释放和回收,避免内存泄漏和内存缓慢释放等问题。

mmap内存映射详解

mmap是一种将磁盘文件或其它进程的内存映射到进程地址空间的方式。它可以将一个文件的部分或全部内容关联到在进程地址空间的一段连续的虚拟内存区域(也叫做内存映射文件)。这种方式可以提高文件的访问速度,因为每次访问的时候,内核可以直接将虚拟内存页中的内容读取到内存中,而不需要通过对文件的读取操作。

需要注意的是,mmap只对常规文件有效,而对于其它类型的文件(如设备文件),将会产生不可预知的后果。而且,在将一个文件映射到进程地址空间之前,首先需要打开文件。

mmap的原型如下:

#include <sys/mman.h>
​
void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);

其中各个参数的含义如下:

  1. addr:指向欲映射的内存起始地址的指针,通常设为NULL表示由系统自动分配,或者显式指定为某个地址。
  2. length: 欲映射的内存区域的长度(以字节为单位),通常与文件的大小相对应。需要注意的是,对于一个映射到文件的内存区域而言,其长度必须是页面大小的整数倍。在Linux系统上,默认页的大小是4KB。
  3. prot:映射区域的保护方式。该参数可取的值有:
  • PROT_READ: 表示映射区域可读。
  • PROT_WRITE:表示映射区域可写。
  • PROT_EXEC:表示映射区域可执行。

在这些值中的任意组合即可。比如,如果映射区域既可读又可写,则prot参数应设置为PROT_READ | PROT_WRITE。

  1. flags:用于描述映射区域的类型和属性。可取的值有:
  • MAP_SHARED:表示映射区域被多个进程共享。对该区域的写操作将直接影响到磁盘文件和所有共享内存中该区域的内容,而对该区域的读操作将从磁盘或共享内存中读取数据。
  • MAP_PRIVATE:表示映射区域是进程私有的。对该区域的写操作将只影响到该进程的内存中,而不会影响到磁盘上的文件或其它进程中共享内存的同一区域。
  • MAP_FIXED:表示映射区域的起始地址可指定。如果addr参数非空,则系统会尝试将映射区域起始地址定位到该地址。如果该地址范围内已经存在其它对象,则映射失败。
  • MAP_ANONYMOUS:表示映射的区域不与文件关联而是由内核分配的一块匿名内存区域。在使用该标志位进行映射时,fd和off参数必须为0。
  • MAP_DENYWRITE:表示不允许将文件写操作映射到该区域。只有对共享内存有效,通常用于防止进程试图修改映射区域中的代码段。
  1. fd:文件描述符,用于指定要映射的文件。
  2. offset:文件偏移量,用于指定映射区域在文件中的起始位置。

mmap函数成功执行后,会返回映射区域的起始地址,如果失败则返回MAP_FAILED。在使用完映射区域后,需要调用munmap函数将映射区域解除。

在使用mmap函数时,需要注意以下几点:

  1. 映射区域的长度必须是页面大小的整数倍。在Linux系统中,默认页面大小为4KB。
  2. 对于多进程访问同一内存映射区域的情况,要保证使用的是共享内存,否则会导致数据不同步的问题。
  3. 映射区域的起始地址必须按页对齐,否则可能会引起内存访问错误。
  4. 映射区域的保护方式和属性一旦确定,就不能更改。
  5. 映射区域是一块连续的虚拟内存,但实际的物理内存可能不是连续的。如果虚拟内存超过了实际物理内存,那么会出现内存换页的情况。
  6. 使用了MAP_ANONYMOUS标志位的映射区域不会关联到磁盘文件,因此不能用于持久化存储。只有使用了MAP_SHARED和MAP_PRIVATE标志位的映射区域才能用于文件的读写操作。

综上所述,mmap函数是一种方便高效的内存映射方式,它可以将磁盘文件或共享内存映射到进程的地址空间中,以提高文件的读写效率,并通过对内存映射区域的操作来对文件进行读写操作。但是要注意参数的设置,以及对映射区域的内存管理。更多有关Android的技术framework通信机制,这里可以参考《Android核心 技术手册》这个技术文档。详细 内容请点击查看。

总结一下

Binder和mmap都是与内存操作相关的技术,但它们的应用场景和实现方式有所不同。

Binder是一种进程间通信机制,常用于Android系统中不同进程之间的通信。在Binder机制中,一个进程可以将自己的一个或多个对象注册到Binder驱动中,其他进程可以通过向Binder驱动发送消息,实现与这些对象交互的目的。Binder机制实际上是基于共享内存和进程间信号量等底层技术实现的,具体地,Binder驱动会为每个进程分配一段共享内存作为缓冲区,用于存放进程间传递的消息和数据。

与Binder不同,mmap是一种内存映射机制,常用于将文件映射到应用程序的内存空间中,实现文件的随机访问。在Linux系统中,mmap函数可以将一个文件映射到一个进程的虚拟地址空间中,实现文件的读写操作。当应用程序访问映射区域时,Linux内核会自动将访问转换为磁盘上相应的文件操作,从而实现了透明的读写操作。

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

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

相关文章

材料写作技巧:关于“新”排比句40例

1.是新时代新征程举旗定向的“宣言书”&#xff0c;是新时代新征程伟大思想的“领航标”&#xff0c;是新时代新征程推进中国式现代化的“动员令”&#xff0c;是新时代新征程自我革命的“冲锋号”。 2.胸怀家国&#xff0c;树立远大理想&#xff0c;奋力担当新时代青年使命&a…

真题详解(数据流图平衡)-软件设计(五十九)

真题详解&#xff08;磁盘&#xff09;-软件设计&#xff08;五十八)https://blog.csdn.net/ke1ying/article/details/130376289 如何保证数据流图平衡&#xff1f; 父图中输入流输出流的名称和数目必须和子图的相同。 父图中一条输入输出流可以对应子图几条输入输出流&…

MATLAB实现OCR自动阅卷,识别答题卡进行成绩统计

利用MATLAB进行答题卡识别编程设计&#xff0c;最主要的是实现了将答题卡中被填涂的答案提取出来&#xff0c;然后与标准的答案进行比对。通过相关的算法&#xff0c;算出考生填涂正确的题数&#xff0c;并统计计算后的得分。 每种答题卡都有很明显的助识别标记&#xff0c;像…

LeetCode - 494 目标和

目录 题目来源 题目描述 示例 提示 题目解析 算法源码 题目来源 494. 目标和 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个…

MathType如何成功插入到word

有时候我们重装mathtype的时候&#xff0c;我们的word里嵌入的mathtype没有了&#xff0c;因此我们如何让它重新出来呢&#xff1f;下面我们来看看。 1、我们打开word&#xff0c;点击“选项”&#xff0c;点击“加载项”找到如图所示的路径内容&#xff08;根据自己电脑的实际…

IDA 知识汇总

工具使用-IDA从入门到理解 - 简书作者ID:leishi-yanmu IDA对于各位师傅应该无需简介了,如果写的不对的地方,还望师傅们多多包涵。讲解的时候会涉及到笔者在学习和使用时候的理解。 启动界面介绍: ...https://www.jianshu.com/p/190805574432[原创]【iOS逆向与安全】利用IDA…

实现网页顶部线性加载进度条

插件一&#xff1a;NProgress.js 下载链接&#xff1a;https://github.com/rstacruz/nprogress 插件二&#xff1a;MProgress.js 下载链接&#xff1a;https://github.com/lightningtgc/mprogress.js/ 这两个插件都是实现网页加载进度条&#xff0c;并且默认方法有四个&…

kitti数据集预处理

kitti数据集预处理 0.引言0.1.calib0.2.oxts(gps/imu)0.3.velodyne0.4.image_2/30.5.kitti-step/panoptics0.6.label 1.create_kitti_depth_maps2.create_kitti_masks3.create_kitti_metadata4.extract_dino_features5.run_pca 0.引言 官网参考链接1参考链接2 注&#xff1a;…

Linux基础指令(1)

Linux的基础指令 对于Linux的学习&#xff0c;先从指令开始学&#xff0c;我们先了解操作系统的一般性概念&#xff0c;然后对于Linux的一些基本的指令进行学习&#xff0c;最后我们发现Linux实际上是一个多叉树的目录结构 文章目录 Linux的基础指令操作系统操作系统是什么&am…

数据可视化开源工具软件

数据可视化工具用于通过图形、图表、表格、地图和其他详细的视觉对象来表示信息。 它们通常将数据呈现和分析结合起来&#xff0c;以帮助专业人员在数据驱动领域(如工程、数据科学和业务分析)做出更明智的决策。 选择正确的数据可视化工具将帮助您减少数据错误&#xff0c;并…

基于本地知识构建简易的chatPDF

Langchain chatglm-6b 文章目录 Langchain chatglm-6b前言一、实验记录1.1 环境配置1.2 代码理解1.3 补充内容 二、总结 前言 介绍&#xff1a;一种利用 ChatGLM-6B langchain 实现的基于本地知识的 ChatGLM 应用 Github: https://github.com/imClumsyPanda/langchain-Chat…

阳光开朗孔乙己,会否奔向大泽乡

前言 &#x1f525;学历对职业关系到底有什么影响呢&#xff1f;&#x1f525;学历给我们带来了优势吗&#xff1f;&#x1f525;到底是什么造成了"孔乙己的长衫"&#xff1f; 孔乙己是中国清代作家鲁迅创作的一篇短篇小说&#xff0c;发表于1919年。这部作品被认为是…

Blender 建模案例一(2)

目录 1. 烛台基座1.1 导入图片1.2 从立方体取一个顶点1.3 用点描边1.4 旋转1.5 实体化修改器1.6 删除内部正面1.7 封盖1.8 平滑着色1.9 表面细分修改器1.10 环切线&#xff08;卡线&#xff09; 1. 烛台基座 1.1 导入图片 1.2 从立方体取一个顶点 中间顶点尽量也X轴平行 1.…

FPGA入门系列5--运算符号

文章简介 本系列文章主要针对FPGA初学者编写&#xff0c;包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解&#xff0c;旨在更快速的提升初学者在FPGA开发方面的能力&#xff0c;每一个章节中都有针对性的代码…

( 栈和队列) 739. 每日温度 ——【Leetcode每日一题】

❓739. 每日温度 难度&#xff1a;中等 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置…

32k*16 薪,3年自动化测试历经3轮面试成功拿下华为Offer....

前言 转眼过去&#xff0c;距离读书的时候已经这么久了吗&#xff1f;&#xff0c;从18年5月本科毕业入职了一家小公司&#xff0c;到现在快4年了&#xff0c;前段时间社招想着找一个新的工作&#xff0c;前前后后花了一个多月的时间复习以及面试&#xff0c;前几天拿到了华为…

Java并发编程 —— ThreadPoolExecutor线程池详解

一、什么是线程池 线程池是一种池化技术&#xff0c;是管理一系列线程的资源池。当有任务要处理时&#xff0c;直接从线程池中获取线程来处理&#xff0c;处理完之后线程并不会立即被销毁&#xff0c;而是等待下一个任务。这样实现线程的复用&#xff0c;避免重复创建与销毁线…

司美格鲁肽进入临床竞速期,减肥“神药”生于偶然、火于乱象?

减肥作为一门市场需求旺盛的生意&#xff0c;在很多行业都有所渗透&#xff0c;如今其高潮逐渐来到了医药领域。 CDE&#xff08;国家食品药品监督管理局药品审评中心&#xff09;网站显示&#xff0c;4月17日&#xff0c;联邦制药全资附属公司联邦生物科技&#xff08;珠海横…

Figma导出源文件的方法,用这个方法快速转换其它格式

市场上设计工具层出不穷&#xff0c;Sketch、AdobeXD、Axure、InVision、Figma、Pixso等都是优秀的设计工具&#xff0c;设计师经常面临如何从设计工具中导出文件的问题。 Figma软件的导出功能非常强大&#xff0c;因为轻量化体验受到很多设计师的喜爱。如何保存导出Figma源文…

【Leetcode -19.删除链表的倒数第N个结点 -24.两两交换链表中的节点】

Leetcode Leetcode -19.删除链表的倒数第N个结点Leetcode - 24.两两交换链表中的节点 Leetcode -19.删除链表的倒数第N个结点 题目&#xff1a;给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;he…