Android Binder机制

打印 上一主题 下一主题

主题 2403|帖子 2403|积分 7209

Binder是IPC(进程间通信)的一种机制,它答应不同的应用或体系服务在不同的进程中安全地互换数据。Binder的焦点原理是基于客户端-服务器模型(C/S架构)。

一、Binder的定义

1. Binder是Android中的一个类,它继承了IBinder接口。
2. 从IPC角度来说,Binder是Android中的一种跨进程通信方式,Binder还可以明白为一种虚拟的物理设备,它的设备驱动是/dev/binder,该通信方式在linux中没有
3. 从Android Framework角度来说,Binder是ServiceManager毗连各种Manager(ActivityManager、WindowManager,etc)和相应ManagerService的桥梁
4. 从Android应用层来说,Binder是客户端和服务端进行通信的媒介,当你bindService的时间,服务端会返回一个包含了服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据,这里的服务包罗普通服务和基于AIDL的服务。
一、Binder架构

在Android体系中,Binder架构主要由以下几个部分组成:
1.Binder驱动程序:这是Linux内核的一部分,负责处置惩罚跨进程通信的所有底层细节。
2.ServiceManager:这是一个特别的体系服务,负责管理所有通过Binder进行通信的服务。它维护一个服务列表,答应其他服务注册和查询服务。
3.Server端:这是提供某种服务的组件,比如体系服务或应用服务。
4.Client端:需要使用Server端提供服务的组件。

二、Binder的工作流程

1、Client和Server都使用同一个AIDL文件,包名相同,编译后,两边都会生成IMyService.java,其中有Stub实体和Proxy代理两个对象
2、Server端通过AndroidManifest.xml 注册Service
3、Client通过bindService()获得服务的代理Stub.Proxy()
4、Client 调用AIDL的方法add(),其实调用的是IMyService.java中的Stub.Proxy.add(),终极通过BinderProxy.java的transact()向服务端发送
5、过Binder驱动的流程,进入到服务端的onTransact(),根据Client发送的TRANSACTION code,解析进入相应的流程处置惩罚,进入add()
6、MyService在被绑定时,有了实体IMyService.Stub,终极进入MyService.java的add()处置惩罚,完成接口调用,调用完成后把数据写入Parcel,通过reply发送给Client


四、Binder通信原理

1. Binder是基于内存映射mmap计划实现的,通过这种方式,直接操作映射的这一部分内存,通过mmap,Binder通信时,只需要履历一次数据复制,从而获得更好的性能。
2. Binder通信过程
. 首先,Binder驱动在内核空间中开辟出一个数据接收缓冲区。
. 接着,在内核空间中开辟出一个内核缓冲区。
. 将内核缓冲区与数据接收缓冲区创建映射关系。
. 将数据接收缓冲区与接收进程的用户空间地点创建映射关系。
. 发送方进程通过copy_from_user将数据从用户空间复制到内核缓冲区。
. 由于内核缓冲区与数据接收缓冲区有映射关系,同时数据接收缓冲区与接收进程的用户空间地点有映射关系,所以在接收进程中可以直接获取到这段数据。

五、参数定义

Stub类:Binder的实现类,服务端通过这个类来提供服务。
Proxy类:服务器的本地代理(Binder),客户端通过这个类调用服务器的方法。
asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。返回对象:
​ 1.若客户端和服务端位于同一进程,则直接返回Stub对象本身;
​ 2.否则,返回的是体系封装后的Stub.proxy对象。
asBinder():根据当前调用情况返回代理Proxy的Binder对象。
onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,长途请求会通过体系底层封装后交由此方法来处置惩罚。
transact():运行在客户端,当客户端发起长途请求的同时将当前线程挂起。之后调用服务端的onTransact()直到长途请求返回,当前线程才继续实行。
Parcel:这是一种用于封装数据的数据结构,可以在进程间传输。它类似于Java中的序列化对象,但更轻量级且效率更高。
isBinderAlive():用于查抄一个Binder对象是否仍旧存活
linkToDeath:注册对Binder殒命通知的观察者,在其殒命后,会收到相应的通知 

六、进程通信对比

1. 共享内存

定义:共享内存是进程间通信中最简单的方式之一,共享内存答应两个或更多进程访问同一块内存,当一个进程改变了这块地点中的内容的时间,其它进程都会察觉到这个更改。
性能和安全分析:由于共享内存是访问同一块内存,所以数据不需要进行任何复制,是IPC几种方式中最快,性能最好的方式。由于能任意的访问和修改内存中的数据,如果有恶意程序去针对某个程序计划代码,很可能导致隐私泄漏或者程序崩溃,所以安全性较差。
2. 管道

定义:它具有固定的读端和写端,写进程通过写段向管道文件里写入数据,读进程通过读段从读进程中读出数据,构成一条数据通报的流水线。
性能和安全分析
管道一次通信需要履历2次数据复制(进程A -> 管道文件,管道文件 -> 进程B)。管道的读写分壅闭和非壅闭,管道创建会分配一个缓冲区,而这个缓冲区是有限的,如果传输的数据大小超过缓冲区上限,或者在壅闭模式下没有安排好数据的读写,会出现壅闭的情况。
3. 消息队列

