Android系统篇之—-Binder机制和远程服务调用机制分析



转载于:http://www.wjdiankong.cn/android系统篇之-binder机制和远程服务调用机制分析java


1、前景概要

最近要实现Android中免注册Activity就能够运行的问题,那么结果是搞定了,就是能够不用在AndroidManifest.xml中声明这个Activity便可运行,主要是经过骗取系统,偷龙转凤技术的,这个知识点后面会详细讲解的,由于在研究了这个问题过程当中遇到了不少知识点,固然最重要也是最根本的就是Android中的Binder机制和远程服务调用机制,而关于Binder机制的话,在Android中算是一个很是大的系统架构模块了,光这篇文章是确定不能讲解到所有的,并且本人也不是很是的熟悉Binder机制,只是发表我的的理解,而且会用最简单的语言讲解最核心的知识,由于如今有不少知识都在介绍Binder机制,可是大部分说的都太抽象了大部分都看不懂。android

2、具体需求

接下来几篇主要是介绍关于Android中的应用启动流程,经过Hook机制拦截Activity的启动流程,达到咱们想要的功能,同时能够实现Activity无需在AndroidManifest.xml中声明便可运行的效果。api

3、Android中远程服务调用分析

咱们若是作过多进程之间通讯的话都了解远程服务的使用了,使用也是很是简单的,下面来看一下如何定义本身的远程服务:缓存

一、定义一个AIDL文件安全

相似于定义接口类型,这个AIDL文件将在本地和远端都要使用到数据结构


二、定义远端服务架构

在远程服务中的onBind方法,实现AIDL接口的具体方法,而且返回Binder对象函数


三、本地建立链接对象工具

本地建立一个服务链接对象,实现ServiceConnection接口,在链接成功以后,会获得一个远端传递过来的Binder对象,就是上面的远端服务onBind方法返回的,获得Binder对象以后在进行转化就能够获得AIDL对象,而后便可调用方法spa


四、链接服务

链接服务也是比较简单的,这时候把上面的链接对象传递进去便可


到这里咱们就看到完成了本地端和远端的通讯了,若是把DemoService远端服务定义在另一个进程中,那么这里就能够实现多进程通讯了。看到上面的步骤很简单,可是有一个核心的地方就是Demo.Stub类,这个类起着重要的做用,下面来分析一下他的实现,每次定义了AIDL接口文件以后,编译一下就会在gen目录中产生对应的java文件了:


这里的实现稍微有点复杂了,可是这些内容其实都是编译工具帮咱们实现的,而这个实现都是有必定规则的:

一、AIDL接口必须实现IInterface接口

关于IInterface接口的实现也很简单:


这里能够把当前的AIDL对象转化成一个IBinder类型对象

二、AIDL接口中确定有一个静态实现类Stub

这个类必须实现Binder类,以及自己的AIDL接口类型。那么这个类就具有了Binder类中的四个功能:

1》能够将Binder对象转化成AIDL对象,调用asInterface方法,能够看到这个方法其实和上面的asBinder方法对立的

2》通讯方法onTransact实现,这个方法是最核心的用于通讯之间的逻辑实现

3》经过queryLocalInterface方法能够根据类的描述符(字符串能够惟一标识这个远端服务的名称便可)获取到对应的AIDL对象(实际上是IInterface类型的)

4》在构造方法中必须调用Binder中的attachInterface方法把当前服务对象和描述符进行关联

上面看完了Stub类以后,发现他实际上是远端服务Binder对象的一个中间者,用来和客户端进行交互的,下面再来看一下Proxy类:


这个代理对象其实就是远端传递过来Binder对象的一个代理,他是客户端这边用户和服务端交互的中间者。咱们在前面的Stub类中能够看到:


这里会把远端传递过来的Binder对象转化成一个本地对象,发现先是经过queryLocalInterface方法借助服务描述符来获取对象:


而这个mOwner和mDescriptor之间的关系就在attachInterface方法中进行初始化的,也就是在Stub类的构造方法中


那么如今就清楚了,若是客户端和服务端是在一个进程中,那么其实queryLocalInterface获取的就是Stub对象,若是不在一个进程queryLocalInterface查询的对象确定为null,由于不一样进程有不一样虚拟机,确定查不到mOwner对象的,因此这时候实际上是返回的Proxy对象了。经过上面的讲解以后,发现多进程服务通讯基准就是借助Binder对象,先传递Binder对象,而后在把Binder转成可使用的原生对象便可调用了,而对于Stub类和Proxy类其实就是至关因而服务端和客户端的中间者,把一些逻辑封装起来,这种设计也会显得不是那么凌乱:

