0
点赞
收藏
分享

微信扫一扫

Binder

独孤凌雪 2021-09-28 阅读 86
Android

大家都知道,如果被问到binder,第一时间都会答是用来进程间通讯。那到底是怎么通讯的?我们一般用AIDL来实现,如果你完全没用过AIDL,可以先看这个:AIDL简单实现进程间通讯
那么,问题来了。

问题一:binder是什么?

①内核层的binder驱动 ②Binder的Java类
通过实现Binder的IBinder接口,可以获得进程间通讯的能力。

问题二:binder是用于进程间通讯,用在哪些地方,为什么要用?

如果一个APP分配多个进程,可以达到扩大内存的效果;而且一个进程的崩溃,也不会造成APP直接崩溃,隔离了部分的风险。
一般放到另一个进程的功能点有:webview、图片下载、文件下载处理等。

已经知道了是什么,和用在哪里了,接下来就要对比下binder的优缺点。

①共享内存,可以理解为线程安全,由于涉及锁和原子性等问题,会导致难以操控。
②socket,性能上,会比binder消耗得多。
③在手机端,由于binder可以为访问的APP分配UID,自己的服务进程也支持是否给外部调用,安全性非常好。

binder是怎么做到的进程间通讯?


①发送方通过binder协议,打包好数据,通过copy_from_user把数据拷贝一次到内核地址空间。
②利用mmap方法,使得内核空间的地址和接收方的空间地址,都映射到同一个物理内存中。
由于内核空间和接收方的进程空间,都指向了同一个物理内存,所以当发送方发送数据时,数据不需要再一次从内内核中copy到接收方中,从而省掉了一次数据的拷贝。

举个例子:平常我们的把数据写到本地文件的功能,其实是分为2步的,第一步是把数据传输到内核层,然后内核层再把数据传输到本地文件,这种就是经历过2次的数据copy。

而binder就不需要,由于mmap的处理,等于我们可以直接把用户层的东西,只传一次给内核层,就达到了我们想要的效果。

AIDL实现原理
/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.tonydash.aidl.bean;
public interface IPersonAidlInterface extends android.os.IInterface
{
  /** Default implementation for IPersonAidlInterface. */
  public static class Default implements com.tonydash.aidl.bean.IPersonAidlInterface
  {
    @Override public void addPersonIn(com.tonydash.aidl.bean.Person person) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.tonydash.aidl.bean.IPersonAidlInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.tonydash.aidl.bean.IPersonAidlInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.tonydash.aidl.bean.IPersonAidlInterface interface,
     * generating a proxy if needed.
     */
    public static com.tonydash.aidl.bean.IPersonAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.tonydash.aidl.bean.IPersonAidlInterface))) {
        return ((com.tonydash.aidl.bean.IPersonAidlInterface)iin);
      }
      return new com.tonydash.aidl.bean.IPersonAidlInterface.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
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_addPersonIn:
        {
          data.enforceInterface(descriptor);
          com.tonydash.aidl.bean.Person _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.tonydash.aidl.bean.Person.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addPersonIn(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.tonydash.aidl.bean.IPersonAidlInterface
    {
      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 void addPersonIn(com.tonydash.aidl.bean.Person person) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((person!=null)) {
            _data.writeInt(1);
            person.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          boolean _status = mRemote.transact(Stub.TRANSACTION_addPersonIn, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addPersonIn(person);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.tonydash.aidl.bean.IPersonAidlInterface sDefaultImpl;
    }
    static final int TRANSACTION_addPersonIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public static boolean setDefaultImpl(com.tonydash.aidl.bean.IPersonAidlInterface impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.tonydash.aidl.bean.IPersonAidlInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public void addPersonIn(com.tonydash.aidl.bean.Person person) throws android.os.RemoteException;
}

这个文件是Androidstudio帮我们自动生成的,代码很多,但需要注意的有几点:
①Stub类继承Binder类,并实现我们自己自定义的aidl接口类。
②asInterface方法,会判断是否同一个进程,同进程直接返回binder,不同进程就创建一个代理类。
③代理类主要是要来实现我们自定义的接口方法的,通过mRemote.transact方法,打包数据,发送给内核层的binder驱动。
④mRemote.transact调用后,线程会挂起,等待服务端返回。
⑤Stub类中有onTransact方法,就是用于接收消息并分发的。

举报

相关推荐

0 条评论