Binder机制原理

13 阅读6分钟

1.Binder是什么?

  • 机制:Binder是一种进程间通信机制。
  • 驱动:Binder是一个虚拟物理设备驱动
  • 应用层:Binder是一个能够发起通信的java类

2.多进程的使用以及优势

虚拟机分配给各个进程的运行内存是有限制的,LMK也会优先回收对系统资源占用多的进程

  • 突破进程内存限制
  • 功能稳定性 ,独立的通信进程保持长连接的稳定性。(极光推送,百度定位)
  • 规避系统内存泄漏:独立的WebView进程阻隔内存泄漏导致的问题。
  • 隔离风险,对于不稳定的功能放入到独立进程,避免导致主进程的崩溃.

3.Linux中进程间的通信机制有哪些?与传统的IPC机制相比,有哪些优势?

1732615212620.png

Binder 共享内存 socket 管道 消息队列 信号 ,信号量

  • Binder:拷贝一次+内存映射 基于CS架构,易用性强(Service>>binder >>分配uid 【如果是恶意软件,通过uid找到,很安全】) ,双向通信

  • 共享内存: 无需拷贝 控制复杂,易用性差 (多线程使用同一块内存时,可能出现死锁,数据不同步问题,访问接入点事开放的,不安全) mmap原理实现 ,双向通信

  • socket : 拷贝二次 基于CS架构,效率低,开销大 (访问接入点是开放的,不安全),双向通信

  • 管道Pipe: 拷贝二次,数据传输也是单向的,一个进程向管道写入数据,另一个进程从管道读取数据. image.png

  • 消息队列:拷贝二次,消息队列是消息的链表,存放在内核中,每个消息队列都有队列id来标识,独立与发送和接收进程,进程终止时,消息队列中的内容不会被删除,也可以实现随机查询,消息不一定要以先进先出的次序读取,也可以按照消息的类型或者优先级读取. image.png

  • 信号 (比如Vsync)是基于事件的异步通知,而不是数据的拷贝,当某个时间发生时,内核会向目标进程发送一个信号,信号会被添加到目标进程的信号队列中,当进程从内核态返回用户态时,内核会检查信号队列,并根据注册的信号处理函数来处理信号.【无需拷贝】

注意:有些资料说是4次拷贝(发送进程的用户空间>>发送进程内核空间缓冲区>>内存>>用户进程内核缓冲区>>用户进程用户空间),也可以简化为2次拷贝(用户空间 >>内核缓冲区>>用户空间)

4.Binder通信原理(一次拷贝+ 内存映射)

  • 具体过程:
  1. 数据接收方进程在初始化的时候,会直接调用mmap函数,通过Binder驱动,提前在内核空间开辟一块共享的内核缓冲区,并映射到自己的用户空间.

  2. 发送方进程(无需通过Binder驱动在内核开辟共享的物理内存)将数据直接拷贝到这一块内核缓冲区,由于接收方的用户空间已经映射了同一块内核缓冲区,它无需再次拷贝,可以直接读取.

  • 在完整的一次Binder远程方法调用中,客户端和服务端的角色是动态转换的
  1. 当发起请求时客户端是数据发送进程,服务端(AMS)是数据接收进程。
  2. 当返回结果时服务端(AMS)是数据发送进程,客户端是数据接收进程。

这就好比双方在翻译官(内核)的办公室里放了一个共享的公文袋(内核缓冲区) 。客户端直接把文件放进公文袋,服务端伸手就从同一个袋子里拿,省去了翻译官中间转交的步骤。

image.png

5.MMAP(Memory Map)内存映射的原理

  • 虚拟内存划分 1732617169964.png

  • 内存映射原理?

内存映射简单的讲:数据接收方进程在进程是初始化内核空间的一块内存区域映射到自己内核空间,映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间提高了通信速度。

6.Binder通过Java代码是如何实现的呢?

6.1.服务端,客户端BookManager.aidl文件,根据aidl接口,系统自动帮忙生成Stub类继承Binder并实现BookManager接口【服务端和客户端生成的代码是一样的,只是调用逻辑不一样而已】

  • BookManager.aidl文件
   interface BookManager{
        List<Book> getBookList();
   }

6.2.根据aidl接口,自动生成BookManager.java类(aidl就是对binder的封装)

//SDK提供
public interface IBinder {
   int FIRST_CALL_TRANSACTION = 1;
    boolean isBinderAlive();
}
//SDK提供
public class Binder implements IBinder {
    public boolean isBinderAlive() {
        throw new RuntimeException("Stub!");
    }
}
 //SDK提供