Stub类是服务端的中间者,通常是实现了AIDL接口类型和继承了Binder类,具有将Binder对象转化成原生对象的能力

Proxy类是客户端的中间者,通常是实现了AIDL接口类型


4、分析系统服务调用流程

这种图就够形象了,因此后面会看到系统中的一些服务使用的时候其实也是跨进程使用,好比下面来看一下著名的PackageManager,IPackageManager,PackageManagerService体系:


这个就是IPackageManager.aidl文件,由于咱们尚未编译源码,因此这里可能须要AIDL工具单独编译才能看到IPackageManager.java了:


这里看到了熟悉的远端服务中间者Stub和本地端的中间者Proxy类了,而这两个类的规则都和上面同样的。

下面来看一下远端服务实现代码PackageManagerService.java:


实现了上面的的Stub类功能。

下面咱们再走一遍获取PackageManager的流程:


而这个getPackageManager方法是在ContextImpl.java中实现的:


看到了吧,这里先从ServiceManager的getService中获取到一个PackageManager远端的IBinder对象,而后在使用Stub的asInterface方法进行转化成本地的PackageManager对象,其实就是那个Proxy对象。而后就能够经过PackageManager来调用方法和远端的PackageManagerService服务进行通讯了。

经过上面的PackageManager案例能够分析,咱们在使用系统中的服务的时候的流程都是如此:


每一个应用在使用系统服务的时候,都会走这么几步:

一、调用getSystemService(String serviceName)方法获取服务对象

二、而getSystemService通常都是在ContextImpl类中实现的,实际上是调用了ServiceManager的getService方法

三、调用ServiceManager的getService方法获取远端服务的IBinder对象

四、有了远端服务的IBinder对象以后,在使用远端服务的中间者类Stub进行转化对象asInterface方法

五、由于系统中的服务获取都是确定是跨进程的,远端服务都是在system_server进程中的,因此asInterface方法中返回的是Proxy代理对象,也就是本地端的中间者。

六、最后返回的对象其实就是这个Proxy对象,而这个对象内部使用了静态代理方式,内部有一个来自远端的mRemote变量即IBinder对象。而后直接调用方法其实就是调用mRemote的transact方法进行通讯了。

因此在这个过程当中能够看到有两个对象很重要,一个是ServiceManager,一个是IBinder对象。下面再来一一介绍

5、服务大管家ServiceManager

那么如今又有几个问题了,这个ServiceManager是干吗的?如何可以经过服务描述符就能够获取到对应服务的IBinder对象?这个就要看一下ServiceManager的功能了:

首先看看他获取远端服务的IBinder对象方法,他自己会维护一个IBinder缓存池,也是为了效率高考虑,对于一个应用频繁的使用一些服务的话效率就会高不少。


而后最核心的获取服务的方法是getIServiceManager方法:


这个方法看到了,又是一个远程通讯获取Binder对象,而此次是IServiceManager对象了:


看到这里的ServiceManager也是经过远端服务获取到他的IBinder对象,而后在转化成本地对象进行使用的。那么刚刚看到系统的服务都是经过ServiceManager管理获取的,而如今ServiceManager自己是怎么获取到的IBinder对象的呢?这个就要从系统启动的时机看了,众所周知系统启动的时候是根据init.rc文件进行操做的:


这里会启动一个servicemanager服务,那么就要去service_manager.c程序中的入口程序看了:


这个入口其实包含了Binder机制的重要信息,而主要就是三件事:

一、打开底层的Binder驱动程序,这个后面介绍Binder机制在介绍

二、经过向binder程序发送命令:BINDER_SET_CONTEXT_MGR,告诉binder程序,我要成为大管家

三、进入循环监听上层应用的服务请求处理,因此这里能够看到其实ServiceManager是一个守护进程在后台默默监听

在第二步中成为大管家的代码深刻看一看:


其实这里的逻辑也是比较简单的,首先建立一个属于servicemanager的binder节点,而后在建立一个binder链表,而这个链表的做用就是存放上层中须要系统服务的全部binder对象的节点,这样ServiceManager就能够实现了服务的增长和查询操做了。

再来看看ServiceManager的添加服务操做:


添加服务比较复杂,首先查看这个服务有没有注册权限限制,不是全部的服务都能注册的,而后在查看这个服务是否是已经被注册过了,最后在通知binder驱动程序注册一个服务便可。

而后在来看看ServiceManager的查找服务功能:


查找服务就比较简单了,直接经过服务的描述符名称遍历binder链表节点便可。

