图片 11

Android通信机制分析-Binder(1)

本文是Android Binder机制解析的第三篇,也是最后一篇文章。本文会讲解Binder
Framework Java部分的逻辑。

概述

Android四大组件分别是
ActivityServiceBroadcastReceiverContentProvider,我们平时开发的
App
都是由四大组件中的一个或者多个组合而成;这四大组件所涉及的多进程间通信底层实现都是基于
Binder 的 IPC 机制。

我们平时开发过程中用到很多跨进程的通信,比如:

  1. App 中的 ActivityA 调用系统的 ActivityB

  2. App 中的 ActivityA 调用另一个 App 的 Service

Binder 作为 Android 系统提供的一种的 IPC 机制,整个 Android
系统架构中大量采用了 Binder 机制的 IPC 方案。

Binder简析

直观来说,Binder 是 Android 中的一个类,是继承了 IBinder 接口;从 IPC
角度考虑 Binder 是进程间通信的一种方式;从 Framework 层,Binder 是 连接
ServiceManager 和 各种 Manager(AM,WM) 以及各种 ManagerService
的桥梁;从应用层来说,Binder 是客户端和服务器端进行通信的媒介,当
bindService 的时候服务器端会返回一个包含了服务端业务调用的 Binder
对象,客户端就可以获取服务端提供的数据或服务。

Binder机制分析的前面两篇文章,请移步这里:

IPC

说到 IPC,我们来稍微看一下 IPC 机制的原理:进程间通信(IPC,
Inter-Process Communication)

指至少两个进程或线程减传送数据或者信号的技术或方法。每个进程都有自己的一部分独立的系统资源,彼此之间是隔离的。为了能使不同的进程相互访问资源并进行协调工作,才有了进程间通信。IPC
的方法有多种,包括文件、Socket、管道、信号量、共享内存
等,我们今天主要来说说 Android 中的 Binde r。

应用层的使用 AIDL

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\MyApplication\ServiceDemo\app\src\main\aidl\com\renxl\servicedemo\aidl\MyWorker.aidl
 */
package com.renxl.servicedemo.aidl;
// Declare any non-default types here with import statements

