Android开发之漫漫长途 Ⅷ——Android Binder(也许是最容易理解的)

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!另外,本系列文章知识可能需要有一定Android开发基础和项目经验的同学才能更好理解,也就是说该系列文章面向的是Android中高级开发工程师。


前言

我们在上一篇中比较详尽的介绍了Android的消息机制,不过有一些内容我们在不理解Android Binder的话是无法讲解清楚的。对于初学Android的朋友而言,最难却又最想掌握的恐怕就是Binder机制了,因为Android系统基本上可以看作是一个基于Binder通信的C/S架构。 Binder就像网络一样,把系统的各个部分连接在了一起,因此它是非常重要的。我们下面会Android Binder机制进行从上到下从易到难的分层次讲解,从而既能让初学者对Binder有一定认识,也能让有一定Android基础的人获得收获。

注:下文中的源码均出自android-6.0.0_r5

Binder概述

对于初学者来说,深入Android Binder机制是非常不明智的。Android Binder机制大都涉及Java层、Native层、驱动层这三三个方面,对于初学者来说想啃这三块硬骨头很容易磕着牙。我们这这一节概述从以下几个方面让你从比较宏观的角度理解Android Binder。

进程

在该系列博客中的第一章我们就说起了Android进程相关问题,Android故意弱化了进程的概念,而用相对容易理解的四大组件。可是我们在稍微深入Android的时候,那么进程是绕不过的。默认情况下,同一个应用程序中的所有组件运行在同一个进程中,而且绝大多数的应用程序也都是这样的。这个默认进程是用这个应用的包名来命名的。

进程间通信

我们在运行App的时候经常需要使用一些系统服务,比如剪切板服务,而剪切板服务是运行在SystemServer进程中的。那我们的App是怎么使用剪切板服务的呢,我们都知道进程是相互独立的,静态变量等等都无法共用。这就涉及到进程间的通信了,即IPC。我们都知道Android是基于Linux内核的,那我们简单介绍下Linux下的几种IPC机制。

管道(Pipe)

管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。

  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道
  • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)。比如fork或exec创建的新进程,在使用exec创建新进程时,需要将管道的文件描述符作为参数传递给exec创建的新进程。当父进程与使用fork创建的子进程直接通信时,发送数据的进程关闭读端,接受数据的进程关闭写端。
  • 管道只能在本地计算机中使用,而不可用于网络间的通信。

命名管道(FIFO)

命名管道是一种特殊类型的文件,它在系统中以文件形式存在。这样克服了管道的弊端,他可以允许没有亲缘关系的进程间通信。

共享内存(Share Memory)

共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的地址空间中。其他进程可以将同一段共享内存连接到自己的地址空间中。所有进程都可以访问共享内存中的地址,如果一个进程向共享内存中写入了数据,所做的改动将立刻被其他进程看到。

  • 共享内存是IPC最快捷的方式,共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是同一块的物理空间,仅仅映射到各进程的地址不同而已,因此不需要进行复制,可以直接使用此段空间。
  • 共享内存本身并没有同步机制,需要程序员自己控制。

    内存映射(Memory Map)

    内存映射是由一个文件到一块内存的映射,在此之后进程操作文件,就像操作进程空间里的内存地址一样了。

    套接字(Socket)

    套接字机制不但可以单机的不同进程通信,而且使得跨网机器间进程可以通信。

    套接字的创建和使用与管道是有区别的,套接字明确地将客户端与服务器区分开来,可以实现多个客户端连到同一服务器。

Binder

作为Android系统下的一种IPC机制,其本质上与上面罗列出的IPC机制并无本质上的不同,都是作为进程间通信的一种手段。并且在Android系统中也不是只存在Binder这一种进程间通信的方式,在有些地方也使用了Socket。既然Linux已经提供了众多IPC机制,那么Android 为何还要使用Binder作为主要的进程间通信的方式呢,那么当然有他的优点存在。

  • 采用C/S的通信模式。而在linux通信机制中,目前只有socket支持C/S的通信模式,但socket有其劣势,具体参看第二条。
  • 有更好的传输性能。对比于Linux的通信机制,socket:是一个通用接口,导致其传输效率低,开销大;管道和消息队列:因为采用存储转发方式,所以至少需要拷贝2次数据,效率低;共享内存:虽然在传输时没有拷贝数据,但其控制机制复杂(比如跨进程通信时,需获取对方进程的pid,得多种机制协同操作)。
  • 安全性更高。Linux的IPC机制在本身的实现中,并没有安全措施,得依赖上层协议来进行安全控制。而Binder机制的UID/PID是由Binder机制本身在内核空间添加身份标识,安全性高;并且Binder可以建立私有通道,这是linux的通信机制所无法实现的(Linux访问的接入点是开放的)。
  • 对用户来说,通过binder屏蔽了client的调用server的隔阂,client端函数的名字、参数和返回值和server的方法一模一样,对用户来说犹如就在本地(也可以做得不一样),这样的体验或许其他ipc方式也可以实现,但binder出生那天就是为此而生。

