android的Binder机制入门


正文

android的Binder机制是IPC中非常重要的,可以说android中的绝大部分IPC都是用binder实现的,有句话叫“无binder,不android”

从framework角度来看,ServiceManager连接各种Manager(如WindowManager、ActivityManager等)的桥梁

从app层来看,是客户端服务端通信的媒介

往往通过编写aidl文件来实现。

aidl编译会生成一个java文件,本文以后边的代码为例来说明,后边的代码就是aidl文件编译生成的java文件,来源于AidlClient这个module中
首先这个java文件是个接口,继承自android.os.IInterface,
aidl实际上是个中间文件,或者说android提供给大家的一种简单实现ipc的方式,本质上还是用到了这个接口类

然后这个接口内部主要由一个抽象类Stub,还有若干个函数,这些函数就是aidl文件中定义的函数,这是要进行ipc调用的函数.

主要3个类的关系如下图所示.


Stub是个Binder类,是个抽象类,真正实现在service内部,通过onBind获取。
public class MyService extends Service {
    ......

    @Override
    public IBinder onBind(Intent intent) {
        LogUtil.d("onBind process name " + SystemUtil.getCurProcessName(MyService.this));
        return mBinder;
    }

    IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {

        @Override
        public int getCount() throws RemoteException {
            return count;
        }

        @Override
        public double complexCal(String str, int t) throws RemoteException {
            LogUtil.d("complexCal real " + SystemUtil.getCurProcessName(MyService.this));
            int  ret=str.hashCode()+t;
            return ret*0.3;
        }
    };

}

一般来说我们的流程是bindservice,onServiceConnected,然后在onServiceConnected回调里进行IPC。常见代码像这样。

        public void onServiceConnected(ComponentName name, IBinder service) {
            myAIDLInterface = IMyAidlInterface.Stub.asInterface(service);
            try {
                int cnt = myAIDLInterface.getCount();
                }
                。。。
        }

onServiceConnected回来的是binder的一个proxy,通过asInterface转化为Proxy,而Proxy就是客户端和服务端通信的中介。真正的binder在Service进程内,但是每个进程都可以去要一个代理,这是个CS结构。去bind 那个 service,就会得到一个代理。真正的binder只有一个,但是代理可以有很多个。


getCount方法如下,首先把数据写到_data,然后调mRemote的transact,会导致服务端的Binder调用onTransact调用。这就完成了IPC。


       public int getCount() 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_getCount, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }


再仔细看看

Stub是个啥?
  public static abstract class Stub extends android.os.Binder implements com.aidl.server.IMyAidlInterface 
  注意他是个静态类,继承了Binder,而Binder实现了IBinder
Stub里面有神马?
一个asInterface,一个asBinder,一个onTransact,还有个Proxy类,这些都是干啥的
先看asInterface方法
      public static com.aidl.server.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.aidl.server.IMyAidlInterface))) {
                return ((com.aidl.server.IMyAidlInterface) iin);
            }
            return new com.aidl.server.IMyAidlInterface.Stub.Proxy(obj);
        }




首先要有个客户端和服务端的概念,我们可以认为这是2个进程。service执行的地方时在服务端的binder线程池中,客户端就是bindService或者startService的那个进程。当然客户端和服务端可以是同一个进程,那我们还要IPC干嘛??岂不是多此一举?所以asInterface做了一件事情,他来判断一下,客户端进程是否和服务端进程是同一个进程,如果是就返回((com.aidl.server.IMyAidlInterface) iin),实际上就是返回Stub对象;而如果不在同一个进程就new 一个proxy对象,要走ipc通道。判断是否同一个进程,主要通过queryLocalInterface方法。


asBinder就是返回this指针,没啥好说的
onTransact,他运行在服务端的binder线程池中,等客户端发起跨进程调用的时候,会执行onTransact方法,来实现客户端数据和方法名读取,方法执行,存储结果等功能
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
code代表aidl里的某个方法的标识,对应这种static final int TRANSACTION_getCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
data代表客户端存进来的数据,是序列化的

reply是方法返回值存储的地方,也是序列化的
实际上进程之间传递的数据都是序列化的,双方约定好方法和数据和返回值怎么存储,就能进行准确的读和写


还剩个Proxy,跨进程调用通过他来实现,注意Proxy这个东西是属于客户端的
Proxy有什么?
看此处的例子,有成员变量mRemote,成员函数asBinder(),getCount(),complexCal()
mRemote是个IBinder对象,在前文的asInterface传入,代表了服务端binder对象,asBinder()就是返回mRemote
再看getCount,就是将函数名和参数序列化,然后调用mRemote.transact(Stub.TRANSACTION_getCount, _data, _reply, 0);
这个transact会调用服务端的onTransact,然后完成真正的函数执行,返回值存到_reply中
complexCal和getCount类似,不多说
这么看来最核心的,就是proxy内的transact调用了Binder内的onTransact,这里就是最核心的跨进程.注意跨进程调用的时候,客户端方会挂起当前线程,等待服务端处理数据,服务端处理完了会通知客户端。
而写服务端的时候要注意同步,有时候需要加synchronized锁,因为可能有几个客户端同时调用某个方法


代码



/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: /Users/fish/AndroidStudioProjects/FishProject/AidlServer/src/main/aidl/com/aidl/server/IMyAidlInterface.aidl
 */
package com.aidl.server;
// Declare any non-default types here with import statements

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

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

        /**
         * Cast an IBinder object into an com.aidl.server.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.aidl.server.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.aidl.server.IMyAidlInterface))) {
                return ((com.aidl.server.IMyAidlInterface) iin);
            }
            return new com.aidl.server.IMyAidlInterface.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_getCount: {
                    data.enforceInterface(DESCRIPTOR);
                    int _result = this.getCount();
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                case TRANSACTION_complexCal: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    int _arg1;
                    _arg1 = data.readInt();
                    double _result = this.complexCal(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeDouble(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.aidl.server.IMyAidlInterface {
            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 getCount() 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_getCount, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

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

        static final int TRANSACTION_getCount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_complexCal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    public int getCount() throws android.os.RemoteException;

    public double complexCal(java.lang.String str, int t) throws android.os.RemoteException;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值