public interface MyWorker extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.renxl.servicedemo.aidl.MyWorker {
        private static final java.lang.String DESCRIPTOR = "com.renxl.servicedemo.aidl.MyWorker";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.renxl.servicedemo.aidl.MyWorker interface,
         * generating a proxy if needed.
         */
        public static com.renxl.servicedemo.aidl.MyWorker asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.renxl.servicedemo.aidl.MyWorker))) {
                return ((com.renxl.servicedemo.aidl.MyWorker) iin);
            }
            return new com.renxl.servicedemo.aidl.MyWorker.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public 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_doWork: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    int _result = this.doWork(_arg0);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.renxl.servicedemo.aidl.MyWorker {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public int doWork(java.lang.String str) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(str);
                    mRemote.transact(Stub.TRANSACTION_doWork, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_doWork = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public int doWork(java.lang.String str) throws android.os.RemoteException;
}

理解 Android Binder
机制(一):驱动篇

Binder

介绍

我们自定义的 AIDL 数据类继承 IInterface 接口,因为可以在 Binder
中传输的数据接口都需要继承 IInterface 并实现其 asBinder 方法

Stub 是 AIDL 接口中的抽象类,Stub 类继承了 Binder
和我们需要在进程中传递的数据类型接口,Stub 类中还有 Proxy
子类,该类也继承了需要在进程间传递的数据类型

理解 Android Binder
机制(二):C++层

概念

每个 Android 在各自独立的 Dalvik
虚拟机中运行,每个进程拥有独立的地址空间和资源,对应的地址空间有一部分是用户空间,另一部分是内核空间。对于用户空间,不同进程之间彼此是不能共享的,而内核空间则是可以共享的,Client
进程同 Server
进程通信,就是利用进程间可共享的内核空间(内核驱动)来完成底层通信工作的。

图片 1

IPC 机制

Android 中 Binder 通信采用的是 C/S 架构,Binder 框架包括
Client、Server、ServiceManager 以及 Binder 驱动,其中 ServiceManager
用来管理系统中各种服务。其中 Server,Client,ServiceManager
运行于用户空间,Binder
驱动运行于内核空间。这四个角色的关系和互联网类似:Server
是服务器,Client 是客户终端,ServiceManager 是域名服务器(DNS),Binder
驱动是路由器。如图:

图片 2

Binder

服务端

首先看客户端绑定时服务端的返回的客户端所需的 AIDL
接口类型对象,服务端返回的 Binder 对象继承的是 AIDL 中内部类 Stub
类,因为 Java 中多态的存在,我们需要 IBinder 对象时返回 IBinder
的子类即可。说一下为什么 服务端 返回的是 AIDL 中的内部类 Stub
类的对象的子类,因为,该抽象类的子类实现了我们定义的 .aidl
接口中的方法,所以返回的应该是这个 Stub 类的子类。Stub 子类实现了 .aidl
中声明的方法的抽象方法。

服务器端 Stub 的子类实例化时,因为同时是 Binder 的子类,需要调用 Binder
的 attachInterface 方法,将本身和 IInterface 的描述字符串添加到 Binder
类中,Binder 类中会根据描述字符串匹配相应的 IInterface 对象

下文所讲内容的相关源码,在AOSP源码树中的路径如下:

Binder使用实例

Binder 是 Android 中一个类,它实现 IBinder 接口,从 IPC 方面来看 Binder
是一种跨进程通信的方式,从 Framework 方面来看 Binder 是 ServiceManager
连接各种 Manager (WindowManager, ActivityManager 等等)和相应的
ManagerService (WindowManagerService, ActivityManagerService
等等)的桥梁;

图片 3

AMS 架构

对客户端应用来说,Binder
是客户端和服务端通信的媒介,当bindService的时候,服务端会返回一个包含服务端业务调用的
Binder 对象,通过这个 Binder
对象客户端可以获取服务端提供的服务、数据等。

public class LocalService extends Service {
    // Binder given to clients
    private final IBinder mBinder = new LocalBinder();
    // Random number generator
    private final Random mGenerator = new Random();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // Return this instance of LocalService so clients can call public methods
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder; //通过 onBind 返回一个服务端的 Binder 对象
    }

    /** method for clients */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

上面这段代码是 Service 的一种实现方式,这里的 Binder
不涉及跨进程通信,所以比较简单,跨进程的 Binder 使用在 Android 中主要是
Messager 和 AIDL,Messager 的底层实现也是 AIDL,所以我们先来聊聊 AIDL。

客户端

根据绑定模式的 Service 绑定过程,最终服务端返回的 Binder
对象会传递到客户端的 ServiceConnection 的 onServiceConnected 方法中。

客户端得到服务端返回的 Binder 后,会通过自定义 AIDL 接口类的 asInterface
将该 Binder 转化为客户端需要的接口类型对象,asInterface 方法会从 Binder
类中根据描述字符串寻找相应的
IInterface,客户端和服务端不在统一进程时,由于 Binder
类的加载也是分开的,所以在客户端的 Binder 中不会找到匹配的 IInterface

在同进程请求时 asInterface 返回的是 Stub
的实现类的对象,也就是直接返回的服务端返回的继承了 Stub
类的对象。同进程不用考虑 Binder 传输数据,所以直接调用 Stub
实现类的各种方法即可实现客户端调用服务端的数据和服务的功能。

在跨进程调用时,由于客户端 Binder 中不能找到对应的 IInterface,所以
asInterface 中返回的是根据 Stub 的子类对象构造的 Stub.Proxy
类的对象。Stub.Proxy
类中调用服务器端方法时会将参数和返回值都使用序列化处理,经过跨进程通信后最终传递到客户端。从而完成客户端调研服务端服务和数据的功能。

// Binder Framework JNI
/frameworks/base/core/jni/android_util_Binder.h
/frameworks/base/core/jni/android_util_Binder.cpp
/frameworks/base/core/jni/android_os_Parcel.h
/frameworks/base/core/jni/android_os_Parcel.cpp

// Binder Framework Java接口
/frameworks/base/core/java/android/os/Binder.java
/frameworks/base/core/java/android/os/IBinder.java
/frameworks/base/core/java/android/os/IInterface.java
/frameworks/base/core/java/android/os/Parcel.java

AIDL

新建一个 AIDL 的文件</br>

图片 4

新建 AIDL File

新建后会自动生成 aidl 的目录,并将新建的 AIDL
文件放到该目录下</br>

图片 5

生成的aidl目录

Book.aidl 文件内容是自动生成的,我们可以根据自己的需求进行修改,
自动生成的代码标记了 import 语句的地方和可以用做 AIDL
参数和返回值的一些基本类型

// Book.aidl
package me.jifengzhang.aidldemo;

// Declare any non-default types here with import statements

interface Book {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

这个demo主要是提供 Book 的两个操作,我们新建的文件包括 Book.java 、
IBook.aidl 、 IBookManager.aidl,其中 Book
对象需要跨进程通过Binder传输,所以需要实现 Parcelable 接口。

Book.java

import android.os.Parcelable;

public class Book implements Parcelable{
    public int bookId;
    public 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>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(bookId);
        dest.writeString(bookName);
    }
}

Book.aidl

package me.jifengzhang.aidldemo;

parcelable Book;

IBookManager.aidl

package me.jifengzhang.aidldemo;

import me.jifengzhang.aidldemo.Book;

interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
}