Java层Binder

Java层Binder的功能,依赖于Native层Binder来实现,可以认为Java层Binder架构是Native层Binder架构的一个镜像。但是这并不影响我们分析Android Java层Binder的功能。我们用一个例子来说明这个过程。

我们在第一篇中就讲解了SystemServer这个进程,这个进程和zygote进程一起撑起了Android 世界,他们之中有一个崩溃,Android世界就会砰然倒塌。Android许多的重要的系统服务如AMS、PMS等都运行在SystemServer进程中。但是还有一个比较重要的进程ServiceManager进程(简称SM)跟zygote是兄弟进程。这个进程的作用是用来统一管理服务,如AMS。它们之间的关系如下。

我们的AMS需要向SM进程中注册信息,其他进程如果想使用AMS,那么先和ServiceManager进程进行通信查询,接着再和AMS所在SystemServer进程通信。这部分关系图如下

我们这里仅上图分析①②③中的一条道路,我们来分析③,即我们的应用进程(Client)如何与服务进程(Server)交互。

Java层的Binder,我们来看涉及的类的结构图

[IBinder.java]

public interface IBinder {
    //交互函数
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;
}

我们接着来看Binder和BinderProxy 他们都声明在Binder.java中

[Binder.java]

/**
    Binder类
    */
public class Binder implements IBinder {
    public final boolean transact(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException {
        ......
        //这里调用了onTransact函数进行处理,一般情况下这个函数都会被它的子类重写
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }
}

/**
    BinderProxy类
    */
final class BinderProxy implements IBinder {
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        //直接以JNI的方式调用Native层的transact函数
        return transactNative(code, data, reply, flags);
    }

    public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
}

通用的IPC流程如下

现在假设下面一个场景,我们的应用进程即我们的App想要使用ActivityManagerService的startActivity函数(这种场景肯定有的,当我们拿到手机的时候,手机已经预装了许多App,其中Launcher App(桌面管理App)是在Android系统启动完成之后启动的第一个App,我们安装好一个应用后,点击应用图标即发出Intent,想要启动另一个App中的Activity,我们在AndroidManifest.xml中注册了Main Activity)。Launcher App所在的进程要与AMS所在的进程SystemServer进程交互。

我们来看这个例子。按照上面的通用流程我们猜测Launcher进程与SystemServer进程交互过程也如上图所示,那么按照这个思路我们来看。分为3点:

是否存在业务函数的统一声明?

这一部分是我们的上图中的test函数所声明的类或者接口,我们的Client端代理和Server端服务都要实现这个函数。果然有

[IActivityManager.java]

public interface IActivityManager extends IInterface {
    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
            ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
    ......
}

这里声明了我们将要调用的业务函数startActivity,那么接着第二点

是否存在Server端服务代理?

ActivityManagerProxy是在ActivityManagerNative.java中声明的内部类

class ActivityManagerProxy implements IActivityManager
{
    public ActivityManagerProxy(IBinder remote)
    {
        mRemote = remote;
    }

    public IBinder asBinder()
    {
        return mRemote;
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }

        //看这里果然是通过mRemote.transact函数,这里的mRemote是BinderProxy类,关于这一点我们在Native层分析的时候再给出
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }
    ......
}

是否存在Server端服务

ActivityManagerNative是继承于Binder的抽象类,并重写了onTransact方法

