Binder是一个很大的话题,里面涉及到java、c/c++、linux等知识,并且核心是位于native层的c/c++编写的代码,想要弄清楚整个Binder机制的来龙去脉不看native层的代码是不可能的。而对于一个看不懂c/c++的Android开发者而言,要理清Binder的机制更是难上加难。幸好网上关于Binder的资料还是挺多的,这里推荐老罗的Android之旅的Binder系列、书籍【深入理解Android内核的设计思想】、Android Binder设计与实现 - 设计篇。Binder设计与实现全程没有一行代码但讲解非常通透,不过要清楚的知道Binder整个执行流程避免不了要看代码;老罗的Binder系列讲解和源码分析面面俱到,但是细节太多太详细,没有一定的c/c++功底很难啃的下去;相对而言,【深入理解Android内核的设计思想】的Binder章节更友好(至少对我),从设计者的角度出发去思考问题并辅于源码的分析,让人很容易进入感觉,有自己的节奏。
本文将从Android开发者的角度出发,只为弄清楚从Client端发起请求到Server响应请求整个执行流程,不会对c/c++的细节作细究。c/c++代码实在看不懂的,多看几遍,混个熟脸,再看就会比较有感觉了。
下面将会从以下四点展开分析
1.获取ServiceMananger远程接口的过程
2.调用ServiceMananger.addService过程
3.调用ServiceMananger.getService过程
4.Server的onTransact响应过程
读完本文,你应该会得到以下的收获:
.对Binder机制它的整体流程应该有了比较清晰的了解
.Binder对象可以跨进程传输到底是什么意思
.Parcel在其中扮演的角色
.最简单的APP进程也至少包含Binder_1、Binder_2线程,这两个线程是怎么来的
先来看一下Binder的通讯模型,对Binder机制的几个角色有个大概的了解。
Binder的通讯模型:Server、Client、ServiceManager、Binder驱动。
Server:提供服务的一方,这个是我们自己要实现的,但系统中也存在了一些已经实现了的Server,例如AMS、WMS等等。
Client:使用服务的一方
ServiceManager:服务的管理者,提供注册和查询等功能。Server启动后向ServiceManager注册,ServiceManager保存着【名称字符串,Server引用】的对应关系,Client通过该字符串查询得到Server的引用,从而使用Server的服务。注意,这里说的ServiceManager是用c实现的,和ServiceManager.java不是一个概念,ServiceManager.java只是一个封装类。
Binder驱动:通常Server和Client是位于不同的进程中,由于进程的隔离,Client和Server是无法直接访问到对方的虚拟内存地址的。什么意思呢?每个进程都有自己的一套虚拟地址空间,一个虚拟地址在进程A中映射到一块内存,而同一个虚拟地址在进程B中映射的是另外一个内存,同一个虚拟地址在不同进程中代表的是不同的内存,因而进程A和进程B是无法直接通信的。想要通信,得借助Binder驱动。虽然每个进程都有自己的一套虚拟地址空间,但有那么一段是大家共用的,这段地址映射的到是同一段内存,这段虚拟地址是留给内核使用的,而Binder驱动就是实现在内核中的。因此Binder驱动既可以访问到Client进程,也可以访问到Server进程,那么使用Binder当做Client和Server的传话筒就最合适不过了。
本文不打算分析Binder驱动和ServiceMananger的源码,一来是篇幅收不住;二来是这两者对于Android开发者是不可见的。当然我们也不能打无准备的仗,下面总结一下Binder驱动和ServiceMananger在Binder机制中的职责所在。
.Client、Server、ServiceMananger之间的通信需要借助Binder驱动
.Server向ServiceMananger注册(addService),传递给Binder驱动的是Server的内存地址(当然也包括字符串name等),Binder驱动会为这个Server(Binder实体)生成一个句柄值,并维护这个句柄值与该Server之间的关系,并把这个句柄值传递给ServiceMananger,而ServiceMananger维护的是字符串name与这个句柄值之间的关系
.Client获取Server的远程接口(getService),传递字符串name给Binder驱动,Binder驱动传递name给ServiceMananger,ServiceMananger查询name对应的句柄值返回给Binder驱动,Binder驱动根据根据这个句柄找到对应的Server,然后重新生成一个句柄值返回个Client,当然Binder驱动也会维护这个新的句柄值与Server之间的关系,因此Client得到的其实只是一个32位的句柄值。
.Client使用Server的服务,传递句柄和方法编号给Binder驱动,由Binder驱动唤醒句柄对应的Server并传递方法编号给Server,Server执行相应的方法并返回结果。
.进程是通过ioctl(fd, cmd, arg)函数实现与Binder驱动的交互,其中cmd是命令,arg是数据。其中最常用的命令为BINDER_WRITE_READ,该命令向Binder写入或读取数据,参数arg为结构体binder_write_read。
明白了ServiceMananger和Binder驱动的职责,我们就可以不用过多的关注Binder驱动和ServiceMananger的源码,我们重点放在Client端的请求发起的流程和Server端的响应流程就可以了。
先来看一段service_manager的源码,了解一下作为一个Server(ServiceMananger也是一个Server)它应该是怎样子的。ServiceManager是独立运行在一个进程中的,Server要向ServiceManager注册,这其中也是进程间的通信,也是要用到Binder驱动的
service_manager.c
int main(int argc, char **argv)
{
struct binder_state *bs;
bs = binder_open(128*1024);
...
binder_loop(bs, svcmgr_handler);
return 0;
}
binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
...
for (;;) {
...
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
...
}
}
ServiceManager启动后会执行main方法,在main方法中会执行binder_open打开binder驱动,然后调用binder_loop进入循环;在binder_loop中,有一个for的死循环,在循环中调用ioctl从binder驱动中获取消息,如果没有消息会进入睡眠;如果有请求消息到来,就会被Binder驱动唤醒,然后调用binder_parse进行处理。
嗯,作为一个Server应该就是这样子的,但是我们在实现自己的Server的时候好像并不需要实现一个for循环然后从Binder驱动读取消息也能实现作为一个Server的功能被Client访问的?是的,因为一个进程中可能有很多这样的Server,如果每个Server都要自己实现这样一个功能那就太麻烦了,我们只需要在进程的层面实现这样的一个功能,由进程去跟Binder驱动打交道,然后分发给不同的Server去处理就好了,这个过程在第4点Server的onTransact响应过程中会有分析。
1.获取ServiceMananger远程接口的过程
从结果上讲,获取ServiceMananger远程接口和获取Server远程接口(getService)是一样的,因为ServiceMananger也是一个Server。只不过要获取Server的远程接口,首先要获得ServiceMananger的远程接口。
在java端是如何获取ServiceMananger远程接口的呢?没错,Server通过ServiceManager.addService(“name”,new Server())向ServiceManager注册自己之前,是通过getIServiceManager() 获得ServiceMananger远程接口的。
ServiceManager.addService
public static void addService(String name, IBinder service) {
try {
getIServiceManager().addService(name, service, false);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
ServiceManagerNative.asInterface
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
我们知道,想要跟Server通信,就要首先获得这个Server的远程接口,其实这个远程接口是指什么呢?个人理解是指这个IBinder对象。而从前面分析知道Client进程从Binder驱动得到的是一个32位的句柄,那么这个IBinder对象应该是根据这个句柄创建出来的一个对象了。
跟踪过startActivity过程或者熟悉AIDL的应该对ServiceManagerNative.asInterface这个格式的代码很熟悉了。简单说一下,首先得到一个Server的远程接口IBinder,然后通过asInterface得到一个XXXProxy对象,XXXProxy实现了和Server一样的接口,因此访问XXXProxy就好像访问Server一样。
这里关键是要理解这个IBinder参数 obj。这里我们是通过BinderInternal.getContextObject()得到这个IBinder对象的,而通过ServiceManager.getService(“”)得到的也会是一个IBinder对象,这个IBinder对象其实就是代表了远端的Server(也就是远程接口),所有对XXXProxy的调用,最终都会通过这个IBinder对象的transact方法访问到远程的Server。
现在来分析BinderInternal.getContextObject()
BinderInternal:getContextObject
public static final native IBinder getContextObject();
getContextObject是一个JNI方法,实现在android_util_Binder.cpp中
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
这里分两步,第一步通过ProcessState.getContextObject获得一个c++层的IBinder对象,然后通过javaObjectForIBinder将这个IBinder对象转化成java层使用的IBinder对象。
ProcessState.getContextObject
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
...
handle_entry* e = lookupHandleLocked(handle);
...
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
...
e->refs->decWeak(this);
}
}
return result;
}
可以看到,得到的c++层的IBinder对象的实际类型是BpBinder,注意了,这里handle传进来的值是0。前面说过,通过BinderInternal.getContextObject()和ServiceManager.getService(“”)得到的都是一个IBinder对象,代表着远程的Server,那么BinderInternal.getContextObject()得到的IBinder代表的是ServiceMananger,而ServiceManager.getService(“”)得到的IBinder代表的是其它的Server对象。而这两种方法得到的IBinder对象都是通过getStrongProxyForHandle构造出来的,getService的流程下面会分析,他们不同的地方只有这个handle的值。前面说了Client从Binder驱动得到的是一个句柄,这里的handle就是这个句柄,getStrongProxyForHandle就是根据句柄创建一个c++层的IBinder对象,最终会转换为java的IBinder对象返回给java层。而ServiceManager这个Server比较特殊,它并没有在ServiceManager中注册自己,它在各个Client进程中的句柄固定为0。
现在来看看是如何将一个c++的IBinder转化成java的IBinder的
android_util_binder.cpp:javaObjectForIBinder
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
...
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
...
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
...
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
...
}
return object;
}
这里就是通过NewObject生成一个BinderProxy对象的,这个gBinderProxyOffsets是什么东西呢?我们把它当成记录着BinderProxy类的信息的东西就好,例如gBinderProxyOffsets.mClass就表示BinderProxy的Class,gBinderProxyOffsets.mObject就表示BinderProxy的成员变量mObject。这样就清楚了,通过javaObjectForIBinder,会根据一个BpBinder的对象创建出一个java层的BinderProxy对象,而这个BpBinder对象的地址保存在BinderProxy的成员变量mObject中(通过SetLongField)。
总结一下:Clinet在获取Server的远程接口的时候会得到一个句柄(从Binder驱动得到或者是0),然后再在Client的进程中根据这个句柄构造一个BpBinder对象,最后创建出一个相对应的BinderProxy对象返回给java层。而ServiceManager对应的句柄在各个Cilent中都统一为0,这个句柄是不需要额外通过进程间通信得到的。
2.调用ServiceMananger.addService过程
ServiceManagerProxy:addService(“name”,new Server())
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
...
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated ? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
获得ServerMananger的远程接口后就可以调用addService将Server纳入ServerMananger的管理,方便以后Client端以字符串的形式查询到Server,使用Server的服务。
这里有两个知识点,1.Parcel的作用 2.mRemote.transact的过程
Parcel可以理解为数据的载体,通过传输,Parcel携带着数据来到进程的边界,另外一个进程通过读这个Parcel的内容取出数据。我们所说的Binder对象可以跨进程传输,就是将Binder对象写入Parcel,然后另外一个进程从这个Parcel读取Binder(当然实际传输的只是这个Binder实体的地址)。Parcel就是通过writeStrongBinder方法将一个Binder对象写入的。
先来看看Parcel的构造方法
public final class Parcel {
...
private long mNativePtr; // used by native code
...
private Parcel(long nativePtr) {
if (DEBUG_RECYCLE) {
mStack = new RuntimeException();
}
...
init(nativePtr);
}
...
private void init(long nativePtr) {
if (nativePtr != 0) {
mNativePtr = nativePtr;
mOwnsNativeParcelObject = false;
} else {
mNativePtr = nativeCreate();
mOwnsNativeParcelObject = true;
}
}
...
}
android_os_Parcel.cpp:android_os_Parcel_create
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel();
return reinterpret_cast<jlong>(parcel);
}
可以看到,Parcel对象在c++层有个Parcel对象对应着,c++层的Parcel的地址保存在java层Parcel对象的成员变量mNativePtr中
java层Parcel的writeStrongBinder也是简单的调用了c++层Parcel的writeStrongBinder
android_os_Parcel
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
在调用c++层Parcel的writeStrongBinder前先将java层的IBinder对象通过ibinderForJavaObject转换为c++层的IBinder对象。
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
...
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL;
}
...
return NULL;
}
因为后面还会用到这个gBinderOffsets,因此先来解释一下gBinderOffsets,gBinderOffsets和前面分析过的gBinderProxyOffsets作用是一样的,只不过gBinderProxyOffsets记录的是BinderProxy的信息,而gBinderOffsets记录的是Binder的信息
static struct bindernative_offsets_t
{
// Class state.
jclass mClass;
jmethodID mExecTransact;
// Object state.
jfieldID mObject;
} gBinderOffsets;
gBinderOffsets有三个变量,记录着Binder对应的三种信息
const char* const kBinderPathName = "android/os/Binder";
static int int_register_android_os_Binder(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kBinderPathName);
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie(
env, kBinderPathName,
gBinderMethods, NELEM(gBinderMethods));
}
可以看到,gBinderOffsets.mClass就是Binder的Class,gBinderOffsets.mExecTransact就是Binder的execTransact方法,gBinderOffsets.mObject就是Binder的mObject变量。那么ibinderForJavaObject代码的意思是从java层的IBinder对象中取出它的成员变量mObject强制转换为JavaBBinderHolder对象,然后再调用JavaBBinderHolder的get方法返回的一个c++层的IBinder对象。那就看看java层的IBinder对象是什么时候给mObject赋值的。
IBinder是一个接口,它有个基本的实现类Binder类,通常Server都是继承这个Binder类然后实现自己的业务逻辑。
Binder.java
public class Binder implements IBinder {
...
public Binder() {
init();
...
}
private native final void init();
进入android_util_binder.cpp的android_os_Binder_init
static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();
...
env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
}
class JavaBBinderHolder : public RefBase
{
}
这里可以看到在Server初始化的时候在基类Binder的构造方法里生成了一个c++层的JavaBBinderHolder对象,并将这个对象的地址保存在了成员变量mObject里。
那就接着看这个JavaBBinderHolder的get方法
class JavaBBinderHolder : public RefBase
{
public:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
mBinder = b;
}
return b;
}
class JavaBBinder : public BBinder
{
}
这里可以看到c++层的IBinder对象的实际类型是JavaBBinder,而JavaBBinder又是继承BBinder类的,并且这个java层的Binder对象保存在这个JavaBBinder对象的成员变量mObject中。那么这里的JavaBBinder类和BBinder类有什么作用呢?我们知道了,一个进程只有一处地方负责与Binder驱动通信,而进程中可能存在多个Server,这样当Client端请求到来时,进程怎么知道转给哪个Server处理呢?进程从Binder驱动得到的是某个Server的内存地址,进程拿到这个内存地址强制转化成BBinder(因为Server继承了Binder类,那么底层是有个JavaBBinder与之对应的),然后调用BBinder的相关方法进行处理,JavaBBinder通过重写该方法,然后层层传递给java层的Binder类处理的,具体过程会在第4点Server的onTransact响应过程中有所讲解。
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
...
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
...
}
return finish_flatten_binder(binder, obj, out);
}
结构flat_binder_object用于表示传输中的Binder。
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
unsigned long type;
unsigned long flags;
/* 8 bytes of data. */
union {
void *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
void *cookie;
};
type表示Binder的类型,为BINDER_TYPE_BINDER时表示传输的是Binder实体,例如addService添加的就是Binder实体;为BINDER_TYPE_HANDLE表示传输的是Binder引用,例如getService得到的就是Binder的引用。当type为BINDER_TYPE_BINDER时,使用binder指向Binder实体的地址,当type为BINDER_TYPE_HANDLE时,使用handle表示Binder实体对应的句柄,cookie存放一些额外的信息
代码执行的是
obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
这里表示的是传输的是一个Binder的实体对象,指向该Binder实体对象地址(对应的c++层的JavaBBinder对象的地址)的指针local保存在cookie中,从这个结构体的内容中可以看出些端倪,Binder对象的跨进程传输其实传输的只是这个Binder对象的地址,最后调用finish_flatten_binder将这个flat_binder_object写入Parcel中。
Parcel中保存了Binder对象后就可以通过mRemote.transact发起远程通信了。上面的分析知道mRemote的实际类型是BinderProxy,而BinderProxy的transact方法也是简单的通过jni进入c/c++层的调用流程。
public class Binder implements IBinder {
...
final class BinderProxy implements IBinder {
...
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags);
}
...
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
}
简单解释一下transact的code参数的意义:方法编号,我们知道单进程中代理的实现方式是代理持有原始对象的引用,访问代理对象的方法是由代理在内部访问原始对象的方法来实现的,而跨进程中,代理是无法直接访问到原始对象的方法的。因此,只能发送一个方法的编号告诉远程的原始对象该调用哪个方法,这个code就是起这个作用的
android_util_binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
...
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
...
status_t err = target->transact(code, *data, reply, flags);
...
return JNI_FALSE;
}
前两段代码就是将java层的Parcel转换为c/c++层的Parcel对象,而obj就是前面的BinderProxy类型的对象。还记得前面在讲解BinderInternal.getContextObject()的javaObjectForIBinder的时候说过,这个BinderProxy对象在c/c++层有个对应的BpBinder对象,这个BpBinder的地址保存在BinderProxy的成员变量mObject中。这里就是通过GetLongField将这个BpBinder取出来,然后通过这个BpBinder对象发起对远程Server的请求,因为这个BpBinder内部保存着一个句柄值handle,而这个handle值在Binder驱动中唯一对应着一个Server的,因此通过这个BpBinder发起的远程请求是可以访问到远程的Server的,而这里的Server就是ServiceMananger。
BpBinder:transact
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
这里出现了一个新的类IPCThreadState,这个IPCThreadState就是专门负责跟Binder驱动通信的。注意一下这里IPCThreadState的transact的前两个参数,这两个参数连起来就是要告诉Binder驱动我要调用ServiceMananger的编号为ADD_SERVICE_TRANSACTION的方法。
IPCThreadState:transact
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
...
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
...
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
...
cmd = (uint32_t)mIn.readInt32();
...
switch (cmd) {
...
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
...
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
...
do {
...
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
...
} while (err == -EINTR);
...
return NO_ERROR;
}
return err;
}
这里看到在talkWithDriver里调用了ioctl跟Binder驱动通信,数据就是这个binder_write_read类型的bwr,这个bwr的内容来源就是前面的Parcel的内容,其中最重要的内容就是Binder实体对象的地址。
这样一个Server实体对象的地址就传递到了Binder驱动,Binder驱动经过一系列处理后唤醒ServerManager,还记得ServerManager睡眠在ioctl代码里吗,被唤醒后执行binder_parse进行消息的处理,这样Server实体就被纳入了ServerManager的管理了。
3.调用ServiceMananger.getService过程
ServiceMananger:getService
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
我们已经知道getIServiceManager返回的是ServiceManagerProxy
ServiceManagerProxy:getService(“name”)
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
...
}
分析过前面的两点,getService就简单了。getService中reply.readStrongBinder()之前的代码和addService的过程是类似的,这里的mRemote.transact就是要告诉Binder驱动我要调用ServerMananger的编号为GET_SERVICE_TRANSACTION的方法,具体就不展开分析了。当执行到了reply.readStrongBinder()时,Client端就拿到了name对应的远程Binder实体对象在该Client进程中对应的句柄,下面就通过readStrongBinder读取出来了。
Parcel.java:readStrongBinder
public final IBinder readStrongBinder() {
return nativeReadStrongBinder(mNativePtr);
}
private static native IBinder nativeReadStrongBinder(long nativePtr);
通过jni进入c/c++流程
android_os_Parcel.cpp:android_os_Parcel_readStrongBinder
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
首先将java层Parcel对象保存的地址nativePtr强制转换为c++层的Parcel;接着从c++层的Parcel中读取出数据;最后调用javaObjectForIBinder将c++层的对象转为java层的对象返回给java层使用。
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
调用Parcel的readObject取出表示Binder对象的flat_binder_object,这里的flat->type就等于BINDER_TYPE_HANDLE,表示Binder引用,因此这个flat->handle就是对应的句柄值了。接下来的流程就和在获取ServiceMananger的远程接口中的流程一致了,调用proc的getStrongProxyForHandle获得了一个实际类型为BpBinder对象,然后调用javaObjectForIBinder将这个BpBinder对象转换为java层的BinderProxy对象。这样Client端就得到Server的远程接口了,然后再调用asInterface根据这个IBinder对象(BinderProxy)创建一个XXXProxy的代理对象,因为XXXProxy和Server实现了一样的接口,因此使用XXXProxy就好像使用了远程的Server一样。
4.Server的onTransact响应过程
获得了Server的远程接口后,Client端就可以使用这个Server的服务了,具体是通过调用XXXProxy的方法,由XXXProxy在内部调用Server的远程接口IBinder的transact方法发起对远端Server的请求。这个过程和ServerMananger.addService、ServerMananger.getService的过程是类似的,主要是告诉Binder驱动我要调用哪个Server的哪个方法。ServerMananger的响应过程我们知道了,现在来看看其它Server的响应过程。我们在实现自己的Server的时候发现并不需要额外的起一个循环,然后在循环里通过ioctl向Binder驱动获取消息,最后处理的这样一个过程,那是因为该Server所在的进程在启动的时候就已经具备了这样的能力。
在Android应用程序中,是由ActivityManagerService组件负责为Android应用程序创建新的进程的,主要是从其成员函数startProcessLocked开始
ActivityManagerService:startProcessLocked
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
...
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
...
}
在startProcessLocked中,主要是调用Process.start创建新的进程,其中参数entryPoint = “android.app.ActivityThread”,这个类我们应该很熟悉了,它就是代表了应用程序的主线程,ActivityThread被加载进来后,就会调用其main方法开始消息的循环。
Process.start开始后经过层层调用,最终会调用到RuntimeInit的zygoteInit方法
RuntimeInit:zygoteInit
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
...
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
这里有两个关键的方法调用,一个是nativeZygoteInit,一个是applicationInit。applicationInit是进行ActivityThread的加载,并调用它的main方法进入消息循环;而nativeZygoteInit就是用来支持与Binder驱动通信的
nativeZygoteInit方法就不一步一步跟了,想知道执行的流程的话可以参考老罗的文章,最后会执行ProcessState的startThreadPool
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
这里会创建一个PoolThread线程类,然后执行它的run方法,最终会调用PoolThread的threadLoop方法。
先来看一下这个PoolThread线程的名字name,它是由makeBinderThreadName起的
String8 ProcessState::makeBinderThreadName() {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
String8 name;
name.appendFormat("Binder_%X", s);
return name;
}
这个名字的规则是Binder_%X,这个X是从1开始并且递增的,由此可知,最简单的APP进程也至少包含的Binder_1、Binder_2线程,这些线程就是在这里创建的,并且Binder_1线程是在进程创建的时候就已经创建了,而Binder_2或者Binder_X线程是因后面的进程间通信的需要由Binder驱动调度按需通知进程创建的。
接着看看PoolThread的threadLoop方法
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
线程里调用了IPCThreadState的joinThreadPool方法,IPCThreadState前面讲过,它是专门来跟Binder驱动通信的,离真相原来越近了。
IPCThreadState:joinThreadPool
void IPCThreadState::joinThreadPool(bool isMain)
{
...
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
...
status_t result;
do {
result = getAndExecuteCommand();
...
} while (result != -ECONNREFUSED && result != -EBADF)
...
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
...
cmd = mIn.readInt32();
...
result = executeCommand(cmd);
...
}
return result;
}
在IPCThreadState的joinThreadPool里面,进入一个循环,在循环里,调用talkWithDriver从Binder驱动获取消息,如果没有消息就会睡眠,如果有消息就会调用executeCommand进行处理。
代码分析到这里可以得出一个结论:在应用程序进程创建的时候,会创建一个名叫Binder_1的线程,在Binder_1线程里开启一个循环,在循环里会调用talkWithDriver与Binder驱动进行交互。那么如果一个进程里有多个Server,该进程怎么知道把消息分发到哪个Server进行处理呢?
来看一下executeCommand
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
...
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
...
if (tr.target.ptr) {
sp<BBinder> b((BBinder*)tr.cookie);
error = b->transact(tr.code, buffer, &reply, tr.flags);
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
...
}
break;
...
case BR_SPAWN_LOOPER:
mProcess->spawnPooledThread(false);
break;
...
}
...
return result;
}
executeCommand里只关注两个命令,一个BR_SPAWN_LOOPER,一个BR_TRANSACTION。BR_SPAWN_LOOPER是Binder驱动根据调度给进程下达的一个新起线程的命令,Binder_2和之后的线程就是接收到这个命令创建的。
BR_TRANSACTION就是Server响应Client请求的,其中binder_transaction_data结构和前面分析过的flat_binder_object是类似的,binder_transaction_data中的cookie保存的是Server的内存地址,因此此处强转为BBinder对象,然后调用BBinder对象的transact
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
...
switch (code) {
...
default:
err = onTransact(code, data, reply, flags);
break;
}
...
return err;
}
记得在前面分析addService的过程中,通过Parcel的writeStrongBinder将一个Binder实体对象写入Parcel的时候,在c++层实际上是将一个与其对应的JavaBBinder对象的地址写入c++层的Parcel中,而这个JavaBBinder又是继承BBinder的。而刚才应用进程中得到的地址cookie就是这个JavaBBinder对象的地址,最后强转成父类BBinder后调用transact进行处理,最终会调用onTransact,JavaBBinder重写了onTransact方法。
JavaBBinder:onTransact
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
JNIEnv* env = javavm_to_jnienv(mVM);
...
IPCThreadState* thread_state = IPCThreadState::self();
...
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
...
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
前面的分析知道java层的Binder对象(Server)就是保存在JavaBBinder的mObject中的,这里通过CallBooleanMethod就执行到了java层Binder对象的execTransact方法了,这个execTransact方法定义在Binder类中
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
Parcel data = Parcel.obtain(dataObj);
Parcel reply = Parcel.obtain(replyObj);
...
res = onTransact(code, data, reply, flags);
...
return res;
}
在Binder的execTransact中调用了onTransact方法,而Server继承Binder类后都会重写onTransact方法,这样就回调到了java层Server的onTransact方法了。