一、Service Manager能集中管理系统内的全部服务,它能被施加权限控制,并非任何进程都能注册服务的。
二、Service Manager支持经过字符串名称来查找对应的Service。
三、因为各类缘由的影响,Server进程可能生死无常。若是有了Service Manager作统一的管理,那么Client只要向Service Manager作查询,就能获得Server的最新信息。

6、系统服务注册流程分析

下面来看一下一些系统服务是如何进程注册的,这里用MediaService来进行查看吧:

系统中的MediaService服务的启动也是在init.rc中的


查看main_mediaserver.cpp源码的main函数:


看到了系统的MediaServer依赖不少其余服务的,而这些服务必需要注册的,他们的注册操做都是在各自的初始化方法中的,这里用MediaPlayerService来看看注册操做:


看到熟悉的代码了把,这里经过ServiceManager来进行服务注册了,那么这里是如何获取到ServiceManager的?


看看ProcessState.cpp的源码:


看看getStrongProxyForHandle方法实现:


这里看到了,会使用IPCThreadState的transact方法和底层的Binder进行通讯的,而后使用一个句柄handle构造一个BpBinder对象,而BpBinder对象其实就是native层实现的Binder对象,之后只要看到Bp开头的就是代理对象对应Java层的Proxy对象,Bn开头的就是native对象对应Java层的Stub对象。

在上面分析servicemanager的时候知道会维护一个binder节点链表,那里其实就有一个每一个binder对应句柄handle,然后续进行通讯的话都是经过这个句柄来标识是哪一个服务的binder对象了,这样也就在通讯的时候不会发生紊乱了,而servicemanager的句柄handle就是0。还有一个知识点就是能够看到IPC通讯的时候传输数据使用的就是Parcel类,这个类就是为了跨进程通讯产生的,他有一个方法readStrongBinder,就是能够从Parcel的数据中获取到Binder对象,这个也是在跨进程中传递Binder对象的核心地方。


好了,上面就经过系统的mediaserver服务来说解了系统服务的注册流程:


到这里就分析完了Android中的远程服务调用机制逻辑以及ServiceManager这个服务大管家的做用:


一、首先跨进程通讯的话,确定会有两个对象:一个是本地端的中间者Proxy对象,一个是远程端的中间者Stub对象

二、Proxy对象经过静态代理模式维持一个远端传递过来的Binder对象,而Stub对象能够把远端传递过来的Binder对象转化成一个实际服务对象给应用使用

三、Android中在使用系统服务的时候经过getSystemService方法获取到的其实都是Stub把远端的Binder转化的对象,由于系统服务都是在system_server进程中,因此确定是跨进程获取对象的,那么这个Binder对象其实就是上面的Proxy对象

四、系统的服务都是在一个指定的系统进程中system_server

五、服务大管家ServiceManager在系统启动的时候也是先获取自生的Binder对象,而后转化成实际操做对象,而后才能够操做系统服务的注册和查询功能

下面是系统一些服务的注册流程:


上面已经介绍了远程五福调用机制以及ServiceManager的实现原理,下面就要看看另一个重点,也是上面提到的一个重要对象Binder,准确来讲这个是Binder机制,在Android中Binder机制最复杂的一个架构系统了,它的设计很复杂,因此有不少同窗在了解Binder机制的时候,老是看着看着就晕了,今天咱们就直说重点,并且说得要相对明了简单。

7、Binder机制解析

第1、Android中的IPC为什么要采用Binder机制

Binder是Android系统进程间通讯(IPC)方式之一。Linux已经拥有的进程间通讯IPC手段包括(Internet Process Connection):管道(Pipe)、信号(Signal)和跟踪(Trace)、插口(Socket)、报文队列(Message)、共享内存(Share Memory)和信号量(Semaphore)。

Binder基于Client-Server通讯模式,传输过程只需一次拷贝,为发送发添加UID,PID身份,既支持实名Binder也支持匿名Binder,安全性高。对Binder而言,Binder能够当作Server提供的实现某个特定服务的访问接入点, Client经过这个‘地址’向Server发送请求来使用该服务;对Client而言,Binder能够当作是通向Server的管道入口,要想和某个Server通讯首先必须创建这个管道并得到管道入口。

第2、Android中的Binder实现原理

其实Android中的Binder通讯都是经过虚拟驱动设备程序/dev/binder来实现的,咱们知道一些硬件都会对应一个驱动程序,而binder驱动程序没有对应的硬件,因此叫作虚拟驱动设备程序,其实他就是一个字符驱动设备,或者叫作miscdevice混杂设备驱动。