public abstract class ActivityManagerNative extends Binder implements IActivityManager{
     @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        //根据code处理相应的业务逻辑,我们这里是START_ACTIVITY_TRANSACTION
        switch (code) {
        case START_ACTIVITY_TRANSACTION:
        {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            String callingPackage = data.readString();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            IBinder resultTo = data.readStrongBinder();
            String resultWho = data.readString();
            int requestCode = data.readInt();
            int startFlags = data.readInt();
            ProfilerInfo profilerInfo = data.readInt() != 0
                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
            Bundle options = data.readInt() != 0
                    ? Bundle.CREATOR.createFromParcel(data) : null;

            int result = startActivity(app, callingPackage, intent, resolvedType,
                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
            reply.writeNoException();
            reply.writeInt(result);
            return true;
        }
    }
}

既然ActivityManagerNative是个抽象类,那么谁真正实现了呢

[ActivityManagerService.java]

public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    //重写了onTransact函数
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        ......

        try {
            //调用父类即ActivityManagerNative的onTransact函数
            return super.onTransact(code, data, reply, flags);
        } catch (RuntimeException e) {

            throw e;
        }
    }
}

Launcher进程与SystemServer进程交互过程如下

本节小结

关于Java层的Binder机制,我们只需要理解以BinderProxy代表的代理端和Binder代表的服务端的概念即可,例如我们本例中的AMS,AMS是运行在SystemServer进程中的服务端,它间接继承于Binder,在得到相关请求后,会调用AMS重写的onTransact函数进行逻辑处理。那么这个请求就是是AMS的客户端ActivityManagerProxy通过Binder的方式发给它的,ActivityManagerProxy发送这个请求的方式,是通过调用其内部的成员变量mRemote,这个mRemote其实是BinderProxy的对象,然后BinderProxy通过JNI调用Native层对应函数,最终通过Binder驱动达到与SystemServer交互的目的。

那么还遗留下以下几个问题:

1. 服务器端的代理怎么获得的

2. 位于代理类中的mRemote这个变量

要想理解好上面的个问题,我们必须向Native层进军。

Native层Binder

我们依然以AMS分析,我们先来想一下我们在用户进程中即我们的App中想使用AMS或者其他剪切板之类的系统服务函数了怎么办??按照上面的分析我们要获得AMS的代理ActivityManagerProxy

[ActivityManagerNative.java]

//这里我们的App进程从SM进程得到AMS服务对应的客户端代理BinderProxy
IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
//以BinderProxy为参数得到我们ActivityManagerProxy,并把BinderProxy对象存储在mRemote变量中
IActivityManager am = asInterface(b);

return am;

到这里我们就有以下问题,本小节分析1,2

1. 既然可以通过SM获得对应的客户端代理,那么AMS必定已经注册在SM中了,那么怎么注册的呢?

2. AMS代理是如何获得的?

3. AMS代理是如何与Binder通信的?

我们来一一分析,在分析问题之前我们先做一个假设,这个假设至关重要,那就是不管我们的SystemServer进程与SM进程交互也好还是我们的App进程与SM进程也好,SM的代理已经事先创建完毕,即不管我们在SystemServer端还是App端,在与SM进程交互的时候不用考虑代理怎么获得的。为什么会有如此假设,因为我自己深受其害,由于上述三个过程均是通过Binder,很容易陷入思维混乱。

AMS是如何注册的?

我们SystemServer进程中的AMS通过"Socket"与SM进程交互,并把自己注册在SM中

SystemServer创建出ActivityManagerService后,最终将调用其setSystemProcess方法:

[SystemServer.java]

public void setSystemProcess() {
    try {
        //注册服务,第二个参数为this,这里通过“socket”与SM交互
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
        ..........
    } catch (PackageManager.NameNotFoundException e) {
        ........
    }
}

上面的请求最终是通过SM服务代理发送的()

[ServiceManagerNative.java]

public void addService(String name, IBinder service, boolean allowIsolated)
        throws RemoteException {
    //将数据打包写入Parcel对象
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
    //注意这个地方,后文分析,此时的service为ActivityManagerService
    data.writeStrongBinder(service);
    data.writeInt(allowIsolated ? 1 : 0);
    //调用BindProxy的transact函数
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    reply.recycle();
    data.recycle();
}

上面的过程已经分析过了, 这里我们主要看一下哪个对应的native层的transact函数

[android_ util_Binder.cpp]

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags)
{
    ........
    //将java对象转化为native对象
    Parcel* data = parcelForJavaObject(env, dataObj);
    .........
    Parcel* reply = parcelForJavaObject(env, replyObj);
    ........
    //得到native层的BpBinder
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);
    ........
    //通过BpBinder利用IPCThreadState,将请求通过Binder驱动发送给SM进程
    status_t err = target->transact(code, *data, reply, flags);
    ........
}