定义:消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表示。消息队列允许多个进程同时读写消息,发送方与接收方要约定好,消息体的数据类型与大小。
性能和安全分析:消息队列克服了信号承载信息量少、管道只能承载无格式字节省等缺点,消息队列一次通信同样需要履历2次数据复制(进程A -> 消息队列,消息队列 -> 进程B)。
4. Socket

定义:Socket本来是为了网络计划的,但也可以通过本地回环地点 (127.0.0.1) 进行进程间通信。Socket是一种通信机制,位于应用层和传输层之间,提供了一组接口用于应用程序之间的通信。
性能和安全分析:一个Socket会拥有两个缓冲区,一读一写,由于发送/接收消息需要将一个Socket缓冲区中的内容拷贝至另一个Socket缓冲区,所以Socket一次通信也是需要履历2次数据复制。
5.Binder优势
1. 性能优势
. 在移动设备上(性能受限制的设备,比如要省电),广泛地使用跨进程通信对通信机制的性能有严酷的要求,Binder相对出传统的Socket方式,更加高效。
. Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,共享内存方式一次内存拷贝都不需要,但实现方式又比力复杂。
2. 安全优势
. 传统的进程通信方式对于通信两边的身份并没有做出严酷的验证,比如Socket通信ip地点是客户端手动填入,很容易进行伪造。
. 而Binder机制从协议本身就支持对通信两边做身份校检,因而大大提拔了安全性。
. 还有一些好处,如实现面象对象的调用方式,在使用Binder时就和调用一个本地实例一样。

