Android

Android Binder解析

2022-03-11  本文已影响0人  漆先生

Binder是Android中一种跨进程通信方式,还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder。
从Framework角度来说,Binder又是ServiceManager连接各种Manager和相应ManagerService的桥梁,从应用层来说,它是客户端和服务端进行通信的媒介,绑定服务的时候服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据。

一、创建AIDL

//Book.java
package com.qijinfeng.jvm;

import android.os.Parcel;
import android.os.Parcelable;

class Book implements Parcelable {
    public int bookId;
    public String bookName;

    protected Book(Parcel in) {
        bookId = in.readInt();
        bookName = in.readString();
    }

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

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

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

//Book.aidl
package com.qijinfeng.jvm;
parcelable Book;

//IBookManager.aidl
package com.qijinfeng.jvm;
import com.qijinfeng.jvm.Book;


interface IBookManager {
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);
    List<Book> getBookList();
    void adddBook();
}

二、内部方法解析

build/generated/aidl_source_output_dir/debug/out目录下会自动生成一个IBookManager.java文件,它继承了IInterface接口。

IBookManager.java里边声明了两个方法getBookList和addBook

  public java.util.List<com.qijinfeng.jvm.Book> getBookList() throws android.os.RemoteException;
  public void adddBook() throws android.os.RemoteException;

同时声明了两个整型的id,标识两个方法,用于在transact过程中判断客户端发送请求的到底是哪个方法。

    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_adddBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

声明了一个内部类Stub,是一个Binder派生类,客户端和服务端都位于同一个进程时,方法不会走跨进程transact过程,而当连着处于不同的进程,就会走transact过程,这个邮它的内部类Proxy来完成。

 public static abstract class Stub extends android.os.Binder implements com.qijinfeng.jvm.IBookManager
  {
    private static class Proxy implements com.qijinfeng.jvm.IBookManager
    {
    }
  }

1.DESCRIPTOR

Binder的唯一标识,一般用单签Binder的类名标识。

    private static final java.lang.String DESCRIPTOR = "com.qijinfeng.jvm.IBookManager";

2.asInterface(android.os.IBinder obj)

用户将服务端的Binder对象转换陈客户端所需的AIDL对象,这种转换是区分进程的,同一进程返回的是服务端的Stub对象本身,否则是系统封装后的Stub.proxy对象。

3.asBinder()

返回当前的Binder对象。

4.onTransact

这个方法运行于服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由次方法来处理。参数code确定客户端的请求目标方法,参数data存放数据,请求完成后,reply中写入返回值,onTransact如果返回false,客户端会请求失败,可以用这个特性来做权限验证。

5.Proxy#getBookList和Proxy#addBook

这个方法运行在客户端,当客户端远程调用次方法时。

image.png

6.linkToDeath和unlinkToDeath

Binder运行于服务端,可能由于某种原因异常终止,这个时候我们到服务端的Binder连接已经断裂。会导致调用远程失败,客户端功能受到影响。
Binder中提供linkToDeath和unlinkToDeath方法,通过linkToDeath给Binder设置死亡代理,当Binder死亡时,我们会收到用纸,就可以重新发起连接请求,从而恢复连接。

class MainActivity2 : AppCompatActivity() {

    var mIBookManager: IBookManager? = null

    val mConn = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            mIBookManager = IBookManager.Stub.asInterface(service);
            try {
                service!!.linkToDeath(mDeathRecipient!!, 0);
            } catch (e: RemoteException) {
                e.printStackTrace()
            }
        }

        override fun onServiceDisconnected(name: ComponentName?) {

        }
    }
    var mDeathRecipient: IBinder.DeathRecipient? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        mDeathRecipient = IBinder.DeathRecipient {
            if (mIBookManager == null)
                return@DeathRecipient
            mIBookManager!!.asBinder().unlinkToDeath(mDeathRecipient!!, 0);
            mIBookManager = null
            val intent = Intent(this, BookService::class.java)
            bindService(intent, mConn, AppCompatActivity.BIND_AUTO_CREATE);
        }
        val intent = Intent(this, BookService::class.java)
        bindService(intent, mConn, BIND_AUTO_CREATE);
    }

    override fun onDestroy() {
        unbindService(mConn)
        super.onDestroy()
    }

