Android Binder机制基本原理

一、概述

  1. Binder是什么?

    • 从功能上讲:Binder是一种在Android设备上进行IPC(Inter-Process Communication,进程间通信)的主要方式,主要用来实现跨进程通信。
    • 从代码上讲:Binder是一个类,实现了IBinder接口。
    • 从Android Framwork角度来说,Binder是ServerManager连接各种Manager和ManagerService的桥梁。
  2. 为什么需要Binder?

    • 进程隔离:为了保证安全性&独立性,一个进程不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的
    • IPC(跨进程通信):在实际开发中,经常需要进程间的合作、交互和通信
    • 进程空间的分配:
      用户空间:数据不可共享,即不可共享空间
      内核空间:数据可以共享,即空闲空间
      在这里插入图片描述
    1. 通过上图可以看到,各个进程的用户空间是无法共享的,为了实现进程间的通信,则需要内核空间作为中介来进行数据的交换。如下图:
      工作流程: 发送进程通过系统调用,将需要发送的数据拷贝到内核空间的缓冲区中。内核服务程序唤醒接收进程的接收线程,通过系统调用将数据发送到接收进程的用户空间中,完成数据的发送。所以这里通过两次拷贝完成了一次数据的发送。在这里插入图片描述
  3. Binder IPC模型

    1. 原理图
      Binder跨进程通信机制模型是基于Cilent-Server模式,即cilent进程-server进程。
      说明:Client进程、Server进程、Service Manager之间的数据交互都需要通过Binder来完成。且Service Manager和Binder驱动都是Android基础架构已经帮写好了的,开发人员只需要创建Client进程和Server进程即可。
      在这里插入图片描述

    2. 模型相关角色

      作用备注
      Client进程使用服务的进程
      Server进程提供服务的进程
      ServerManager进程管理Service的注册和查询
      Binder驱动一种虚拟设备驱动,是链接Service进程、Client进程、Service Manager的桥梁。作用为:1.通过内存映射来传递进程间的数据 2.实现线程控制,采用Binder的线程池,并由Binder驱动自身进行管理
    3. 跨进程通信的基本原理
      核心原理:内存映射
      工作流程:

      1. Binder驱动创建一块接收缓冲区
      2. 在内核空间中确定一块用于接收数据的Buffer,然后将用户空间的Buffer与内核空间的Buffer映射到实际的物理内存上,实现用户空间Buffer与内核空间Buffer的同步化
      3. 由于内核缓冲区&接收进程的用户地址空间存在映射关系,故相当于也发送到了接收进程的用户地址空间,实现了跨进程通信
        在这里插入图片描述

二、根据代码进行分析Binder的工作过程