编译后,会自动生成 IBookManager.aidl 对应的 java
文件(app/build/generated/source/aidl/debug/me/jifengzhang/aidldemo/IBookManager.java),格式调整后如下:

package me.jifengzhang.aidldemo;

public interface IBookManager extends android.os.IInterface {
    /**
    * Local-side IPC implementation stub class.
    */
   public static abstract class Stub extends android.os.Binder implements me.jifengzhang.aidldemo.IBookManager {

       ...

   }

   public java.util.List<me.jifengzhang.aidldemo.Book> getBookList() throws android.os.RemoteException;

   public void addBook(me.jifengzhang.aidldemo.Book book) throws android.os.RemoteException;

这个类结构其实很简单,它继承了 IInterface 接口(所有可以在 Binder
中传输的接口都需要继承 IInterface
接口)同时它自己也是一个接口类,可以看到其实它的内部结构就是声明了两个方法
getBookList 和 addBook (显然这两个方法是 IBookManager.aidl
中声明的),同时还有一个内部类 Stub,这个类就是一个 Binder 类(很明显
Stub 继承 Binder)。但我们应该认识到 IBookManager.java 的核心实现是 Stub
以及 Stub 的内部代理类 Proxy。

下面详细介绍下 Stub 以及内部代理类 Proxy 中各个方法的含义:

** DESCRIPTOR **

Binder 的唯一标识符,一般使用当前 Binder 的类名表示, 比如上述例子中的
*** “me.jifengzhang.aidldemo.IBookManager” ***

** asInterface **

转换服务端传递过来的 IBinder 对象为客户端需要的 AIDL
接口类型的对象,这个转换过程是区分进程的,如果客户端和服务端是同一个进程,那么该方法返回的就是服务端的
Stub 对象本身,当然如果不是同一个进程则返回的是封装后的 Stub.Proxy
对象。

public static me.jifengzhang.aidldemo.IBookManager asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof me.jifengzhang.aidldemo.IBookManager))) { //同一个进程
        return ((me.jifengzhang.aidldemo.IBookManager) iin);
    }
    //不同进程
    return new me.jifengzhang.aidldemo.IBookManager.Stub.Proxy(obj);
}

** asBinder **

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

** onTransact **

该方法运行在服务端的 Binder 线程池中,
当客户端发起跨进程请求时,远程请求会通过系统底层封装后交给该方法处理。服务端通过
code 来确定客户端请求的方法是什么,从 data:Parcel
中取出方法所需要的参数,然后执行目标方法,最后将方法执行的结果(返回值)存到
replay: Parcel 中。

** Proxy#getBookList **

该方法运行在客户端,当客户端调用该方法时,首先创建该方法所需要的输入
Parcel 对象 _data, 输出 Parcel 对象 _reply 以及返回值
List,然后将参数信息写入 _data 中,接着调用 transact 方法发起远程调用
RPC ,此时客户端当前线程挂起,服务端的 onTransact 方法会被调用执行,直到
RPC 过程返回后,客户端当前线程继续执行,并从 _reply 中取出 RPC
过程的返回结果。最后将 _reply 转换成 List 返回。

** Proxy#addBook

执行过程和 getBookList 一样。

通过简单的分析描述,其实 AIDL 的实现其实很简单,方法调用的流程大概如下:

图片 6

AIDL 流程

为什么服务器端返回的 Binder 是客户端需要的类对象,但是跨进程时需要转换为 Proxy

因为不同进程间的对象不能相互调用,虽然绑定玩成时客户端拿到了服务器端对象的引用但是并不能直接操作该对象,所以需要通过
Proxy 来代理,Proxy 类的方法执行时会在 Native
层通过系统进程的协助调用服务端对象来执行任务,所以跨进程时客户端拿到的
Binder 对象不可以直接强制转型为需要的对象。

主要结构

Android应用程序使用Java语言开发,Binder框架自然也少不了在Java层提供接口。

前文中我们看到,Binder机制在C++层已经有了完整的实现。因此Java层完全不用重复实现,而是通过JNI衔接了C++层以复用其实现。

下图描述了Binder Framework Java层到C++层的衔接关系。

图片 7

这里对图中Java层和JNI层的几个类做一下说明(
关于C++层的讲解请看这里 ):

名称 类型 说明
IInterface interface 供Java层Binder服务接口继承的接口
IBinder interface Java层的IBinder类,提供了transact方法来调用远程服务
Binder class 实现了IBinder接口,封装了JNI的实现。Java层Binder服务的基类
BinderProxy class 实现了IBinder接口,封装了JNI的实现。提供transact方法调用远程服务
JavaBBinderHolder class 内部存储了JavaBBinder
JavaBBinder class 将C++端的onTransact调用传递到Java端
Parcel class Java层的数据包装器,见C++层的Parcel类分析

