Binder机制

article/2025/10/29 0:35:21

直观来讲,Binder是Android中的一个类,它实现了IBinder接口。从IPC角度来看,Binder是Android中一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在Linux中没有:从Android framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager,WindowManager等等)和相应ManagerService的桥梁;从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务区会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端可以获取服务器提供的服务或者输几局,这里的服务包括普通服务和基于AIDL的服务。

(1)Binder分为Client和Servcer两个进程

Cilent和Server是相对的。谁发消息,谁就是Client,谁接受消息,谁就是Server

(2)Binder的组成

Binder的架构如图所示,途中的IPC纪委进程间通信,ServiceManager负责把Binder Server注册到一个容器中

可以把ServiceManager比喻成电话局,存储这个每个住宅的座机电。张三给李四打电话,拨打电话号码,会转接到电话局,电话局的接线员查询到这个号码的地址,因为李四的电话号码之间在电话局注册过,所以能够拨通;如果没有注册,就会提示该号码不存在。

(3)Binder的通信过程

Binder的通信过程如图所示,途中的SM即为ServiceManager。我们看到,Client不可以直接调用Server的add方法,因为他们在不同的进程中,这时候就需要Binder来帮忙了。

首先Server在SM容器中注册。

其次,Client要想调用Server的add方法,就需要获取Server对象,但是SM不会把真正的Server对象返回给Client,而是把Server的一个代理对象,也就是Proxy,返回给Client。

再次,Client调用Proxy的add方法,ServiceManager会帮它去调用Server的add方法,并把结果返回给Client

以上3步,Bidner驱动除了很多力,但我们不需要知道Binder驱动的底层实现

综上所述,学习Binder是为了更好的理解AIDL,基于AIDL模型,进而了解四大组件的原理。礼节了Bidner再看AMS和四大组件的关系,就像是Binder的两个进程Server和Client通信。

为了分析Binder的工作机制,我们需要新建一个AIDL示例,SDK会自动为我们生产AIDL对应的Binder类,然后我们可以分析Binder的工作过程。

首先新建Book.java类,用来传输实体类,不过需要实现Parcelable接口,将实体类进行序列化才能用于传输,

package mfy.com.binderdemo;import android.os.Parcel;
import android.os.Parcelable;public class Book implements Parcelable {private int bookId;private String bookName;public Book(int bookId, String bookName) {this.bookId = bookId;this.bookName = bookName;}protected Book(Parcel in) {bookId = in.readInt();bookName = in.readString();}public static final Creator<Book> CREATOR = new Creator<Book>() {@Overridepublic Book createFromParcel(Parcel in) {return new Book(in);}@Overridepublic Book[] newArray(int size) {return new Book[size];}};@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(bookId);dest.writeString(bookName);}@Overridepublic String toString() {return "Book{" +"bookId=" + bookId +", bookName='" + bookName + '\'' +'}';}
}

定义Book.aidl,

// Book.aidl
package mfy.com.binderdemo;parcelable Book;

声明Book类

定义BookManager接口,用来定义进程间通信的接口

// IBookManager.aidl
package mfy.com.binderdemo;// Declare any non-default types here with import statements
import mfy.com.binderdemo.Book;
interface IBookManager {List<Book> getBookList();void addBook(in Book book);
}

定义好aidl接口之后,我们就可以在项目中查看生成的类:

