REFRENCE :https://blog.csdn.net/zhwadezh/article/details/79310119
https://blog.csdn.net/liwei405499/article/details/42775319
一、Binder简介
Binder机制就是一种进程间通信(IPC)的实现方式,在linux中没有。
1、现有的IPC通信机制
管道:在创建时分配一个page大小的内存,缓存区大小比较有限;
消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
共享内存:无须复制,共享缓冲区直接附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
套接字:作为更通用的接口,传输效率低,主要用于不同机器或跨网络的通信;
信号量:常作为一种锁机制,防止某进程正在访问共享资源时,被其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
信号:不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等
2、使用Binder的原因
Android系统是基于Linux系统的,理论上应该使用Linux内置的IPC方式。Linux中的IPC方式有管道、信号量、共享内存、消息队列、Socket,Android使用的Binder机制不属于Linux。Android不继承Linux中原有的IPC方式,而选择使用Binder,说明Binder具有一定的优势。
Android系统为了向应用开发者提供丰富的功能,广泛的使用了Client-Server通信方式,如媒体播放、各种传感器等,Client-Server的通信方式是Android IPC的核心,应用程序只需要作为Client端,与这些Server建立连接,即可使用这些功能服务。
下面通过一些功能点,解释为什么Android选择使用Binder:
从通信方式上说,我们希望得到的是一种Client-Server的通信方式,但在Linux的五种IPC机制中,只有Socket支持这种通信方式。虽然我们可以通过在另外四种方式的基础上架设一些协议来实现Client-Server通信,但这样增加了系统的复杂性,在手机这种条件复杂、资源稀缺的环境下,也难以保证可靠性;
从传输性能上说,Socket作为一款通用接口,其传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信;消息队列和管道采用存储-转发方式,即数据先从发送方拷贝到内存开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程;共享内存虽然无需拷贝,但控制复杂,难以使用;而Binder只需要拷贝一次;
从安全性上说,Android作为一个开放式的平台,应用程序的来源广泛,因此确保只能终端的安全是非常重要的。Linux传统的IPC没有任何安全措施,完全依赖上层协议来确保,具体有以下两点表现:第一,传统IPC的接收方无法获得对方可靠的UID/PID(用户ID/进程ID),从而无法鉴别对方身份,使用传统IPC时只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用;第二,传统IPC的访问接入点是开放的,无法建立私有通信,只要知道这些接入点的程序都可以和对端建立连接,这样无法阻止恶意程序通过猜测接收方的地址获得连接。
基于以上原因,Android需要建立一套新的IPC机制来满足系统对通信方式、传输性能和安全性的要求,这就是Binder。
综上,Binder是一种基于Client-Server通信模式的通信方式,传输过程只需要一次拷贝,可以为发送方添加UID/PID身份,支持实名Binder和匿名Binder,安全性高。Binder机制是Android系统的核心机制,几乎贯穿于整个Android系统,Android系统基本上可以看作是一个基于binder通信机制的C/S架构,Binder就像网络,把Android系统的各个部分连接到了一起。
二、Binder
1、IPC原理
从进程角度来看IPC机制
每个Android的进程,只能运行在自己进程所拥有的虚拟地址空间。对应一个4GB的虚拟地址空间,其中3GB是用户空间,1GB是内核空间,当然内核空间的大小是可以通过参数配置调整的。对于用户空间,不同进程之间彼此是不能共享的,而内核空间却是可共享的。Client进程向Server进程通信,恰恰是利用进程间可共享的内核内存空间来完成底层通信工作的,Client端与Server端进程往往采用ioctl等方法跟内核空间的驱动进行交互。
2、Binder结构
(1)Binder通信架构
从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。架构图如下所示:
Binder通信是一种client-server的通信结构,
1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;
2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;
3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;
4.代理接口将该Parcel发送给内核中的binder driver.
5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;
6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。
(2)Binder通信的四个角色
Client进程:使用服务的进程。
Server进程:提供服务的进程。
ServiceManager进程:ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
Binder驱动:驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
3、Binder实现
Binder的实现主要有以下几个部分:
(1)、注册服务:Server进程要先注册Service到ServiceManager。该过程:Server是客户端,ServiceManager是服务端。
(2)、获取服务:Client进程使用某个Service前,须先向ServiceManager中获取相应的Service。该过程:Client是客户端,ServiceManager是服务端。
(3)、使用服务:Client根据得到的Service信息建立与Service所在的Server进程通信的通路,然后就可以直接与Service交互。该过程:client是客户端,server是服务端。
Binder架构图中的Client,Server,Service Manager之间交互都是虚线表示,是由于它们彼此之间不是直接交互的,而是都通过与Binder驱动进行交互的,从而实现IPC通信方式。其中Binder驱动位于内核空间,Client,Server,Service Manager位于用户空间。
下面我们将结合源码对以上三个部分分别进行分析
三、源码分析
我这里是Android6.0的源码。这里以MediaService为例进行分析。
1、注册服务
MediaService是一个应用程序,其源码位置如下:
frameworks\av\media\mediaserver\main_mediaserver.cpp
int main(int argc __unused, char** argv)
{
.....
.....
sp<ProcessState> proc(ProcessState::self());//获得一个ProcessState实例
sp<IServiceManager> sm = defaultServiceManager();//得到一个ServiceManager对象
//实际上返回一个BpServiceManager对象
MediaPlayerService::instantiate();//初始化MediaPlayerService服务
ProcessState::self()->startThreadPool();//启动Process的线程池
IPCThreadState::self()->joinThreadPool();//将自己加入到刚才的线程池
}
}
我的理解:注册服务的大概流程就是server先获取一个BpBinder对象,然后该对象与ServiceManager取得联系即获取BpServiceManager对象,然后将自己的服务加到ServiceManager的服务list上去。然后ServiceManager一直loop等待client来请求服务,同时该server也loop等待Binder Driver 传来请求数据,执行并返回结果。
1.1 ProcessState::self()
第一个调用的函数是ProcessState::self(),然后赋值给了proc变量,程序运行完,proc会自动delete内部的内容,所以就自动释放了先前分配的资源。
ProcessState位置在frameworks\native\libs\binder\ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);//锁保护
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;//创建一个ProcessState对象
return gProcess;
}
我们看看ProcessState的构造函数
ProcessState::ProcessState()//ProcessState构造函数
: mDriverFD(open_driver())//open_driver()返回fd,打开binder驱动
, mVMStart(MAP_FAILED)//映射内存的起始地址
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
//这个需要你自己去查mmap的用法了,不过大概意思就是
//将fd映射为内存,这样内存的memcpy等操作就相当于write/read(fd)了
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}
#else
mDriverFD = -1;
#endif
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
open_driver(),就是打开/dev/binder这个设备,并且返回一个fd赋值给mDriverFD
static int open_driver()
{
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers = 0;
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol does not match user space protocol!");
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//通过ioctl告诉内核这个,
//这个fd支持最大线程数是15个。
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
return fd;
}
好了,到这里Process::self就分析完了,到底干什么了呢?
1 打开/dev/binder设备,这样的话就相当于和内核binder机制有了交互的通道
2 映射fd到内存,设备的fd传进去后,估计这块内存是和binder设备共享的
接下来就是 defaultServiceManager();
1.2 defaultServiceManager()
接下来就是 defaultServiceManager();
defaultServiceManager位置在frameworks\native\libs\binder\IServiceManager.cpp中
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
//真正的gDefaultServiceManager是在这里创建的
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
//ProcessState::self()->getContextObject(NULL)=new BpBinder(0)
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
首先是 ProcessState::self()->getContextObject(NULL),这里的参数是NULL,我们来看看ProcessState类的成员函数getContextObject()的实现。
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);//返回一个IBinder类型的对象,实际上是BpBinder类型的
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
// Special case for context manager...
// The context manager is the only object for which we create
// a BpBinder proxy without already holding a reference.
// Perform a dummy transaction to ensure the context manager
// is registered before we create the first local reference
// to it (which will occur when creating the BpBinder).
// If a local reference is created for the BpBinder when the
// context manager is not present, the driver will fail to
// provide a reference to the context manager, but the
// driver API does not return status.
//
// Note that this is not race-free if the context manager
// dies while this code runs.
//
// TODO: add a driver API to wait for context manager, or
// stop special casing handle 0 for context manager and add
// a driver API to get a handle to the context manager with
// proper reference counting.
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
b = new BpBinder(handle); //创建一个BpBinder对象
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
接下来我们看看BpBinder(handle),handle值为0,位置在frameworks\native\libs\binder\BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()