这里的IInterface,IBinder和C++层的两个类是同名的。这个同名并不是巧合:它们不仅仅同名,它们所起的作用,以及其中包含的接口都是几乎一样的,区别仅仅在于一个是C++层,一个是Java层而已。

除了IInterface,IBinder之外,这里Binder与BinderProxy类也是与C++的类对应的,下面列出了Java层和C++层类的对应关系:

C++ Java层
IInterface IInterface
IBinder IBinder
BBinder Binder
BpProxy BinderProxy
Parcel Parcel

服务端(Service)实现

上面简单说明了 AIDL
中接口的定义,这里我们来看看服务端也就是作为服务提供者的 Service
的实现,我们可以想到的是 Service 肯定是要实现 IBookManager
定义的两个接口,剩余的应该有 Service 的基本实现。那我们来看代码:

public class BookManagerService extends Service {
    private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();

    private Binder mBinder = new IBookManager.Stub() {

        @Override
        public List<Book> getBookList() throws RemoteException {
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            mBookList.add(book);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        mBookList.add(new Book(1, "Android"));
        mBookList.add(new Book(2, "IOS"));
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
}

果然,代码和我们想的是一样的,这里通过 new 一个 Stub (IBookManager
的内部类,继承自 Binder)来实现 getBookList 和 addBook 两个接口方法。

进程间通信

跨进程调用时客户端的调用逻辑:上面说了跨进程时得到的AIDL接口数据类型是
Stub.Proxy ,所以直接分析 Stub.Proxy 类中的方法调用。Stub.Proxy
中调用方法并不会直接调用服务端的方法,会先创建 Parcel
类型的输入对象和输出对象以及返回值。如果方法有参数就将参数写入输入型
Parcel
对象中,这个过程还是在客户端,接下来会将序列化后的参数,序列化的返回值,以及表示客户端调用的是哪个方法的
int 值传入 Binder 的 transact 方法,客户端线程挂起。

Binder 的 transact 方法中会调用 Native 层的方法,Native 层会根据
IInterface 描述字符串从系统中所有进程的 Binder 中找到客户端 Proxy
对应的服务器端的 IInterface ,然后通过其 asBinder 方法得到服务器端的
Binder 对象也就是 Stub 对象,在通过调用其 onTransact
方法,通过系统进程将客户端跟服务端连接,并将客户端线程挂起

说一下这个 Binder , 创建 Proxy 时构造方法传入的 IBinder
也就是客户端绑定时得到的 Binder 类对象,通过系统进程调用服务端的
onTransact
方法,执行也就切换到了服务端,服务端也就拿到了序列化后的参数,返回值以及代表哪个方法的
int 值。transact 方法中会把存储参数和返回值的可序列化数据传递到
onTransact 方法中

onTransact
方法中会将序列化的参数反序列化,再根据代表客户端调用哪个方法的 int
值,将参数传入相应方法得到返回值。
这里需要注意,传入相应的方法,其实是调用的 Stub
类的子类的方法,也就是服务端实现了 Stub
类中抽象方法的那个类的对象的方法,这样最终任务的执行实在 Stub
中执行的,并不是在 Proxy 类中。

再将返回值进行序列化后写入参数中传来的输出型 Parcel
中,这时候,注意,服务端就执行结束了。

服务端执行结束之后,系统进程会返回一个 Boolean
值表示是否成功调用,系统进程收到这个返回值时后将该返回值和及 将输出型的
Pacel 返回到客户端进程,客户端进程的 Binder
线程会被唤醒,客户端线程唤醒后,会根据是否执行成功的返回值接收执行结果

注:

  1. 客户端发起请求时当前线程就会挂起,所以要是执行任务耗时则需要客户端在子线程中调用

  2. 服务端相应请求执行过程在 Binder 的线程池中,即已经在子线程中了,所有
    Binder 中执行过程无需再开启子线程

JNI的衔接

JNI全称是Java Native
Interface,这个是由Java虚拟机提供的机制。这个机制使得native代码可以和Java代码互相通讯。简单来说就是:我们可以在C/C++端调用Java代码,也可以在Java端调用C/C++代码。

关于JNI的详细说明,可以参见Oracle的官方文档:Java Native
Interface ,这里不多说明。

实际上,在Android中很多的服务或者机制都是在C/C++层实现的,想要将这些实现复用到Java层,就必须通过JNI进行衔接。AOSP源码中,/frameworks/base/core/jni/
目录下的源码就是专门用来对接Framework层的JNI实现的。

看一下Binder.java的实现就会发现,这里面有不少的方法都是用native关键字修饰的,并且没有方法实现体,这些方法其实都是在C++中实现的:

public static final native int getCallingPid();

public static final native int getCallingUid();

public static final native long clearCallingIdentity();

public static final native void restoreCallingIdentity(long token);

public static final native void setThreadStrictModePolicy(int policyMask);

public static final native int getThreadStrictModePolicy();

public static final native void flushPendingCommands();

public static final native void joinThreadPool();

在android_util_Binder.cpp文件中的下面这段代码,设定了Java方法与C++方法的对应关系:

static const JNINativeMethod gBinderMethods[] = {
    { "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },
    { "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },
    { "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },
    { "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },
    { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },
    { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },
    { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
    { "init", "()V", (void*)android_os_Binder_init },
    { "destroy", "()V", (void*)android_os_Binder_destroy },
    { "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable }
};

这种对应关系意味着:当Binder.java中的getCallingPid方法被调用的时候,真正的实现其实是android_os_Binder_getCallingPid,当getCallingUid方法被调用的时候,真正的实现其实是android_os_Binder_getCallingUid,其他类同。

然后我们再看一下android_os_Binder_getCallingPid方法的实现就会发现,这里其实就是对接到了libbinder中了:

static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz)
{
    return IPCThreadState::self()->getCallingPid();
}

这里看到了Java端的代码是如何调用的libbinder中的C++方法的。那么,相反的方向是如何调用的呢?最关键的,libbinder中的BBinder::onTransact是如何能够调用到Java中的Binder::onTransact的呢?

这段逻辑就是android_util_Binder.cpp中JavaBBinder::onTransact中处理的了。JavaBBinder是BBinder子类,其类结构如下:

图片 8

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();
   const int32_t strict_policy_before = thread_state->getStrictModePolicy();

   jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
       code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
   ...
}

请注意这段代码中的这一行:

jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
  code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);

这一行代码其实是在调用mObject上offset为mExecTransact的方法。这里的几个参数说明如下:

  • mObject 指向了Java端的Binder对象
  • gBinderOffsets.mExecTransact 指向了Binder类的execTransact方法
  • data 调用execTransact方法的参数
  • code, data, reply, flags都是传递给调用方法execTransact的参数

JNIEnv.CallBooleanMethod这个方法是由虚拟机实现的。即:虚拟机会提供native方法来调用一个Java
Object上的方法(关于Android上的Java虚拟机,今后我们会专门讲解)。

这样,就在C++层的JavaBBinder::onTransact中调用了Java层Binder::execTransact方法。而在Binder::execTransact方法中,又调用了自身的onTransact方法,由此保证整个过程串联了起来:

private boolean execTransact(int code, long dataObj, long replyObj,
       int flags) {
   Parcel data = Parcel.obtain(dataObj);
   Parcel reply = Parcel.obtain(replyObj);
   boolean res;
   try {
       res = onTransact(code, data, reply, flags);
   } catch (RemoteException|RuntimeException e) {
       if (LOG_RUNTIME_EXCEPTION) {
           Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
       }
       if ((flags & FLAG_ONEWAY) != 0) {
           if (e instanceof RemoteException) {
               Log.w(TAG, "Binder call failed.", e);
           } else {
               Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
           }
       } else {
           reply.setDataPosition(0);
           reply.writeException(e);
       }
       res = true;
   } catch (OutOfMemoryError e) {
       RuntimeException re = new RuntimeException("Out of memory", e);
       reply.setDataPosition(0);
       reply.writeException(re);
       res = true;
   }
   checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
   reply.recycle();
   data.recycle();

   StrictMode.clearGatheredViolations();

   return res;
}

客户端的实现

客户端也就是访问端的实现也比较简单,首先是绑定服务(BinderService),绑定成功后将服务端返回的
Binder 对象转换为 AIDL 接口,然后就可以使用这个接口来调用 Server
端的远程方法。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //绑定服务
    Intent intent = new Intent(this, BookManagerService.class);
    bindService(intent, mServiceConnect, Context.BIND_AUTO_CREATE);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    //解绑
    unbindService(mServiceConnect);
}

private ServiceConnection mServiceConnect = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //将服务端传递过来的Binder对象转换为AIDL接口
        IBookManager manager = IBookManager.Stub.asInterface(service);
        try {
            List<Book> list = manager.getBookList();
            Log.i("MainActivity", "queue book list : " + list.toString());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

Binder 的死亡代理

通过 linkToDeath 和 unlinkToDeath 方法可以为 Binder 绑定和解绑死亡代理
死亡代理是一个 DeathRecipient 类,内部又一个 binderDied
方法,我们需要实现这个方法,在 Binder 死亡的时候,系统就会回调
binderDied 方法,我们就可以移除之前绑定的 binder
代理并重新绑定完成服务。

Java Binder服务举例

和C++层一样,这里我们还是通过一个具体的实例来看一下Java层的Binder服务是如何实现的。

下图是ActivityManager实现的类图:

图片 9

下面是上图中几个类的说明:

类名 说明
IActivityManager Binder服务的公共接口
ActivityManagerProxy 供客户端调用的远程接口
ActivityManagerNative Binder服务实现的基类
ActivityManagerService Binder服务的真正实现

看过Binder
C++层实现之后,对于这个结构应该也是很容易理解的,组织结构和C++层服务的实现是一模一样的。

对于Android应用程序的开发者来说,我们不会直接接触到上图中的几个类,而是使用android.app.ActivityManager中的接口。

这里我们就来看一下,android.app.ActivityManager中的接口与上图的实现是什么关系。我们选取其中的一个方法来看一下:

public void getMemoryInfo(MemoryInfo outInfo) {
   try {
       ActivityManagerNative.getDefault().getMemoryInfo(outInfo);
   } catch (RemoteException e) {
       throw e.rethrowFromSystemServer();
   }
}

这个方法的实现调用了ActivityManagerNative.getDefault()中的方法,因此我们在来看一下ActivityManagerNative.getDefault()返回到到底是什么。

static public IActivityManager getDefault() {
   return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
   protected IActivityManager create() {
       IBinder b = ServiceManager.getService("activity");
       if (false) {
           Log.v("ActivityManager", "default service binder = " + b);
       }
       IActivityManager am = asInterface(b);
       if (false) {
           Log.v("ActivityManager", "default service = " + am);
       }
       return am;
   }
};

这段代码中我们看到,这里其实是先通过IBinder b = ServiceManager.getService("activity"); 获取ActivityManager的Binder对象(“activity”是ActivityManagerService的Binder服务标识),接着我们再来看一下asInterface(b)的实现:

static public IActivityManager asInterface(IBinder obj) {
   if (obj == null) {
       return null;
   }
   IActivityManager in =
       (IActivityManager)obj.queryLocalInterface(descriptor);
   if (in != null) {
       return in;
   }

   return new ActivityManagerProxy(obj);
}

这里应该是比较明白了:首先通过queryLocalInterface确定有没有本地Binder,如果有的话直接返回,否则创建一个ActivityManagerProxy对象。很显然,假设在ActivityManagerService所在的进程调用这个方法,那么queryLocalInterface将直接返回本地Binder,而假设在其他进程中调用,这个方法将返回空,由此导致其他调用获取到的对象其实就是ActivityManagerProxy。而在拿到ActivityManagerProxy对象之后在调用其方法所走的路线我想读者应该也能明白了:那就是通过Binder驱动跨进程调用ActivityManagerService中的方法。

这里的asInterface方法的实现会让我们觉得似曾相识。是的,因为这里的实现方式和C++层的实现是一样的模式。

运行结果

我们在 Manifest 中给 BookManagerService 设置 process 属性,这样
BookManagerService 和 MainActivity 就是不同的进程。

<service android:name=".BookManagerService" android:process=":remote"/>

运行结果:

05-04 10:10:28.622 17622-17622/me.jifengzhang.aidldemo I/MainActivity: queue book list : [[1:Android], [2:IOS]]

总结

  • Worker 需要传递的对象需要实现的接口,继承 IInterface 接口

  • Stub 服务器端需要实现的对象的父类继承 Binder 类

  • Proxy 代理类,客户端调用服务器端对象时使用的类,继承 Binder

当 Stub 的子类实例化时,Binder 中会存起来,并将该 Binder
返回到客户端,客户端拿到这个 Binder
会根据是否是同进程操作,不同进程时会通过 Binder 构造

Java层的ServiceManager

源码路径:

frameworks/base/core/java/android/os/IServiceManager.java
frameworks/base/core/java/android/os/ServiceManager.java
frameworks/base/core/java/android/os/ServiceManagerNative.java
frameworks/base/core/java/com/android/internal/os/BinderInternal.java
frameworks/base/core/jni/android_util_Binder.cpp

有Java端的Binder服务,自然也少不了Java端的ServiceManager。我们先看一下Java端的ServiceManager的结构:

图片 10

通过这个类图我们看到,Java层的ServiceManager和C++层的接口是一样的。

然后我们再选取addService方法看一下实现:

public static void addService(String name, IBinder service, boolean allowIsolated) {
   try {
       getIServiceManager().addService(name, service, allowIsolated);
   } 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(BinderInternal.getContextObject());

然后我们需要再看一下BinderInternal.getContextObject()和ServiceManagerNative.asInterface两个方法。

BinderInternal.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);
}

而ServiceManagerNative.asInterface的实现和其他的Binder服务是一样的套路:

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);
}

先通过queryLocalInterface查看能不能获得本地Binder,如果无法获取,则创建并返回ServiceManagerProxy对象。

而ServiceManagerProxy自然也是和其他Binder Proxy一样的实现套路:

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();
}

有了上文的讲解,这段代码应该都是比较容易理解的了。

参考

Gityuan

** Android 开发艺术探索 **

AIDL原理

Binder 在 AIDL 中应用,服务器端将客户端需要的对象转换成一个 Binder 对象

AIDL
原理,即客户端需要一个服务器端的对象,客户端和服务器端不在同一进程,服务端返回一个
Binder 对象给客户端,客户端根据将 Binder 对象转换成需要的对象的 Proxy
代理,需要调用服务端执行任务时就调用该 Proxy 代理的方法,Proxy
代理的方法执行时会通过 Native 层通过系统进程找到其他进程中匹配的 Stub
子类,并调用其执行任务方法,从而实现客户端和服务端的进程间通信。

关于AIDL

作为Binder机制的最后一个部分内容,我们来讲解一下开发者经常使用的AIDL机制是怎么回事。

AIDL全称是Android Interface Definition Language,它是Android
SDK提供的一种机制。借助这个机制,应用可以提供跨进程的服务供其他应用使用。AIDL的详细说明可以参见官方开发文档:

这里,我们就以官方文档上的例子看来一下AIDL与Binder框架的关系。

开发一个基于AIDL的Service需要三个步骤:

