Binder IPC跨进程通讯学习记录

IPC跨进程通讯的方式有 socket/管道/广播/binder,在android 中用的最广泛的就是binder几乎底层通讯都是使用binder来处理的例如:ActivityThread 和 IApplication等等,少数使用了socket 例如在zogit系统启动的时候。

目录

binder通讯原理

代码调用流程

binder优点


binder通讯原理

在手机系统中我们可以创建很多app,每一个app就是一个进程,每个进程/线程的内存都是独立的,不是数据共享的。
但是在系统内核中内存是共享的,所以我们要想实现夸进程就需要通过内核层的内存实现数据交互/共享。
内核中内存的数据共享就是通过binder驱动来实现的。

不同进程之间数据交互是通过内核层的‘内存共享’实现的,个人理解他的思想就和我们的 多线程开发 道理很相似:多个线程之间是不能直接交互数据的,每个线程都有自己的工作内存,每个线程工作完后就会把数据拷贝到主内存中,然后其他线程才能获取到新数据。

binder在android系统中分为三层:
1.java层就是我们的Application层。
2.jni层过度层,帮助我们java层和c/c++层传递数据
3.c/c++层 binder 驱动层 核心层

我们重点需要了解的有java层 和 binder驱动层,java层也就是我们直接使用的层面主要有 IBinder 接口 和 Binder类以及IInterface接口,Binder实现了 IBinder 接口,有些重要的方法,接下来在做分析。
binder驱动层有binder.c 和 binder.h 文件,binder在底层有很多 结构体比如binder_node等等。
我们应用层每创建一个service,底层就对应创建一个binder实体,binder实体链接了我们的serve端和client端,并且根据具体的discriptor去通知serviceManager去返回对应的service对象给client使用。

代码调用流程

  1. service的注册
    我们需要注意的是两个接口和一个类1.IInterface 2. IBinder 3. Binder
    1. IInterface
    /**
     * Base class for Binder interfaces.  When defining a new interface,
     * you must derive it from IInterface.
    翻译:必须要实现的接口,当创建binder子类时候
     */
    public interface IInterface
    {
        /**
         * Retrieve the Binder object associated with this interface.
         * You must use this instead of a plain cast, so that proxy objects
         * can return the correct result.
         */
        public IBinder asBinder();
    }
    

    通过注释我们可以看到 我们创建binder子类时候,必须要实现的接口。所以:创建一个接口IClient

    public interface IClient extends android.os.IInterface {
        public void take(com.parrot.car.aidl.Book x) throws android.os.RemoteException;
    
        /** Local-side IPC implementation stub class. */
        public static abstract class Stub extends android.os.Binder implements com.parrot.car.aidl.IClient {

    绑定当前binder对象到IInterface接口

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

    2. IBinder 接口有一个重要的方法

    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
            throws RemoteException;

    3. Binder 类
    BInder类中有一个内部类BinderProxy这个内部类主要是链接Jni层的代理类
    binder中实现的Ibinder接口的方法

        /**
         * Default implementation rewinds the parcels and calls onTransact.  On
         * the remote side, transact calls into the binder to do the IPC.
         */
        public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
                int flags) throws RemoteException {
            if (false) Log.v("Binder", "Transact: " + code + " to " + this);
            Log.e("---bbb-----","----transact----");
            if (data != null) {
                data.setDataPosition(0);
            }
            boolean r = onTransact(code, data, reply, flags);
            if (reply != null) {
                reply.setDataPosition(0);
            }
            return r;
        }

    这个方法是被我们客户端直接调用的。

    // Entry point from android_util_Binder.cpp's onTransact
    //翻译:被jni 层的 android_util_Binder.cpp 的 onTransact 方法调用
        private boolean execTransact(int code, long dataObj, long replyObj,
                int flags) {
            BinderCallsStats binderCallsStats = BinderCallsStats.getInstance();
            BinderCallsStats.CallSession callSession =  
            ....
                res = onTransact(code, data, reply, flags);
            } catch (RemoteException|RuntimeException e) {
      
            ...
          
            return res;
        }

    这个方法是被系统底层jni层调用的,application层不直接调用
    关于BinderProxy是底层的代理类,直接访问的是JNI层

    /**
     * Java proxy for a native IBinder object.
     * Allocated and constructed by the native javaObjectforIBinder function. Never allocated
     * directly from Java code.
     */
    final class BinderProxy implements IBinder {

    上面是java层重要的类,整个通讯的开始是从serve端向serviceManager注册service对象,首先serve端的Stub构造方法中会根据这个DISCRIPPOR字段把当前的service绑定到IInterface上。service对象会被注册到serviceManager中根据,在native层service是以binder实体存在,每个service在binder驱动中都有一个binder实体。

  2. client获取service对象
    客户端通过binderService()调用
         /**
             * Cast an IBinder object into an com.parrot.car.aidl.IClient interface,
             * generating a proxy if needed.
             */
            public static com.parrot.car.aidl.IClient asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.parrot.car.aidl.IClient))) {
                    return ((com.parrot.car.aidl.IClient) iin);
                }
                return new com.parrot.car.aidl.IClient.Stub.Proxy(obj);
            }

    会根据这ESCRIPTOR到serviceManager中获取service对象。

  3. 调用方法传递数据

binder优点

1.binder的数据传输的时候只需要拷贝一次,而其他通讯需要拷贝两次,所以极大的降低了底层的耗时。
2.binder的安全性,因为binder在通讯时系统会先通过uid和pid的验证,然后才通讯。
3.binder是使用C/S的通讯,client和serve通讯简单方便,而且binder是liunx自带的通讯方式。

Binder 实例: https://github.com/WangRain1/aidl

参考学习: https://www.cnblogs.com/xinmengwuheng/p/7070167.html
                   https://www.cnblogs.com/mingfeng002/p/10696023.html

发布了119 篇原创文章 · 获赞 140 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/WangRain1/article/details/90901591
今日推荐