/** This file is auto-generated.  DO NOT MODIFY.* Original file: E:\\code\\BinderDemo\\app\\src\\main\\aidl\\mfy\\com\\binderdemo\\IBookManager.aidl*/
package mfy.com.binderdemo;public interface IBookManager extends android.os.IInterface {/*** Local-side IPC implementation stub class.*/public static abstract class Stub extends android.os.Binder implements mfy.com.binderdemo.IBookManager {private static final java.lang.String DESCRIPTOR = "mfy.com.binderdemo.IBookManager";/*** Construct the stub at attach it to the interface.*/public Stub() {this.attachInterface(this, DESCRIPTOR);}/*** Cast an IBinder object into an mfy.com.binderdemo.IBookManager interface,* generating a proxy if needed.*/public static mfy.com.binderdemo.IBookManager asInterface(android.os.IBinder obj) {if ((obj == null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof mfy.com.binderdemo.IBookManager))) {return ((mfy.com.binderdemo.IBookManager) iin);}return new mfy.com.binderdemo.IBookManager.Stub.Proxy(obj);}@Overridepublic android.os.IBinder asBinder() {return this;}@Overridepublic boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {switch (code) {case INTERFACE_TRANSACTION: {reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_getBookList: {data.enforceInterface(DESCRIPTOR);java.util.List<mfy.com.binderdemo.Book> _result = this.getBookList();reply.writeNoException();reply.writeTypedList(_result);return true;}case TRANSACTION_addBook: {data.enforceInterface(DESCRIPTOR);mfy.com.binderdemo.Book _arg0;if ((0 != data.readInt())) {_arg0 = mfy.com.binderdemo.Book.CREATOR.createFromParcel(data);} else {_arg0 = null;}this.addBook(_arg0);reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements mfy.com.binderdemo.IBookManager {private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) {mRemote = remote;}@Overridepublic android.os.IBinder asBinder() {return mRemote;}public java.lang.String getInterfaceDescriptor() {return DESCRIPTOR;}@Overridepublic java.util.List<mfy.com.binderdemo.Book> getBookList() throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.util.List<mfy.com.binderdemo.Book> _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);_reply.readException();_result = _reply.createTypedArrayList(mfy.com.binderdemo.Book.CREATOR);} finally {_reply.recycle();_data.recycle();}return _result;}@Overridepublic void addBook(mfy.com.binderdemo.Book book) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);if ((book != null)) {_data.writeInt(1);book.writeToParcel(_data, 0);} else {_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);_reply.readException();} finally {_reply.recycle();_data.recycle();}}}static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);}public java.util.List<mfy.com.binderdemo.Book> getBookList() throws android.os.RemoteException;public void addBook(mfy.com.binderdemo.Book book) throws android.os.RemoteException;
}

可以看到生成的代码中IBookManager继承了IInterface接口,自己也是接口,里面有两个方法,也就是我们在AIDL中定义的方法,还声明了连个整型的id,分别标识这两个方法,这两个id用来标识在transact过车中,客户端所请求的到底是哪个方法。接着声明了一个内部类Stub,这个Stub就是一个Binder类,当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的transact过程,而当两者位于不同的进程时,方法调用需要走transact过程,这个逻辑由Stub的内部代理类Proxy来完成。下面来看没个方法的含义。

DESCRIPTOR

Binder的唯一标识,一般用于当前Binder的类名标识

asInterface(android.os.IBinder obj)

用于将服务端的Binder对象转换为客户端所需要的AIDL接口类型对象,这种转换过程是区分进程,如果客户端和服务端处于同一进程,那么此方法返回的就是服务端的Stub对象本身,否则就返回系统封装后的Stub.Proxy对象

asBinder

此方法用于返回当前Binder对象

onTransact

这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理。该方法的原型为public Boolean onTransact(int code,android.os.Parcel data,android.os.Parcel reply,int flags)。服务端通过code既可以确定客户端所请求的目标方法是什么。当目标方法执行完毕后,就想reply中写入返回值(如果目标方法有返回值的话),onTransact方法的执行过程就是这样得 。需要注意的是,如果此方法返回false,那么客户端的请求会失败,因此我们可以利用这个特性来做权限验证,毕竟我们不希望一个进程都能调用我们的服务。

Proxy#getBookList

这个方法运行在客户端,当客户端远程调用此方法是,他的内部实现是这样得:首先穿件该方法所需要的输入型Parcel对象_data、输出型Parcel对象_reply和返回值对象List;然后把该方法的参数信息写入_data中(如果有参数的话);接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;然后服务端的onTransact方法会被调用,知道RPC过程返回后,当前线程继续执行,并从_reply中取出RPC过程的返回结果;最后返回_reply中的数据

Proxy#addBook

这个方法运行在客户端,它的执行过程和getBookList是一样的,addBook没有返回值,所以不需要从_reply中取出返回值。