  1. 定义一个.aidl文件
  2. 实现接口
  3. 暴露接口给客户端使用

aidl文件使用Java语言的语法来定义,每个.aidl文件只能包含一个interface,并且要包含interface的所有方法声明。

默认情况下,AIDL支持的数据类型包括:

  • 基本数据类型(即int,long,char,boolean等)
  • String
  • CharSequence
  • List(List的元素类型必须是AIDL支持的)
  • Map(Map中的元素必须是AIDL支持的)

对于AIDL中的接口,可以包含0个或多个参数,可以返回void或一个值。所有非基本类型的参数必须包含一个描述是数据流向的标签,可能的取值是:inout或者inout

下面是一个aidl文件的示例:

// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

这个文件中包含了两个接口 :

  • getPid 一个无参的接口,返回值类型为int
  • basicTypes,包含了几个基本类型作为参数的接口,无返回值

对于包含.aidl文件的工程,Android IDE(以前是Eclipse,现在是Android
Studio)在编译项目的时候,会为aidl文件生成对应的Java文件。

针对上面这个aidl文件生成的java文件中包含的结构如下图所示:

图片 11

在这个生成的Java文件中,包括了:

  • 一个名称为IRemoteService的interface,该interface继承自android.os.IInterface并且包含了我们在aidl文件中声明的接口方法
  • IRemoteService中包含了一个名称为Stub的静态内部类,这个类是一个抽象类,它继承自android.os.Binder并且实现了IRemoteService接口。这个类中包含了一个onTransact方法
  • Stub内部又包含了一个名称为Proxy的静态内部类,Proxy类同样实现了IRemoteService接口

仔细看一下Stub类和Proxy两个中包含的方法,是不是觉得很熟悉?是的,这里和前面介绍的服务实现是一样的模式。这里我们列一下各层类的对应关系:

C++ Java层 AIDL
BpXXX XXXProxy IXXX.Stub.Proxy
BnXXX XXXNative IXXX.Stub

为了整个结构的完整性,最后我们还是来看一下生成的Stub和Proxy类中的实现逻辑。

Stub是提供给开发者实现业务的父类,而Proxy的实现了对外提供的接口。Stub和Proxy两个类都有一个asBinder的方法。

Stub类中的asBinder实现就是返回自身对象:

@Override
public android.os.IBinder asBinder() {
    return this;
}

而Proxy中asBinder的实现是返回构造函数中获取的mRemote对象,相关代码如下:

private android.os.IBinder mRemote;

Proxy(android.os.IBinder remote) {
    mRemote = remote;
}

@Override
public android.os.IBinder asBinder() {
    return mRemote;
}

而这里的mRemote对象其实就是远程服务在当前进程的标识。

上文我们说了,Stub类是用来提供给开发者实现业务逻辑的父类,开发者者继承自Stub然后完成自己的业务逻辑实现,例如这样:

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
   public int getPid(){
       return Process.myPid();
   }
   public void basicTypes(int anInt, long aLong, boolean aBoolean,
       float aFloat, double aDouble, String aString) {
       // Does something
   }
};

