Binder机制原理

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 用户空间 | 内核空间 共享同一块物理内存A【Binder驱动提供】

内存映射 >>> 虚拟内存 ,物理内存 指针就是表示虚拟内存

地球仪 && 地球 关系

进程2 用户空间 | 内核空间 共享同一块物理内存B 【Binder驱动提供】

image.png
Binder驱动是一个Linux内核模块,通常位于内核源码的drivers/android/binder.c文件中。它通过以下方式与用户空间交互:
  • 设备文件:Binder驱动在/dev目录下创建一个设备文件(通常是/dev/binder),用户空间进程通过打开这个设备文件来与Binder驱动交互。
  • IOCTL命令:用户空间进程通过ioctl()系统调用向Binder驱动发送命令,例如注册服务、获取服务引用等。
  • 内存映射:用户空间进程通过mmap()系统调用将Binder驱动的内存映射到自己的地址空间,从而实现高效的数据传输。
注意1:每一个使用Binder通信的进程都会有一个Binder线程池,Binder驱动【drivers/android/binder.c】是所有进程共有的,而操作Binder驱动的设备文件,每个进程都会有,因为当父进程通过fork()创建子进程时,子进程会继承父进程的binder驱动相关的设备文件(通常是/dev/binder)【前台】,通过mmap内存映射函数或者open函数来操作binder 驱动【后厨】,Binder驱动管理Binder线程池,处理来自客户端的请求,当客户端发起请求时,Binder驱动会将请求分发给服务端的线程池中的空闲线程。
注意2:binder驱动其实就是用户空间和内核空间共享的一块内存区域。
image.png

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

虚拟内存划分
1732617169964.png
内存映射原理?

内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间,映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间,避免了数据拷贝和用户态与内核态的转换,提高了通信速度。

binder驱动是什么?

binder驱动其实就是用户空间和内核空间共享的一块内存区域。

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

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

interface BookManager{
     List<Book> getBookList();
}

5.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;
                         }
                     }
            }
      }
}

5.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();
           }
    }
}

5.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;
      }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容