Android 之 Binder与进程间通信

news/2024/7/7 7:55:51
  1. Binder机制是android中实现的进程间通信的架构,它采用的是c/s架构,client通过代理完成对server的调用。

    ServiceManager

    既然这里提到了server,那么我们有必要先了解下在android中是怎么来管理server的。先来看一个重要的Native进程:ServiceManager,从名字可以看出来,这个是用来管理所有server的。在init进程启动之后,会启动另外两个重要的进程,一个是我们上一篇讲的Zygote进程,另外一个就是这个ServiceManager进程了,这两个进程启动之后就建立了android的运行环境和server的管理环境。ServiceManager进程启动之后其他server就可以通过ServiceManager的add_service和check_service来添加和获取特定的server了。关于ServiceManager在接下来会详细介绍,因为Binder会涉及到ServiceManager,所以先简单介绍下,有个大概印象,知道他是干什么的就行了。

    Binder与进程间通信

    在本篇介绍中,我们所指的客户端没有特别说明的话就指应用程序。应为service和serviceManager通信也会涉及到IPC。

    我们还是从activity的启动开始来研究Binder的机制。来看下startActivity涉及通信的类图:

     

    在ActivityManagerProxy中,有这句代码          

    [java]  view plain copy
    1. IBinder b = ServiceManager.getService("activity");  
    2. 继续看下getService方法,在getService中对数据进行了序列化封装,并通过BinderProxy的native方法向ServiceManager发送请求,获取Binder的代理对象。看下getService代码:  

    [java]  view plain copy
    1. /* 
    2.    * 从ServiceManager中获取service对应的代理Binder 
    3.    * @param na 
    4.    * @return 
    5.    * @throws RemoteException 
    6.    */  
    7.   public IBinder getService(String name) throws RemoteException {  
    8.       Parcel data = Parcel.obtain();  
    9.       Parcel reply = Parcel.obtain();  
    10.       data.writeInterfaceToken(IServiceManager.descriptor);  
    11.       data.writeString(name);  
    12.       mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);  
    13.       IBinder binder = reply.readStrongBinder();  
    14.       reply.recycle();  
    15.       data.recycle();  
    16.       return binder;  
    17.   }  

    也就是说,在android中进行IPC的话,需要先通过ServiceManager获得客户端的代理,然后再通过该代理与对应的service进行通信。

    1. 建立和ServiceManager的连接,获取客户端对象的代理Binder。
    2. 客户端再通过该代理binder和服务器端进行通信。
  1. 真正的Binder

    我们在上面所提到的这些Binder实际上只是JVM中的Binder,主要作用是提供了访问C++中的代理Binder,叫做BpBinder(BproxyBinder)。真正的Binder是Linux上的一个驱动设备,专门用来做android的数据交换。

     

    从上面分析可以看出,一次IPC通信大概有以下三个步骤:

  1. 在JVM中对数据进行序列化,并通过BinderProxy传递到C++中。
  2. C++中的BpBinder对数据进行处理,并传入到Binder设备中(这里是在ProcessState类中处理并调用BpBinder).
  3. Service从内核设备中读取数据。

   既然在C++中,处理数据主要是在ProcessState中,那么我们就来看看ProcessState的代码,在getContextObject中调用了getStrongProxyForHandle方法,从而获取了代理对象BpBinder:

  1. [java]  view plain copy
    1. sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)  
    2. {  
    3.     sp<IBinder> result;  
    4.     AutoMutex _l(mLock);  
    5.     handle_entry* e = lookupHandleLocked(handle);  
    6.     if (e != NULL) {  
    7.         // We need to create a new BpBinder if there isn't currently one, OR we  
    8.         // are unable to acquire a weak reference on this current one.  See comment  
    9.         // in getWeakProxyForHandle() for more info about this.  
    10.         IBinder* b = e->binder;  
    11.         if (b == NULL || !e->refs->attemptIncWeak(this)) {  
    12.             b = new BpBinder(handle);  
    13.             e->binder = b;  
    14.             if (b) e->refs = b->getWeakRefs();  
    15.             result = b;  
    16.         } else {  
    17.             // This little bit of nastyness is to allow us to add a primary  
    18.             // reference to the remote proxy when this team doesn't have one  
    19.             // but another team is sending the handle to us.  
    20.             result.force_set(b);  
    21.             e->refs->decWeak(this);  
    22.         }  
    23.     }  
    24.     return result;  
    25. }  

    再来看看BpBinder中的transact方法代码:

    [java]  view plain copy
    1. status_t BpBinder::transact(  
    2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
    3. {  
    4.     // Once a binder has died, it will never come back to life.  
    5.     if (mAlive) {  
    6.         status_t status = IPCThreadState::self()->transact(  
    7.             mHandle, code, data, reply, flags);  
    8.         if (status == DEAD_OBJECT) mAlive = 0;  
    9.         return status;  
    10.     }  
    11.     return DEAD_OBJECT;  
    12. }  
    在BpBinder中的transact函数中,只是调用了IPCThreadState::self()->transact方法,也就是说,数据处理是在IPCThreadState类中的transact。在transact中,它把请求的数据经过Binder设备发送给了Service。Service处理完请求后,又将结果原路返回给客户端。

     

    总结:

  2. 在android中,使用Binder进行进程间的通信,并采用C/S架构
  3. Android中的Binder分为JVM中的、C++中的、和真正的linux中的Binder块设备
  4. 进程间通信首先是从JVM中对数据进行转化并传递到C++中,C++中的BpBinder对数据进行处理写入到linux中的Binder设备,并接受Service端得请求,请求完毕后按照原路返回给调用端。

http://www.niftyadmin.cn/n/3649481.html

相关文章

如何在Ubuntu 18.04上使用Ansible安装和设置Apache

介绍 (Introduction) Server automation now plays an essential role in systems administration, due to the disposable nature of modern application environments. Configuration management tools such as Ansible are typically used to streamline the process of aut…

最新版Microsoft Edge——Chromium内核

2015年4月30日&#xff0c;微软在旧金山举行的Build 2015开发者大会上宣布&#xff0c;其最新操作系统——Windows 10内置代号为“Project Spartan”的新浏览器被正式命名为“Microsoft Edge”&#xff0c;其内置于Windows 10版本中。 2018年3月&#xff0c;微软宣布登陆iPad和…

优秀的前端JS框架——AngularJS的安装

AngularJS 诞生于2009年&#xff0c;由Misko Hevery 等人创建&#xff0c;后为Google所收购。是一款优秀的前端JS框架&#xff0c;已经被用于Google的多款产品当中。AngularJS有着诸多特性&#xff0c;最为核心的是&#xff1a;MVC(Model–view–controller)、模块化、自动化双…

Android中的Parcel机制 实现Bundle传递对象

Android中的Parcel机制 实现了Bundle传递对象 使用Bundle传递对象&#xff0c;首先要将其序列化&#xff0c;但是&#xff0c;在Android中要使用这种传递对象的方式需要用到Android Parcel机制&#xff0c;即&#xff0c;Android实现的轻量级的高效的对象序列化和反序列…

Picasso的封装(一)

public class PicassoUtils {//加载本地图片public static void setImg(Context context, int resId, ImageView imgView){Picasso.with(context).load(resId).config(Bitmap.Config.RGB_565)//8位RGB位图.fit().into(imgView);}//按照一定的宽高加载本地图片&#xff0c;带有加…

如何在Ubuntu 18.04上使用Ansible安装和设置Docker

介绍 (Introduction) Server automation now plays an essential role in systems administration, due to the disposable nature of modern application environments. Configuration management tools such as Ansible are typically used to streamline the process of aut…

JavaScript 运行环境——Node.js的安装

Node.js 是一个基于Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。Node 是一个让JavaScript运行在服务端的开发平台&#xff0c;它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。发布于2009年5月…

System.loadLibrary()的使用方法汇总

当使用System.loadLibrary()调用 Dll&#xff0c;两种方法: 1.设定环境变量。 比如&#xff1a;所编辑的Dll在目录“D:/cppProjects/nativecode/release”内&#xff0c;将这个路径复制添加到电脑的环境变量中的path变量内即可。 2.设定项目属性。(开发推荐) 右击项目名|选择属…