而这个Proxy类,就是用来给调用者使用的对外接口。我们可以看一下Proxy中的接口到底是如何实现的:

Proxy中getPid方法实现如下所示:

@Override
public int getPid() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    int _result;
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
        _reply.readException();
        _result = _reply.readInt();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

这里就是通过Parcel对象以及transact调用对应远程服务的接口。而在Stub类中,生成的onTransact方法对应的处理了这里的请求:

@Override
public 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_getPid: {
        data.enforceInterface(DESCRIPTOR);
        int _result = this.getPid();
        reply.writeNoException();
        reply.writeInt(_result);
        return true;
    }
    case TRANSACTION_basicTypes: {
        data.enforceInterface(DESCRIPTOR);
        int _arg0;
        _arg0 = data.readInt();
        long _arg1;
        _arg1 = data.readLong();
        boolean _arg2;
        _arg2 = (0 != data.readInt());
        float _arg3;
        _arg3 = data.readFloat();
        double _arg4;
        _arg4 = data.readDouble();
        java.lang.String _arg5;
        _arg5 = data.readString();
        this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
        reply.writeNoException();
        return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
}

onTransact所要做的就是:

  1. 根据code区分请求的是哪个接口
  2. 通过data来获取请求的参数
  3. 调用由子类实现的抽象方法