Android开发中,Binder主要用在Serviec中,包括AIDL和Messenger,其中普通Service中的Binder不涉及进程间通信,无法触及Binder的核心,而Message的底层其实是AIDL,所以可以用AIDL来分析Binder的工作机制。

  1. 创建Book.java Book.aidl IBookManager.aidl 三个文件

    Book.java 实现Parcelable接口

    package com.kanghui.demo.aidl;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class Book implements Parcelable {
        public String bookName;
        public int bookId;
    
        public Book(int bookId, String bookName) {
            this.bookId = bookId;
            this.bookName = bookName;
        }
    
    
        protected Book(Parcel in) {
            bookName = in.readString();
            bookId = in.readInt();
        }
    
        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];
            }
        };
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(bookName);
            dest.writeInt(bookId);
        }
    }
    
    

    Book.aidl 是Book类在AIDL中的声明

    // Book.aidl
    package com.kanghui.demo.aidl;
    
    // Declare any non-default types here with import statements
    
    parcelable Book;
    

    IBookManager.aidl 对外提供获取书籍和添加书籍的方法

    // IBookManager.aidl
    package com.kanghui.demo.aidl;
    
    import com.kanghui.demo.aidl.Book;
    
    // Declare any non-default types here with import statements
    
    interface IBookManager {
    
         List<Book> getBookList();
         void addBook(in Book book);
    
    
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);
    }
    

    通过上面写的相关类,系统会为IBookManager 生成Binder类,在build-generate 目录下生成了IBookManager.java的类

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     */
    package com.kanghui.demo.aidl;
    // Declare any non-default types here with import statements
    
    public interface IBookManager extends android.os.IInterface
    {
      /** Default implementation for IBookManager. */
      public static class Default implements com.kanghui.demo.aidl.IBookManager
      {
        @Override public java.util.List<com.kanghui.demo.aidl.Book> getBookList() throws android.os.RemoteException
        {
          return null;
        }
        @Override public void addBook(com.kanghui.demo.aidl.Book book) throws android.os.RemoteException
        
        /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
        @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.kanghui.demo.aidl.IBookManager
      {
        private static final java.lang.String DESCRIPTOR = "com.kanghui.demo.aidl.IBookManager";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
          this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.kanghui.demo.aidl.IBookManager interface,
         * generating a proxy if needed.
         */
        public static com.kanghui.demo.aidl.IBookManager asInterface(android.os.IBinder obj)
        {
          if ((obj==null)) {
            return null;
          }
          android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
          if (((iin!=null)&&(iin instanceof com.kanghui.demo.aidl.IBookManager))) {
            return ((com.kanghui.demo.aidl.IBookManager)iin);
          }
          return new com.kanghui.demo.aidl.IBookManager.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_getBookList:
            {
              data.enforceInterface(descriptor);
              java.util.List<com.kanghui.demo.aidl.Book> _result = this.getBookList();
              reply.writeNoException();
              reply.writeTypedList(_result);
              return true;
            }
            case TRANSACTION_addBook:
            {
              data.enforceInterface(descriptor);
              com.kanghui.demo.aidl.Book _arg0;
              if ((0!=data.readInt())) {
                _arg0 = com.kanghui.demo.aidl.Book.CREATOR.createFromParcel(data);
              }
              else {
                _arg0 = null;
              }
              this.addBook(_arg0);
              reply.writeNoException();
              return true;
            }
            case TRANSACTION_basicTypes:
            {
              data.enforceInterface(descriptor);
              int _arg0;
              _arg0 = data.readInt();
              long _arg1;
              _arg1 = data.readLong();
              boolean _arg2;
              _arg2 = (0!=data.readInt());
              float _arg3;
              _arg3 = data.readFloat();
              double _arg4;
              _arg4 = data.readDouble();
              java.lang.String _arg5;
              _arg5 = data.readString();
              this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
              reply.writeNoException();
              return true;
            }
            default:
            {
              return super.onTransact(code, data, reply, flags);
            }
          }
        }
        private static class Proxy implements com.kanghui.demo.aidl.IBookManager
        {
          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 java.util.List<com.kanghui.demo.aidl.Book> getBookList() throws android.os.RemoteException
          {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            java.util.List<com.kanghui.demo.aidl.Book> _result;
            try {
              _data.writeInterfaceToken(DESCRIPTOR);
              boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
              if (!_status && getDefaultImpl() != null) {
                return getDefaultImpl().getBookList();
              }
              _reply.readException();
              _result = _reply.createTypedArrayList(com.kanghui.demo.aidl.Book.CREATOR);
            }
            finally {
              _reply.recycle();
              _data.recycle();
            }
            return _result;
          }
          @Override public void addBook(com.kanghui.demo.aidl.Book book) 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 ((book!=null)) {
                _data.writeInt(1);
                book.writeToParcel(_data, 0);
              }
              else {
                _data.writeInt(0);
              }
              boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
              if (!_status && getDefaultImpl() != null) {
                getDefaultImpl().addBook(book);
                return;
              }
              _reply.readException();
            }
            finally {
              _reply.recycle();
              _data.recycle();
            }
          }
          /**
               * Demonstrates some basic types that you can use as parameters
               * and return values in AIDL.
               */
          @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
          {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            try {
              _data.writeInterfaceToken(DESCRIPTOR);
              _data.writeInt(anInt);
              _data.writeLong(aLong);
              _data.writeInt(((aBoolean)?(1):(0)));
              _data.writeFloat(aFloat);
              _data.writeDouble(aDouble);
              _data.writeString(aString);
              boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
              if (!_status && getDefaultImpl() != null) {
                getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
                return;
              }
              _reply.readException();
            }
            finally {
              _reply.recycle();
              _data.recycle();
            }
          }
          public static com.kanghui.demo.aidl.IBookManager sDefaultImpl;
        }
        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        public static boolean setDefaultImpl(com.kanghui.demo.aidl.IBookManager impl) {
          if (Stub.Proxy.sDefaultImpl == null && impl != null) {
            Stub.Proxy.sDefaultImpl = impl;
            return true;
          }
          return false;
        }
        public static com.kanghui.demo.aidl.IBookManager getDefaultImpl() {
          return Stub.Proxy.sDefaultImpl;
        }
      }
      public java.util.List<com.kanghui.demo.aidl.Book> getBookList() throws android.os.RemoteException;
      public void addBook(com.kanghui.demo.aidl.Book book) throws android.os.RemoteException;
      /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
      public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
    }
    
    

    这个类IBookManager.java继承了IInterface,它本身也是一个接口。接口本身申明了两个方法:getBookList()和addBook。同时申明了两个ID标识这两个方法,这两个id用于表示在transact过程中客户端到底请求的是哪个方法。

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

    其次,申请了一个内部类Stub继承自Binder,当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的transact过程,而当两者位于不同进程是,方法调用需要走transct过程。这个逻辑由Stub的内部代理类Proxy来完成。

    主要方法介绍:

    介绍
    DESCRIPTORBinder的唯一标识,一般用当前的Binder的类名表示,如com.kanghui.demo.aidl.IBookManager
    asInterface(android.os.IBinder obj)将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象。
    asBinder用于返回当前的Binder对象
    onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)这个方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,服务端根据code确定目标方法,从data参数中取出所需参数,执行完后向apply写入返回值。
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值