通过以上分析,基本了解了Binder的工作机制,但是还有两点需要说明一下:首先,客户端发起远程请求后,由于当前线程会被挂起直至服务器进程返回数据,所以如果一个远程方法是耗时的,那么不能在UI线程中发起此远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采取同步的方式去实现,因为它已经=运行在一个线程中了。


http://chatgpt.dhexx.cn/article/spt9xGfs.shtml

相关文章

Binder机制原理

前言 本篇文章记录本人对Binder的学习&#xff0c;因为本人能力有限&#xff0c;若有错误&#xff0c;还请批评指正。 binder的使用文章推荐 1.Binder是什么&#xff1f; 可以理解是为Android的血管。是一种进程间通信的机制。比如Activity&#xff0c;Service需要和AMS通信…

Binder机制(非常好理解)

Binder是一种进程间通信机制&#xff0c;用来实现不同进程之间的通信。 Binder机制主要由四大块组成&#xff0c;分别是客户空间的client、server&#xff0c;serverManager&#xff0c;还有内核的Binder驱动。 下面我先看下图&#xff0c;利于理解Binder内部工作机制&#x…

Android进程间通信之一:Binder机制学习

Binder机制学习 Binder驱动Binder核心APILinux 使用两级保护机制&#xff1a;0 级供系统内核使用&#xff0c;3 级供用户程序使用。 Linux 下的传统 IPC 通信原理Linux 下的传统 IPC 通信原理Binder通信过程ServiceManager进程启动MMAP Binder驱动 binder驱动在以misc设备进行注…

Android跨进程通信:图文详解 Binder机制 原理

前言 如果你接触过 跨进程通信 &#xff08;IPC&#xff09;&#xff0c;那么你对Binder一定不陌生虽然 网上有很多介绍 Binder的文章&#xff0c;可是存在一些问题&#xff1a;浅显的讨论Binder机制 或 一味讲解 Binder源码、逻辑不清楚&#xff0c;最终导致的是读者们还是无…

操作系统实验五--存储管理

文章目录 操作系统实验五--存储管理一、实验目的二、实验内容三、设计原理及相关算法四、结果分析五、源代码 操作系统实验五–存储管理 一、实验目的 1、了解虚拟存储技术的特点&#xff0c;掌握请求页式存储管理的主要页面置换算法原理。 2、掌握请求页式存储管理中页面置…

操作系统实验—存储管理

操作系统实验—存储管理 所有实验源码&#xff1a; gitee&#xff1a;https://gitee.com/infiniteStars/os-project github&#xff1a;https://github.com/helloworldzsq/OSproject 1.实验内容 设计一个虚拟存储区和内存工作区&#xff0c;并使用下述方法计算访问命中率。 ①…

操作系统实验——磁盘调度算法

文章目录 前言一、实验目的二、实验内容和要求三、实验程序四、运行结果运行结果截图 五、思考和分析程序实现(思路)&#xff1a;分析几种算法&#xff1a; 附 前言 提示&#xff1a;本次实验在Linux(Ubuntu)中运行&#xff0c;程序中读取的文件需放在与c文件同一个文件夹中&a…

北航操作系统实验入门

有北航操作系统实验平台账号的部分读者反映不会操作。为了让读者尽快了解实验平台的操作&#xff0c;下面介绍lab0的实验步骤&#xff0c;希望读者能尽快掌握实验平台的使用方法。 1. 用学生账号登录 2. 点击【操作系统实验】进入实验界面 3. lab0实验环境介绍&#xff0c;仔细…

操作系统实验三进程间通信

文末也可直接获取实验文档 实验三 进程间通信 目录 1实验目的2 实验内容3实验详细操作步骤及程序清单&#xff1a;4相关问题及思考5总结6背景知识 1实验目的 1、了解linux系统中进程通信的基本原理。 2、分析进程竞争资源现象&#xff0c;学习解决进程互斥的方法。 2 实验内…

操作系统实验——进程控制

操作系统实验——进程控制 预习内容&#xff1a; 1.进程的概念 ⑴程序的并发执行 ⑵进程的定义 2.进程的描述 ⑴进程控制块 ⑵进程上下文 ⑶进程上下文切换 ⑷进程空间与大小 3. 进程状态及其转换 ⑴进程状态 ⑵进程状态转换 4.进程控制 ⑴进程创建与撤销 ⑵进程的阻塞与唤醒…