SM进程收到信息后便处理这个消息(这个说法并不准确,准确的说法是,SM进程中主线程一直在与binder设备交互,想必读者也猜到了for(;;)),有消息时便通过预先定义好的函数进行处理

[service_manager.c]

switch(txn->code) {

    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        //do_add_service
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return -1;
    break;
}

int do_add_service(struct binder_state *bs,
                   const uint16_t *s, size_t len,
                   uint32_t handle, uid_t uid, int allow_isolated,
                   pid_t spid)
{
    //结构体si,用来存储服务信息
    struct svcinfo *si;

    //判断服务有没有权限注册,并不是所有的服务都能注册
    if (!svc_can_register(s, len, spid)) {
        return -1;
    }

    //查询服务有没有注册过
    si = find_svc(s, len);

    if (si) {//已经注册过
        if (si->handle) {
            ALOGE("add_service(‘%s‘,%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                 str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {//还没有注册过,我们进入这个分支
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            ALOGE("add_service(‘%s‘,%x) uid=%d - OUT OF MEMORY\n",
                 str8(s, len), handle, uid);
            return -1;
        }
        //保存一些handle等信息
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = ‘\0‘;
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->next = svclist;
        svclist = si;
    }

    binder_acquire(bs, handle);
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

看到这里SM貌似只保留了一些AMS的信息而已,实际上并不只是如此,我们来看一下上面的保留问题

[Parcel.java]

data.writeStrongBinder(service);

public final void writeStrongBinder(IBinder val) {
    //调用了native函数
    nativeWriteStrongBinder(mNativePtr, val);
}

跟进[android_os_Parcel.cpp]

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        //native层的parcel
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    //obj为Binder类
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        //调用了JavaBBinderHolder的get方法
        return jbh != NULL ? jbh->get(env, obj) : NULL;
    }

    //obj为BinderProxy类
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return (IBinder*)
            env->GetLongField(obj, gBinderProxyOffsets.mObject);
    }

    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

跟进[Pacel.cpp]

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) {//binder不为空
        IBinder *local = binder->localBinder();//是不是本地binder,本地的意思是同一个进程中的调用
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don‘t pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {//我们这里明显不是
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {//错误信息
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }

    return finish_flatten_binder(binder, obj, out);
}

通过上面的代码,我们可以看到当一个服务进行注册时,会将Java层的Binder对象和Native层的BBinder关联起来,于是服务端绑定到了Native层的Binder架构。

此外,addService中打包传入的其实不是ActivityManagerService本身,而是对应的JavaBBinder对象。

这里对应的结构如下图所示:

AMS代理是如何获得的?

我们上面SystemServer中的AMS已经在SM中准备好了,那我们ServiceManager.getService(Context.ACTIVITY_SERVICE);

一样的过程,我们知道最终会在service_manager.c中处理

switch(txn->code) {
    //这里有个case穿透,,好吧
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //查询AMS保存在SM中对应的的那个handle
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;
}
把写入数据后的reply返回
bio_put_uint32(reply, 0);

回到我们的调用处

[ServiceManagerNative.java]

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);
    //看这里readStrongBinder,是不是感觉跟我们上面的writeStrongBinder感觉是一对的
    IBinder binder = reply.readStrongBinder();
    reply.recycle();
    data.recycle();
    return binder;
}

Parcel的readStrongBinder还是个JNI调用

[android_ os_Parcel.cpp]

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        //这里我们看到了什么,,看函数名字应该是为Binder生成一个java对象吧
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

我们先看Pacel的readStrongBinder方法

[Parcel.cpp]

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    //看到这里,还记得writeStrongBinder中的flatten_binder,这里是unflatten_binder
    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:
                //到这里我们也清楚了进入这个分支
                //调用ProcessState的getStrongProxyForHandle函数
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