有了前文的讲解,对于这部分内容应当不难理解了。

到这里,我们终于讲解完Binder了。

恭喜你,已经掌握了Android系统最复杂的模块,的其中之一了 :)

– 以上 –

工作过程

首先,我们服务器端有一个可以执行任务的对象需要传递到客户端,然而不同进程之间不可以直接调用对象的方法,从而通过
Binder 来实现进程间的通信。

  1. aidl文件 定义 .aidl 类型文件,其中声明要实现的功能方法

  2. 定义接口 首先,定义 AIDL
    类型的接口,也就是需要传递的对象类型接口,继承 IInterface
    ,并在其中根据 aidl 文件的内容定义了这个类的可以实现功能的抽象方法

  3. 接口中定义内部类 Stub 在接口中定义 Stub
    类,该类实现了我们需要的接口,并继承了 Binder

  4. 服务端实现接口 服务端要定义类实现 Stub
    类,然后完成我们自己定义的接口的抽象方法

  5. Stub 类的实现 Stub 类中定义了 asInterface
    可以返回一个我们需要的类对象,如果是同进程则返回本身,如果是非同进程则返回
    Stub 的内部类 Proxy 代理类对象

  6. 客户端请求
    客户端绑定时服务器返回服务端实现的接口类型的对象,客户端得到的
    Binder 对象就是 Stub 对象,客户端调用 Stub 对象的 asInterface
    方法得到需要的类型对象

  7. 同进程对象工作
    客户端得到需要的对象后,调用其方法,如果是同进程,参数可以直接传递,同时
    asInterface 得到的就是服务端实现的 Stub
    对象,可以直接执行方法返回结果

  8. 跨进程对象工作 如果是跨进程时,asInterface 得到的就是 Stub
    的内部类 Proxy
    类的对象,该对象继承了我们需要的接口,并实现了其抽象方法,Proxu
    的构造需要一个 Stub 类对象

  9. Proxy 的工作过程
    其实现的抽象方法执行时,会先将方法参数序列化,再调用 Stub 方法的
    transact 方法将序列化后的参数,方法 int
    类型的标识传入,线程挂起,服务端在 Binder
    进程中执行任务后将序列化后的结果返回。Proxy
    的工作方法中,得到结果后,将序列化后的结果反序列化成方法的返回值类型,返回。

  10. transact 方法 transact 方法最后会调用 Stub 的 onTransact 方法

  11. Stub 的 onTransact 方法 onTransact 方法执行在服务器进程的 Binder
    线程池中,根据方法标识,将序列化后的参数反序列化,在服务端执行,得到返回值后序列化,最后将结果返回,传回到客户端。客户端处理后完成。

