Android进阶知识(五):IPC基本概念之Binder、Binder工作机制及其原理

Android进阶知识(五):IPC基本概念之Binder、Binder工作机制及其原理

  Binder是一个很深入的话题——任玉刚老师如是说。就笔者的水平而言,实际上从任玉刚老师的《艺术探索》中读完从AIDL代码中去解析其工作机制,确实可以理解。但是笔者在这不会老套照搬代码,介绍其工作机制时只是必要的些许代码,不会整个代码文件上,有兴趣的读者可以阅读该书,按照书的步骤走即可。
在这里插入图片描述

一、Binder

  什么是Binder?
在这里插入图片描述
  从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以理解为一种虚拟的物理设备,其设备驱动是/dev/binder,值得一提的是该通信方式在Linux中是没有的。
  从Android Framework角度来讲,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等等)和相应ManagerService的桥梁
  从Android应用层角度来说,Binder是客户端和服务端进行通信的媒介,当bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包括普通的服务以及基于AIDL的服务。
在这里插入图片描述
  值得一提的是,Binder在Android开发中主要用在了Service中,包括AIDL和Messenger,而Messenger的底层其实还是AIDL。

二、Binder工作机制

  上面提到了Binder的实现方式之一AIDL,这里我们以AIDL来分析一下Binder的工作机制,当然只是涉及部分代码以理解,关于AIDL的使用读者可令行学习。在AS中,创建一个IBookManager.aidl的文件(右键即可),该aidl中书写如下代码(其中需要一个Book.java的bean类以及对应的Book.aidl)。

// Declare any non-default types here with import statements
import com.fatdoge.myapplication.Book;

interface IBookManager {
    List<Book> getBookList();
    void addBook(in Book book);
}

  AS关于AIDL实现的一个好处是能够自动的为用户实现对应的IBookManager.java以实现跨进程通信。如下为该类的核心代码。

public interface IBookManager extends android.os.IInterface {
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.fatdoge.myapplication.IBookManager {
    public static com.fatdoge.myapplication.IBookManager asInterface(android.os.IBinder obj) {
        // 将服务端Binder对象转为客户端所需AIDL接口类型对象
        // 客户端服务端同一进程,返回Stub本身;否则封装系统包装后的Stub.proxy对象
    }
    @Override public android.os.IBinder asBinder() {
        // 返回当前Binder对象
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
        // 运行在Binder线程池中,服务端根据code确定客户端请求的目标方法
        // data中包含目标方法所需的参数
        // reply中写入目标方法的返回值
        // 该方法返回值为false,则客户端请求会失败
    }
    
    private static class Proxy implements com.fatdoge.myapplication.IBookManager {
      @Override public java.util.List<com.fatwood.myapplication.Book> getBookList() throws android.os.RemoteException {
          // 运行在客户端,参数信息写入_data,
          // 调用transact方法发起RPC(远程过程调用),当前线程挂起
          // 服务端onTransact方法被调用,直到RPC返回当前线程执行
          // 并从_reply中取出RPC过程的返回结果,最后返回其中数据
      }
      @Override public void addBook(com.fatwood.myapplication.Book book) throws android.os.RemoteException {
      }
    }
  }
}

  可以看到其内部类Stub是一个Binder类,当客户端和服务端都位于同一个进程时,方法调用不会走跨进程的transact进程,相反则会,而这个逻辑将由Stub的内部代理类来实现。
  以此可以了解到,Binder的工作机制大致过程为:客户端发起请求调用目标方法,该请求会由Proxy中的对应的方法先将参数信息写入_data,调用transact方法发起RPC,同时当前线程挂起;服务端onTransact方法被调用,直到RPC返回当前线程才会继续执行,并从_reply中取出RPC过程的返回结果,最后返回其中数据
在这里插入图片描述
  对于Binder的工作机制,需要注意两点:首先,当客户端发起请求时,由于当前线程会被挂起直至服务端进程返回数据,所以对于一个耗时的远程方法,不能在UI线程中发起该远程请求;其次,由于服务端的Binder方法运行在Binder的线程池中,所以Binder方法不管是否耗时都应该采用同步的方式去实现。其工作机制可以用如下图所示。
在这里插入图片描述
  这里需要提一句,AIDL文件的本质是系统为开发者提供的一种快速实现Binder的工具,因此开发者也完全可以自己实现。
  另外,Binder中还有两个重要的方法——linkToDeath以及unlinkToDeath。通过这两个方法可以设置Binder死亡代理,当Binder死亡时可以收到通知,此外通过Binder的方法isBinderAlive也可以判断Binder是否死亡。

三、Binder原理

  那么Binder的工作机制了解了,好奇的笔者又在想,其作为媒介到底是如何使得服务端和客户端通信的呢?也就是其原理是如何的呢?
在这里插入图片描述
  Binder通信采用C/S架构,从组件视角来讲,包含Client、Server、ServiceManager以及Binder驱动,其中ServiceManager用于管理系统中的各种服务。Client和Server以及ServiceManager三者之间的交互并不是直接的,而是通过与Binder驱动进行交互的,从而实现IPC通信方式。架构图如下。
在这里插入图片描述
  Binder通信中ServiceManager进程的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使用Client能够通过Binder名字获取对Server中Binder实体的引用。
  Binder驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
  为了更为具体的了解Binder原理的工作过程,以下为使用服务的具体执行过程。
在这里插入图片描述

参考资料:《Android开发艺术探索》
     简单理解Binder机制的原理

原创文章 78 获赞 25 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_38196407/article/details/105413750