三、Binder连接池

Binder连接池的主要作用是将每个业务模块请求统一发到远程Service中去执行,从而避免重复创建Service的过程。


image.png

1.创建两个或者多个AIDL接口

ISecurityCenter.aidl

interface ISecurityCenter {
    String encrypt(String content);
    String decrypt(String password);
}

IComputer .aidl

interface IComputer {
    int add(int a,int b);
}

2.实现AIDL接口

SecurityCenterImpl.java

public class SecurityCenterImpl extends ISecurityCenter.Stub {
   private static final char SECRET_CODE = '^';
    @Override
    public String encrypt(String content) throws RemoteException {
        char[] chars = content.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            chars[i] ^=SECRET_CODE;
        }
        return new String(chars);
    }

    @Override
    public String decrypt(String password) throws RemoteException {
        return encrypt(password);
    }
}

ComputerImpl.java

public class ComputerImpl extends IComputer.Stub {
    @Override
    public int add(int a, int b) throws RemoteException {
        return a + b;
    }
}

3.创建Binder连接池AIDL

interface IBinderPool {
    IBinder queryBinder(int binderCode);
}

4.创建Service

class BinderPoolService : Service() {
    private val mBinderPool = BinderPool.BinderPoolImpl()
    override fun onBind(intent: Intent?): IBinder? {
        return mBinderPool
    }
}

Binder连接池实现

public class BinderPool {
    public static final int BINDER_NONE = -1;
    public static final int BINDER_COMPUTE = 0;
    public static final int BINDER_SECURITY_CENTER = 1;

    private Context mContext;
    private IBinderPool mBinderPool;
    private static volatile BinderPool mInstance;
    private CountDownLatch mConnectBinderPoolCountDownLatch;

    private BinderPool(Context context) {
        mContext = context.getApplicationContext();
        connectBinderPoolService();
    }

    public static BinderPool getInstance(Context context) {
        if (mInstance == null) {
            synchronized (BinderPool.class) {
                if (mInstance == null) {
                    mInstance = new BinderPool(context);
                }
            }
        }
        return mInstance;
    }

    private synchronized void connectBinderPoolService() {
        mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
        Intent intent = new Intent(mContext, BinderPoolService.class);
        mContext.bindService(intent, mBindPoolConnection, Context.BIND_AUTO_CREATE);
        try {
            mConnectBinderPoolCountDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public IBinder queryBinder(int binderCode) {
        IBinder binder = null;
        if (mBinderPool != null) {
            try {
                binder = mBinderPool.queryBinder(binderCode);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        return binder;
    }

    private ServiceConnection mBindPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            mConnectBinderPoolCountDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("123456"+name);
        }
    };

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = () -> {
        mBinderPool.asBinder().unlinkToDeath(mInstance.mBinderPoolDeathRecipient, 0);
        mBinderPool = null;
        connectBinderPoolService();
    };

    public static class BinderPoolImpl extends IBinderPool.Stub {

        public BinderPoolImpl(){
            super();
        }

        @Override
        public IBinder queryBinder(int binderCode) {
            IBinder binder = null;
            switch (binderCode) {
                case BINDER_SECURITY_CENTER:
                    binder = new SecurityCenterImpl();
                    break;
                case BINDER_COMPUTE:
                    binder = new ComputerImpl();
                    break;
                default:
                    break;
            }
            return binder;
        }
    }
}

首先去绑定服务,绑定服务后,客户端可以通过它的queryBinder方法区获取各自对应的Binder。
通过CountDownLatch将bindService这一异步的操作转换成同步操作。Binder的调用过程可能是耗时的,因此不建议在主线程执行。
BinderPool可以方便日常AIDL的开发,如果需要添加新的AIDL,只需要实现自己的AIDL之后,把BinderPoolImpl中的queeyBinder方法进行修改,添加一个新的binderCode并返回对应的Binder对象即可。

上一篇下一篇

猜你喜欢

热点阅读