继续跟进[ProcessState.cpp]

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {

        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {//这里handle为0的情况是为SM准备的,

                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            //我们的不为0,在这里创建了BpBinder
            b = new BpBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {

            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}

好了剩下最后一个了javaObjectForIBinder

[android_ util_Binder.cpp]

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {
    if (val == NULL) return NULL;

    //如果val是Binder对象,进入下面分支,此时val是BpBinder
    if (val->checkSubclass(&gBinderOffsets)) {
        // One of our own!
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it‘s our own %p!\n", val.get(), object);
        return object;
    }
    .........
    //调用BpBinder的findObject函数
    //在Native层的BpBinder中有一个ObjectManager,它用来管理在Native BpBinder上创建的Java BinderProxy对象
    //findObject用于判断gBinderProxyOffsets中,是否存储了已经被ObjectManager管理的Java BinderProxy对象
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        jobject res = jniGetReferent(env, object);
        ............
        //如果该Java BinderProxy已经被管理,则删除这个旧的BinderProxy
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }

    //创建一个新的BinderProxy对象
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        // The proxy holds a reference to the native object.
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        val->incStrong((void*)javaObjectForIBinder);

        // The native object needs to hold a weak reference back to the
        // proxy, so we can retrieve the same proxy if it is still active.
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));

        //新创建的BinderProxy对象注册到BpBinder的ObjectManager中,同时注册一个回收函数proxy_cleanup
        //当BinderProxy对象detach时,proxy_cleanup函数将被调用,以释放一些资源
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);

        // Also remember the death recipients registered on this proxy
        sp<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        //将死亡通知list和BinderProxy联系起来
        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));

        // Note that a new object reference has been created.
        android_atomic_inc(&gNumProxyRefs);

        //垃圾回收相关;利用gNumRefsCreated记录创建出的BinderProxy数量
        //当创建出的BinderProxy数量大于200时,该函数将利用BinderInternal的ForceGc函数进行一个垃圾回收
        incRefsCreated(env);

        return object;
    }
}

到这里总算都打通了总体流程如下

驱动层Binder

还剩下遗留下的两个问题

AMS代理是如何与Binder通信的?

通过Java层的服务端代理最终调用到BpBinder.transact函数

[BpBinder.cpp]

status_t BpBinder:transact(uint32_t code,const Parcel&data,Parcel*reply,uint32_t flags){
    if(mAlive){
        //BpBinder把transact工作交给了IPCThreadState。
        status_t status=IPCThreadState:self()->transact(
        mHandle,code,data,reply,flags);//mHandle也是参数
        if(status==DEAD_OBJECT)mAlive=0;
        return status;
    }
    return DEAD_OBJECT;
}

[IPCThreadState.cpp]

IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),
      mMyThreadId(gettid()),
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    //mIn和mOut是两个Parcel。 把它看成是发送和接收命令的缓冲区即可。
    mIn.setDataCapacity(256);
    mOut.setDataCapacity(256);
}

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    ......
    /*
    注意这里的第一个参数BC_TRANSACTION,它是应用程序向binder设备发送消息的消
    息码,而binder设备向应用程序回复消息的消息码以BR_开头。 消息码的定义在
    binder_module.h中,请求消息码和回应消息码的对应关系,需要查看Binder驱动的实
    现才能将其理清楚,我们这里暂时用不上。
    */

    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    ......
    err = waitForResponse(NULL, NULL);
    ......
    return err;
}

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
   //binder_transaction_data是和binder设备通信的数据结构。
    binder_transaction_data tr;
    //果然,handle的值传递给了target,用来标识目的端,其中0是ServiceManager的标志。
    tr.target.handle=handle;
    //code是消息码,是用来switch/case的!
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    //把命令写到mOut中,而不是直接发出去,可见这个函数有点名不副实。
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) <NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        //看见没?这里开始操作mIn了,看来talkWithDriver中
        //把mOut发出去,然后从driver中读到数据放到mIn中了。
        cmd = mIn.readInt32();

   }
}

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    binder_write_read bwr;
       //中间东西太复杂了,不就是把mOut数据和mIn接收数据的处理后赋值给bwr吗?
        status_t err;
        do {
    //用ioctl来读写
            if (ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr) >= 0)
                err = NO_ERROR;
            else
                err = -errno;
      } while (err == -EINTR);
    //到这里,回复数据就在bwr中了,bmr接收回复数据的buffer就是mIn提供的
            if (bwr.read_consumed > 0) {
                mIn.setDataSize(bwr.read_consumed);
                mIn.setDataPosition(0);
            }
    returnNO_ERROR;
}

本篇总结

我们本篇详细分析了Binder机制,从概述->Java层Binder->Native层Binder->Binder驱动,位于各层次的读者都能获得收获。