操作系统实验一

操作系统实验一 进程调度算法 一、实验目的 1.理解操作系统进程管理中进行进程调度的过程和调度算法的思想原理&#xff1b; 创建进程控制块PCB&#xff0c;并合理组织就绪队列。 2.理解进程的状态及变化&#xff0c;动态显示每个进程的当前状态及进程的调度情况。 掌握几…

操作系统实验一·创建进程

创建进程 1实验目的2实验内容&#xff1a;2.1Windows实现2.2Linux实现 3实验环境3.1Windows3.2Linux虚拟机 4程序设计和实现4.1Windows实现4.1.1函数解释4.1.2程序代码4.1.3运行结果 4.2Linux实现4.2.1函数解释4.2.2程序代码4.2.3运行结果 Use system calls to implement a “m…

操作系统实验

实验一 命令解释程序 实验内容 利用C语言编写一个微型命令解释程序minishell.c&#xff0c;该程序可接收并解释以下命令&#xff1a; (1) dir 列出当前目录 (2) cop file1 file2 拷贝文件 (3) era filename 删除文件 (4) disp string 显示字符串 (5) end 结束&#xff0c;退出…

操作系统实验报告

操作系统 一、实验一 通过 VMware 虚拟机软件安装 Linux二、实验目的三、实验内容&#xff08;实验原理/运用的理论知识、算法/程序流程图、步骤和方法、关键源代码&#xff09;四、实验结果与分析五、小结与心得体会 一、实验二 Windows 进程管理二、实验目的三、实验内容&…

操作系统实验——银行家算法

文章目录 一、实验目的二、实验内容和要求三、实验原理算法实现 四、实验程序代码如下&#xff1a; 五、验证数据和运行结果运行结果截图 六、思考与分析附 一、实验目的 掌握银行家算法思想&#xff0c;并能编程实现。 二、实验内容和要求 1、在Linux环境下编译运行程序&am…

操作系统实验(进程调度)

操作系统实验&#xff08;进程调度&#xff09; 一、实验目的二、实验内容三、实验准备3.1优先权算法3.2时间片轮转调度算法 四、实验 一、实验目的 1.1理解有关进程控制块、进程队列的概念。   1.2掌握进程优先权调度算法和时间片轮转调度算法的处理逻辑。 二、实验内容 2.1…

【MFC】CCriticalSection类在Release编译下调用Lock函数会报0xC0000008错误

【MFC】CCriticalSection类在Release编译下调用Lock函数会报错0xC0000008 问题描述方法一 CRITICAL_SECTION代替CCriticalSection方法二 使用WaitForSingleObject和ReleaseMutex()结语 问题描述 通过以下伪代码方式描述问题&#xff1a; 主对话框类内创建成员变量及结构体变量…

联合使用类CCriticalSection和类CSingleLock同步线程

&#xff08;1&#xff09;新建一个控制台工程SellTicketTest2&#xff0c;并在向导的“应用程序设置”中勾选“MFC”。 &#xff08;2&#xff09;打开SellTicketTest2.cpp&#xff0c;在开头中引入头文件。 #include "afxmt.h"&#xff08;3&#xff09;添加变量&…

单独使用CCriticalSection对象来同步线程

&#xff08;1&#xff09;新建一个控制台工程SellTicketTest&#xff0c;并在向导的“应用程序设置”中勾选“MFC”&#xff0c;因为CCriticalSection属于MFC类&#xff0c;如图所示。 &#xff08;2&#xff09;在SellTicketTest.cpp开头中引入头文件。 #include "afx…

linux查看java线程死锁_ccriticalsection 多线程 死锁_c++ 线程死锁_linux 线程 死锁

qq_407283393122018-12-10 一个很蠢的造成死锁的问题 wanglt3113172018-12-12 什么是死锁&#xff0c;死锁的原因&#xff0c;如何避免 apanying902019-01-09 c3p0连接死锁 Cain_1507662016-09-20 notify产生死锁的场景(备忘) liuchuanyangyan9132017-02-23 C3P0配置错误导致的…