Binder
共享内存
Socket
性能
数据拷贝一次
无需拷贝
数据拷贝两次
稳定
C/S架构,清晰明朗。Client与Server相对独立,稳定性好
实现与控制复杂,需要自行处置惩罚并同步等问题。
基于C/S架构
安全性
内核添加身份标识(可靠)
依靠上层协议,访问接入点开放不安全
依靠上层协议,访问接入点开放不安全
七、代码分析

  1. /*
  2. * This file is auto-generated.  DO NOT MODIFY.
  3. */
  4. package com.flyme.auto.account.manager;
  5. public interface IAccountManagerInterface extends android.os.IInterface
  6. {
  7.     /** Default implementation for IAccountManagerInterface. */
  8.     public static class Default implements com.flyme.auto.account.manager.IAccountManagerInterface
  9.     {
  10.         /**
  11.          * 获取当前登录的账号数据
  12.          */
  13.         @Override public java.lang.String getAccountInfo() throws android.os.RemoteException
  14.         {
  15.             return null;
  16.         }
  17.         /**
  18.          * 判断当前是否已登录
  19.          */
  20.         @Override public boolean isLoggedIn() throws android.os.RemoteException
  21.         {
  22.             return false;
  23.         }
  24.         @Override
  25.         public android.os.IBinder asBinder() {
  26.             return null;
  27.         }
  28.     }
  29.     /** Local-side IPC implementation stub class. */
  30.     public static abstract class Stub extends android.os.Binder implements com.flyme.auto.account.manager.IAccountManagerInterface
  31.     {
  32.         private static final java.lang.String DESCRIPTOR = "com.flyme.auto.account.manager.IAccountManagerInterface";
  33.         /** Construct the stub at attach it to the interface. */
  34.         public Stub()
  35.         {
  36.             this.attachInterface(this, DESCRIPTOR);
  37.         }
  38.         /**
  39.          * Cast an IBinder object into an com.flyme.auto.account.manager.IAccountManagerInterface interface,
  40.          * generating a proxy if needed.
  41.          */
  42.         //asInterface是Android Binder IPC机制中用于将Binder对象转换为特定接口的关键方法,
  43.         // 它使得客户端能够调用服务端提供的方法和服务,实现进程间的通信和数据交换
  44.         public static com.flyme.auto.account.manager.IAccountManagerInterface asInterface(android.os.IBinder obj)
  45.         {
  46.             if ((obj==null)) {
  47.                 return null;
  48.             }
  49.             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  50.             if (((iin!=null)&&(iin instanceof com.flyme.auto.account.manager.IAccountManagerInterface))) {
  51.                 return ((com.flyme.auto.account.manager.IAccountManagerInterface)iin);
  52.             }
  53.             return new com.flyme.auto.account.manager.IAccountManagerInterface.Stub.Proxy(obj);
  54.         }
  55.         //Android Binder IPC机制中用于获取接口对象所关联的IBinder实例的方法,它提供了直接操作IBinder对象的能力,但需要谨慎使用
  56.         @Override public android.os.IBinder asBinder()
  57.         {
  58.             return this;
  59.         }
  60.         //Android Binder IPC机制中服务端用于处理客户端请求的关键方法
  61.         @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
  62.         {
  63.             java.lang.String descriptor = DESCRIPTOR;
  64.             switch (code)
  65.             {
  66.                 case INTERFACE_TRANSACTION:
  67.                 {
  68.                     reply.writeString(descriptor);
  69.                     return true;
  70.                 }
  71.                 case TRANSACTION_getAccountInfo:
  72.                 {
  73.                     data.enforceInterface(descriptor);
  74.                     java.lang.String _result = this.getAccountInfo();
  75.                     reply.writeNoException();
  76.                     reply.writeString(_result);
  77.                     return true;
  78.                 }
  79.                 case TRANSACTION_isLoggedIn:
  80.                 {
  81.                     // Android Binder IPC 机制中用于确保接口一致性和安全性的一个方法
  82.                     data.enforceInterface(descriptor);
  83.                     boolean _result = this.isLoggedIn();
  84.                     reply.writeNoException();
  85.                     reply.writeInt(((_result)?(1):(0)));
  86.                     return true;
  87.                 }
  88.                 default:
  89.                 {
  90.                     return super.onTransact(code, data, reply, flags);
  91.                 }
  92.             }
  93.         }
  94.         //Proxy的实现通常依赖于具体的接口定义和服务端实现。在Android中,可以使用AIDL来定义接口,并自动生成Proxy和Stub(存根)代码。
  95.         // Stub是服务端的一个组件,它与Proxy相对应,负责接收和处理来自客户端的请求
  96.         private static class Proxy implements com.flyme.auto.account.manager.IAccountManagerInterface
  97.         {
  98.             private android.os.IBinder mRemote;
  99.             Proxy(android.os.IBinder remote)
  100.             {
  101.                 mRemote = remote;
  102.             }
  103.             @Override public android.os.IBinder asBinder()
  104.             {
  105.                 return mRemote;
  106.             }
  107.             public java.lang.String getInterfaceDescriptor()
  108.             {
  109.                 return DESCRIPTOR;
  110.             }
  111.             /**
  112.              * 获取当前登录的账号数据
  113.              */
  114.             @Override public java.lang.String getAccountInfo() throws android.os.RemoteException
  115.             {
  116.                 android.os.Parcel _data = android.os.Parcel.obtain();
  117.                 android.os.Parcel _reply = android.os.Parcel.obtain();
  118.                 java.lang.String _result;
  119.                 try {
  120.                     _data.writeInterfaceToken(DESCRIPTOR);
  121.                     boolean _status = mRemote.transact(Stub.TRANSACTION_getAccountInfo, _data, _reply, 0);
  122.                     if (!_status && getDefaultImpl() != null) {
  123.                         return getDefaultImpl().getAccountInfo();
  124.                     }
  125.                     _reply.readException();
  126.                     _result = _reply.readString();
  127.                 }
  128.                 finally {
  129.                     _reply.recycle();
  130.                     _data.recycle();
  131.                 }
  132.                 return _result;
  133.             }
  134.             /**
  135.              * 判断当前是否已登录
  136.              */
  137.             @Override public boolean isLoggedIn() throws android.os.RemoteException
  138.             {
  139.                 android.os.Parcel _data = android.os.Parcel.obtain();
  140.                 android.os.Parcel _reply = android.os.Parcel.obtain();
  141.                 boolean _result;
  142.                 try {
  143.                     //writeInterfaceToken方法的使用有助于确保客户端和服务端之间的接口一致性,
  144.                     // 并减少因接口不匹配而导致的通信错误或安全问题。它是Android Binder IPC机制中保证通信正确性和安全性的一个重要环节
  145.                     _data.writeInterfaceToken(DESCRIPTOR);
  146.                     boolean _status = mRemote.transact(Stub.TRANSACTION_isLoggedIn, _data, _reply, 0);
  147.                     if (!_status && getDefaultImpl() != null) {
  148.                         return getDefaultImpl().isLoggedIn();
  149.                     }
  150.                     _reply.readException();
  151.                     _result = (0!=_reply.readInt());
  152.                 }
  153.                 finally {
  154.                     _reply.recycle();
  155.                     _data.recycle();
  156.                 }
  157.                 return _result;
  158.             }
  159.             public static com.flyme.auto.account.manager.IAccountManagerInterface sDefaultImpl;
  160.         }
  161.         static final int TRANSACTION_getAccountInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
  162.         static final int TRANSACTION_isLoggedIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  163.         public static boolean setDefaultImpl(com.flyme.auto.account.manager.IAccountManagerInterface impl) {
  164.             // Only one user of this interface can use this function
  165.             // at a time. This is a heuristic to detect if two different
  166.             // users in the same process use this function.
  167.             if (Stub.Proxy.sDefaultImpl != null) {
  168.                 throw new IllegalStateException("setDefaultImpl() called twice");
  169.             }
  170.             if (impl != null) {
  171.                 Stub.Proxy.sDefaultImpl = impl;
  172.                 return true;
  173.             }
  174.             return false;
  175.         }
  176.         public static com.flyme.auto.account.manager.IAccountManagerInterface getDefaultImpl() {
  177.             return Stub.Proxy.sDefaultImpl;
  178.         }
  179.     }
  180.    
  181.     public java.lang.String getAccountInfo() throws android.os.RemoteException;
  182.     public boolean isLoggedIn() throws android.os.RemoteException;
  183. }
复制代码



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表