其实混杂驱动设备是字符设备的一种,它们共享一个主设备号(10),但次设备号不一样,全部的混杂设备造成一个链表,对设备访问时内核根据次设备号查找到相应的miscdevice设备。例如:触摸屏,LED,按键,串口。即:为了节约主设备号,将某些设备用链表的形式链接在一块儿,最后经过查找次设备区分。这里用主设备没法匹配出设备驱动,只能找到链表,再经过次设备号,才能找到设备驱动。而以前所学的,通常字符设备,经过主设备号,就能找到设备驱动了。咱们能够经过命令查看/dev/binder驱动的主设备号:


第3、Android中Binder通讯机制

先来看一张图,咱们能够大致的了解到了客户端和服务端经过Binder驱动进行通讯


首先无论是客户端进程仍是服务端进程都是在用户空间的,而binder驱动是在内核空间的,通讯的数据是有规定格式也叫做IPC数据,既然是一种通讯机制,确定是须要协议,数据格式等基础结构信息的:


上面在分析了ServiceManager的启动的时候说到了,第一步是打开驱动程序,具体打开函数在binder.c中:


在使用一个驱动以前,确定要先打开驱动,而后把驱动程序映射到内存中,接着借助IPCTreadState.cpp和binder驱动进行通讯了:


因此看到这里IPCThreadState也是须要进入后台进行监听的,处理来自客户端和服务端的数据传输消息


最后再来看一下通讯时序图。

到这里咱们就介绍完了Binder机制了,关于Binder机制最好不要看太深,由于越深你以为越复杂越难理解,其实你只要了解到他是一个通讯工具,通讯采用的是驱动操做,经过传输IPC数据来进行通讯便可。其余的关于他的详细数据格式和通讯协议,感兴趣的同窗能够了解一下,可是太过复杂并且在实际中也没多大用途,因此这里就不介绍了。

8、技术点概要

一、理解远程服务通讯机制

经过案例先了解到本地端和服务端跨进程通讯,主要就是借助Binder进行功能调用,而在这里主要有两个核心类,一个是Stub类,这个类是继承了Binder类具有了将远程传递的Binder对象转化成本地实际对象asInterface方法便可,同时实现了IXXX接口,须要实现AIDL中的功能方法,还有一个类就是Proxy类,实现了IXXX接口,同时内部保留着远端传递的Binder对象,而后经过这个对象调用远端方法。这里Stub类就是服务端的中间者,而Proxy就是本地端的中间者。

二、系统服务调用流程

经过分析了跨进程通讯机制原理以后,再去看看Android系统中在使用一些服务的时候,经过getSystemService方法获取服务对象,其实这内部就是经过跨进程获取到了远端服务的Binder对象,而后转化成系统服务对象给应用调用,而这些系统服务的Binder对象在系统启动的时候服务会自动注册到ServiceManager中。

三、服务大管家ServiceManager

在整个远程服务调用过程当中两个重要对象,一个是Binder对象,一个就是ServiceManager类,这个类是管理系统服务的类,他能够注册服务,查询服务,系统服务在系统启动的时候会经过addService进行服务注册,而后应用就能够经过getService进行服务查询,而在这个过程当中,底层会维护一个这些服务的binder链表结构,同时每一个服务的binder对象都一个句柄handle,经过这个句柄来表示通讯标识,这样通讯才不会紊乱。

四、底层通讯核心Binder

最后分析了底层真正实现跨进程通讯的机制Binder,实际上是经过虚拟驱动程序/dev/binder进行通讯的。一个通讯机制确定有通讯协议,传输的数据结构,可是这里并无介绍这些知识,缘由是咱们后面的需求并不会用到这些,其次是这些知识点太详细介绍也很差,由于会越看越乱。

9、总结

本文介绍的东东有点多,可是若是掌握了Android中的Binder机制和远程服务调用机制对后面拦截系统api作了铺垫,说到结束了才告诉你们为何要介绍这个知识点,是由于最近在研究如何拦截系统启动Activity的事,那么就必须了解Activity的启动流程,可是在这个过程当中有一个对象就是ActivityManagerService,而他就和Binder以及远程服务调用机制紧密联系了,若是不了解Binder机制,后面工做是没办法进行的,好了,说到最后再来一张神图算是总结了本文内容:


这张图很是好的表达了Android中应用使用系统服务的一个流程,也是最好的最全的解释了。看懂这张图以后,那么对Android中的binder机制和远程服务调用机制就能够掌握了,能够进行后续的拦截操做了。