下篇预告

不好意思各位,下周有个比较重要的面试,所以暂时不会更新该系列的博客,但是也会更新其他博客。记录准备面试的过程中需要用到的比较容易错误的知识。



此致,敬礼

时间: 2024-10-12 08:33:01

Android开发之漫漫长途 Ⅷ——Android Binder(也许是最容易理解的)的相关文章

Android开发之漫漫长途 X——Android序列化

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解Android 卷Ⅰ,Ⅱ,Ⅲ>中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!另外,本系列文章知识可能需要有一定Android开发基础和项目经验的同学才能更好理解,也就是说该系列文章面向的是Android中高级开发工程师. 前言 上一篇中我们比较详尽的分析了ServiceManag

Android开发之漫漫长途 Fragment番外篇——TabLayout+ViewPager+Fragment

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解Android 卷Ⅰ,Ⅱ,Ⅲ>中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!! 前言 上一篇文章中我们使用底部导航+Fragment的方式实现了Android主流App中大都存在的设计.并命名其为"Fragment最佳实践",作为想到单独使用Fragment的用

Android开发之漫漫长途 XIV——RecyclerView

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解Android 卷Ⅰ,Ⅱ,Ⅲ>中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!! 前言 上文我们很详细的分析了ListView的使用.优化.及ListView的RecycleBin机制,读者如果对ListView不太清楚,那么请参看我的上篇博文.不过呢,Google Material

【Android开发】完美解决Android完全退出程序

背景:假说有两个Activity, Activity1和Activity2, 1跳转到2,如果要在2退出程序,一般网上比较常见的说法是用 System.exit(0) 或是 android.os.Process.killProcess(android.os.Process.myPid()) 但实际应用中,并不是能够真正退出,问题出在?1跳转到2时,如果Activity1你finish掉了,两么是可以退出程序的,但有时1跳转到2时,我们不能将Activity1 finish掉,那么在Activit

Android开发工具全面转向Android Studio(3)——AS project/module的目录结构(与Eclipse对比)

如果AS完全还没摸懂的,建议先看下Android开发工具全面转向Android Studio(2)——AS project/module的CRUD. 1.其实AS project/module的目录结构很简单,我浓缩成2张图给总结了,先看图,再看下面的文字,因为还有些细节图上体现不出来(我这个图上的项目来源于我之前的Eclipse项目,并且有lib项目库相互依赖) 2.上面的图很直观,但也很眼花缭乱,我再针对图总结下重点和疑问点. ①在AS的世界里,文件夹都以模块(module)为单位组织的,其

配置cordova的android开发环境(无android studio)

原文:配置cordova的android开发环境(无android studio) 趁元旦放假想试一下cordova,不想安装庞大的android studio,所以想最小化安装,居然花了一整天的时间才能正常编译cordova工程,记录一下过程,备将来参考. 安装环境:操作系统:windows 10 x64 第一步:安装nodejs,下载最新版本v10.15.0 第二步:设置npm安装源 npm config set registry http://registry.npm.taobao.org

android开发步步为营之70:android接入Google Analytics总结

求人不如求己,今天项目里要接入Google Analytics,这个是做应用统计分析用的,可以查看当前手机活跃用户,事件点击等等数据,先看看效果: 之前eclipse里面接入已经成功,昨天项目组决定项目转成使用android studio来开发,看google官方文档,官方文档https://developers.google.com/analytics/devguides/collection/android/v4/,然后官方文档里面的配置文件是用google-services.json的,这

Android开发自学笔记(基于Android Studio1.3.1)—1.环境搭建

一.引言    本套学习笔记的开发环境是Windows 10 专业版和Android Studio 的最新版1.3.1. Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试.    笔者没有怎么使用过Eclipse做Android学习,但是基于Android Studio类似于VS的项目架构,还是偏爱Android Studio这个IDE,没

Android开发工具——Google发布Android studio1.0正式版

Android Studio介绍 Android Studio是一个为Android平台开发程序的集成开发环境.2013年5月16日由Google产品经理Ellie Powers在Google I/O上发布,可供开发者免费使用.2013年5月发布早期预览版本,版本号为0.1.2014年6月发布0.8版本,至此进入beta阶段.第一个稳定版本于2014年12月8日发布.Android Studio基于JetBrains IntelliJ IDEA,为Android开发特殊定制,并在Windows.