美文网首页Java&Android日更补完计划
当问你binder怎么实现时别那么无助

当问你binder怎么实现时别那么无助

作者: 埃赛尔 | 来源:发表于2020-02-22 18:11 被阅读0次

开篇故事

面试的时候很多面试官都喜欢问IPC,然而我比较菜,只能说ipc的几种方式,然后说四大组件实现的跨进程通信就是对Binder的封装,然后面试官就会祭出自己的多命大杀器:
面试官:”你知道binder的实现机制么?“
我:”...共享内存...“
面试官:”你这了解的不够深入啊,再见”

为了不再这样被面试官装一脸,还是决定深入分析一下binder机制

从java层看Binder

由于intent mesager 这些底层都是binder不方便观察 我们就从一个自己写的AIDL中由表及里的观察了:

// Book.aidl 声明自定义对象
package com.example.aidl;

// Declare any non-default types here with import statements

parcelable Book;

// IBookManager.aidl 声明BookManager接口
package com.example.aidl;

import com.example.aidl.Book;
// Declare any non-default types here with import statements
interface IBookManager {

    List<Book> getBookList();

    void addBook(in Book book);

}

在这里找到AIDL生成的文件
../build/generated/aidl_source_output_dir/debug/compileDebugAidl/out/com/example/aidl/IBookManager.java
首先这个类很长一大串,如果直接很容易懵逼,比如之前的我看到这里直接放弃了,所以我在这里做了一些处理,等下还要把图附上去:

根据AIDL生成的接口类:IBookManager
    public interface IBookManager extends android.os.IInterface
{
  public java.util.List<com.example.aidl.Book> getBookList() throws android.os.RemoteException;
  public void addBook(com.example.aidl.Book book) throws android.os.RemoteException;
}

本地侧的跨进程实现类:
  public static abstract class Stub extends android.os.Binder implements com.example.aidl.IBookManager
  {
   /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
/**
     * Cast an IBinder object into an com.example.aidl.IBookManager interface,
     * generating a proxy if needed.
     */
    public static com.example.aidl.IBookManager asInterface(android.os.IBinder obj)
    {
     ...
    }
    @Override public android.os.IBinder asBinder()
    {
     ...
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
    ...
      }
    }

这里着重讲解一下 asInterface() 方法:

用于将服务端的BInder对象转换成客户端所需的AIDL接口类型对象,如果客户端和服务端位于同一进程那么此方法返回的就是服务端的stub对象本身,否则返回的是系统封装后的Stub.proxy,具体实现如下:

 if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.aidl.IBookManager))) {
        return ((com.example.aidl.IBookManager)iin);
      }
      return new com.example.aidl.IBookManager.Stub.Proxy(obj);
本地侧的跨进程实现类的代理类:
    private static class Proxy implements com.example.aidl.IBookManager
    {
 
      @Override public android.os.IBinder asBinder()
      {
        ...
      }
      ...
    
      @Override public java.util.List<com.example.aidl.Book> getBookList() throws android.os.RemoteException
      {
       ...
      }
      @Override public void addBook(com.example.aidl.Book book) throws android.os.RemoteException
      {
       ...
      }
    }

这个类就没啥特别要说的就是拿着stub类一顿操作,由于我们讲的是IPC所以这里忽略.

                    Binder  IBookManager
                       \   /     \
                       Stub   Proxy

那么如何通信需要看Stub类的 onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) :
这个方法在服务端中的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理:code可以确定要操作的目标方法,data从获取目标方法所需的参数--> 执行目标方法 --> 向reply中写返回值完成通信

能不能更深入一点看Binder?

binder解决了哪些问题:
1.跨进程管理对象的生命周期问题:Binder在驱动中建立了一张所有进程的引用对象和实体对象关联表,同时Binder又必须保证用户进程的实体对象或者引用对象和驱动中的一致,为了达到这个目标,BInder定义了自己的跨进程引用计数机制
2.普通的IPC传递参数时要经历两次数据复制的过程:一次时从调用这的数据缓存区复制到内核的缓冲区,第二次时从内核的缓冲区复制到接收进程的缓冲区,binder是如何减少一次复制的呢?
这就需要了解下什么是mmap,当用户创建打开Binder设备后会调用mmap()在驱动中创建一块内存空间用于接收传递给本进程的Binder数据

static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
    ...
//为用户进程分配一块内存空间作为缓冲区
  area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
···
//在内核中分配了同样页数大小的空间,并把他们的物理内存地址绑定在一起
if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) {
        ret = -ENOMEM;
        failure_string = "alloc small buf";
        goto err_alloc_small_buf_failed;
    }
...
    return ret;
}

从而实现了应用和内核共享同一块内存空间:
数据会从发送金层复制到内核空间,驱动会在接收进程的缓冲区中寻找一块合适的空间来存放数据,因为接收进程的用户空间缓冲区和内核空间的缓冲区是共享的所以接收进程不需要将数据再从内核空间复制到用户空间.

          用户空间缓冲区           内核空间缓冲区
                      \                                   /
                        \                               /
                          \                           /
                                物理内存

相关文章

  • 当问你binder怎么实现时别那么无助

    开篇故事 面试的时候很多面试官都喜欢问IPC,然而我比较菜,只能说ipc的几种方式,然后说四大组件实现的跨进程通信...

  • 安卓进程通信之Binder学习指南(二)

    Binder到底是什么? 我们经常提到Binder,那么Binder到底是什么呢? Binder的设计采用了面向对...

  • 深入Android系统 Binder-2-使用

    作者:apigfly 如何使用 Binder 就开发语言而言,Binder服务可以用Java实现,也可以用C++实...

  • Acitivity与Service的交互方式

    (一) Extending the Binder class 通过 Binder 接口的形式实现,当 Activi...

  • 被误解的女儿

    人生总会有那么些时候,我们会不被理解,被他人冤枉,那么当这种情形出现时,我们该怎么办?今天,女儿在认真上网课,老师...

  • 2017-09-26

    我就想问问你,哪来的那么多好看的图。 我就想问问你,你怎么那么有意思? 我就想问问你,你怎么都把我给逗坏了。 哎呀...

  • Binder机制

    Binder 在理解Binder机制之前,需要知道Binder是做什么的,在进程之间通信称作IPC,那么Binde...

  • 随便其实最难

    我问你怎么办你总说随便 我问你怎么看你总说都行 你可知道简单不简单随便不随便 做决定很难 心思很难猜请你说出来 别...

  • Android 重学系列 Binder 死亡代理

    背景 这是Binder系列的最后一篇了。让我们来聊聊Binder的死亡代理是怎么处理。我们之前只是聊了Binder...

  • FW-Binder机制

    问题1 应用是怎么启用Binder机制 1 什么时候支持Binder机制 Activity.oncreate()应...

网友评论

    本文标题:当问你binder怎么实现时别那么无助

    本文链接:https://www.haomeiwen.com/subject/ulqyactx.html