public interface IInterface {
    IBinder asBinder();
}

 //系统生成
public interface BookManager extends android.os.IInterface {

      public static abstract class Stub extends Binder implements BookManager {
           //自动生成的TRANSACTION_getBookList  
            static final int  TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
             private static final  String DESCRIPTOR = "com.lypeer.ipcclient.BookManager";  
             public Stub() {
                this.attachInterface(this, DESCRIPTOR);
             }
             //把IBinder对象转BookManager接口的,如果需要的话,就生成一个Proxy代理类
             public static BookManager asInterface(IBinder obj) {
                 if ((obj == null)) {
                      return null;
                 }
                //此处得到的iin==null
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//iin ==null
                if (((iin != null) && (iin instanceof BookManager))) {
                   return ((com.lypeer.ipcclient.BookManager) iin); //null
                }
                 //因为iin==null,所以此处只会生成一个代理类
                 return new com.lypeer.ipcclient.BookManager.Stub.Proxy(obj);   
             }  
             //返回IBinder的实现类
             public android.os.IBinder asBinder() {
                return this;
              }
   
            private static class Proxy implements BookManager{
                private android.os.IBinder mRemote;
                 Proxy(android.os.IBinder remote) {
                      mRemote = remote;
                 }
                 public IBinder asBinder()  {
                    return mRemote;
                 } 
                //客户端调用getBookList
                 public   List<Book> getBookList() {
                       Parcel _data = android.os.Parcel.obtain();
                       Parcel _reply = android.os.Parcel.obtain();
                       List<Book> _result;
                         try {
                              _data.writeInterfaceToken(DESCRIPTOR);
                               //直接调用服务端transact方法
                               boolean _status = mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
                               if (!_status && getDefaultImpl() != null) {
                                   return getDefaultImpl().getBookList();
                               }
                               _reply.readException();
                               _result = _reply.createTypedArrayList(com.lypeer.ipcclient.Book.CREATOR);
                              }finally{
                               _reply.recycle();
                               _data.recycle();
                          }
                         return _result;
                  }
           }
            // 服务端执行onTransact根据code码进行处理
            public boolean onTransact(int code,Parcel data ,Parcel reply,int flags){
                    java.lang.String descriptor = DESCRIPTOR;
                    switch(code){
                         case TRASACTION_getBookLIst:{
                                //检查客户端调用的接口是否与服务端提供的接口一致
                                data.enforceInterface(descriptor);
                                List<com.lypeer.ipcclient.Book> _result = this.getBookList();
                                reply.writeNoException();
                                reply.writeTypedList(_result);
                                return true;
                         }
                     }
            }
      }
}

6.3.客户端调用

public class AIDLActivity extends AppCompatActivity {
      private BookManager mBookManager = null;
      protected void onStart() {
           attemptToBindService();
    }

   //尝试与服务器建立连接
   private void attemptToBindService() {
        Intent intent = new Intent();
        intent.setAction("com.lypeer.aidl");
        intent.setPackage("com.lypeer.ipcserver");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }
      private ServiceConnection mServiceConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(getLocalClassName(), "service connected");
            mBookManager = BookManager.Stub.asInterface(service); //得到Proxy对象
            mBound = true;
            if (mBookManager != null) {
                try {
                    mBooks = mBookManager.getBooks();
                    Log.e(getLocalClassName(), mBooks.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
         }
        public void onServiceDisconnected(ComponentName name) {
            Log.e(getLocalClassName(), "service disconnected");
            mBound = false;
        }
    };
    //mBookManager.getBookList>>Proxy.getBookList>>Proxy.mRemote.onTransact(Stub.TRANSACTION_getBookList)
    public getBookList(){
           if(mBookManager!=null){
              //回调Proxy类中的getBookList();
              mBookManager.getBookList();
           }
    }
}

6.4.服务端实现代码

public class AIDLService extends Service{
        //包含Book对象的list
       private List<Book> bookList = new ArrayList<>();
        //实现抽象类Stub,Stub实现了BookManager接口
       private final BookManager.Stub mBookManager=new BookManager.Stub(){
               public List<Book> getBookList(){
                    return bookList;
               }
        }
       public void onCreate() {
            Book book = new Book();
            book.setName("Android开发艺术探索");
            book.setPrice(28);
            bookList.add(book);
            super.onCreate();
      }
      public IBinder onBind(Intent intent) {
          return mBookManager;
      }
}