参考资料和推荐读物

  • Android
    Binder
  • Android Interface Definition
    Language
  • Android Bander设计与实现 –
    设计篇
  • Binder系列—开篇
  • 彻底理解Android
    Binder通信架构
  • binder驱动——-之内存映射篇
  • Android Binder机制(一)
    Binder的设计和框架
  • Android Binder
    分析——内存管理

Binder 机制在系统中的应用

Android 系统启动之后会启动很多的 Service,例如 ActivityManagerService
等,在开发中我们可能需要调用这些 Service
的方法,但是由于是不同进程是不可以直接调用的,这时候通过 ServiceManager
我们可以 Binder 机制跨进程拿到 AMS 的代理 ActivityManagerProxy
,通过代理即可实现调用 AMS 的方法。

上面提到了 ServiceManager,那 ServiceManager
又是怎么工作的呢,ServiceManager 其实是 ServiceManagerProxy
的代理,ServiceManagerProxy 是 ServiceManagerNative
的代理,ServiceManagerNative 继承了 IServiceManager ,我们看出来了,原来
ServiceManager 也是通过 Binder 实现跨进程的

我们在应用中使用 ServiceManager 在获取系统服务时,如果 ServiceManager
代理的 ServiceManagerNative 没有初始化,则会通过 Natice 层来通过 Binder
机制完成 ServiceManagerNative
初始化,此时的服务端是系统进程,之后我们就可以使用 ServiceManager
来协助我们获取其他的系统服务了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注