关键词:
本篇开始去了解Binder的调用过程和运行机制,本文不会深入探讨Binder驱动以及底层的实现,而是以AIDL的使用理清Java层面的Binder的实现和通信过程。
本文依然按照惯例,先总结下AIDL的使用步骤,然后根据日志、调试等信息整理其调用逻辑。如果还不知道AIDL的使用方法的请参考http://blog.csdn.net/u012481172/article/details/50925381。
AIDL的使用步骤
AIDL通常用于Service和其它组件(如Activity)的通信。为什么要用AIDL呢,因为AIDL可以帮我们快速实现跨进程通信,如果项目中的Service和Activity分别位于不同的两个进程,而他们又需要互相通信,这时就涉及到跨进程通信了,此时就是AIDL的使用场景了。
(1)编写AIDL文件
这一步请注意,AIDL文件只支持基本类型数据的远程传输,而对于我们自定义的实体对象,需要实现Parcelable接口才行,具体不再赘述,看之前的文章。
(2)在Service中继承Stub类,并重写aidl文件中接口定义的方法实现自己的业务。编译器会自动提示你去继实现哪些方法的,因为Stub是一个抽象类,并且在aidl中的方法在Stub中仍然是待实现的空方法。以下是根据AIDL生成的类:
package com.example.appa;
import android.os.IInterface;
import android.util.Log;
public interface CustomBinder extends android.os.IInterface
final String TAG = "Binder";
public static abstract class Stub extends android.os.Binder implements
com.example.appa.CustomBinder
private static final java.lang.String DESCRIPTOR = "com.example.appa.Test";
public Stub()
this.attachInterface((IInterface) this, DESCRIPTOR);
Log.e(TAG, "CustomBinder.Stub-->" + "Stub()构造器执行");
/**
* 将IBinder对象转换成Test接口实例
*
* @param obj
* 这是一个Binder实例,如果Service另外开启了一个进程那么此obj就是一个Binder.
* BinderProxy实例,
* 如果Service没有另外开启一个进程,那么此obj就是一个Binder实例。总之,obj的类型取决于Binder是本地的还是服务端的
* 通常我们把Service另外开启一个进程当做服务端
* @return
*/
public static com.example.appa.CustomBinder asInterface(
android.os.IBinder obj)
if ((obj == null))
return null;
// 这里就会查找本地Binder对象,如果找到即iin不为null就说明Server端和Client端在同一个进程,那么此时obj就是一个Binder实例
// 如果没有找到即iin为null就说明Server和Client不在同一个进程,此时iin就是null了。然后就要去创建Test.Stub.Proxy实例
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.appa.Test)))
return ((com.example.appa.CustomBinder) iin);
Log.e(TAG, "CustomBinder.Stub-->" + "asInterface()执行:" + iin);
return new com.example.appa.CustomBinder.Stub.Proxy(obj);
@Override
public android.os.IBinder asBinder()
Log.e(TAG, "CustomBinder.Stub-->" + "asBinder()");
return this;
/*
* Client调用hello方法的线程挂起等待返回;驱动完成一系列的操作之后唤醒Server进程,
* 调用了Server进程本地对象的onTransact函数(实际上由Server端线程池完成)。 (non-Javadoc)
*
* @see android.os.Binder#onTransact(int, android.os.Parcel,
* android.os.Parcel, int)
*/
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException
Log.e(TAG, "CustomBinder.Stub-->" + "onTransact()执行");
switch (code)
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_hello:
Log.e(TAG, "CustomBinder.Stub-->"
+ "TRANSACTION_hello执行:服务端执行本地hello方法");
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
// 这里调用了服务端本地的hello()方法,并且获得结果,将结果写回驱动,
// 然后驱动唤醒挂起的Client进程里面的线程并将结果返回。于是一次跨进程调用就完成了。
java.lang.String _result = this.hello(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
return super.onTransact(code, data, reply, flags);
/**
* Stub的代理类,也就是服务端的代理对象
*
* @author Administrator
*
*/
private static class Proxy implements com.example.appa.CustomBinder
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
mRemote = remote;
@Override
public android.os.IBinder asBinder()
Log.e(TAG, "CustomBinder.Stub.Proxy-->" + "asBinder()执行");
return mRemote;
public java.lang.String getInterfaceDescriptor()
Log.e(TAG, "CustomBinder.Stub.Proxy-->"
+ "getInterfaceDescriptor()执行");
return DESCRIPTOR;
@Override
public java.lang.String hello(java.lang.String content)
throws android.os.RemoteException
Log.e(TAG, "CustomBinder.Stub.Proxy-->" + "hello()执行");
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(content);
// 前面说过,只有当Server和Client不在同一个进程才会执行此代理的方法,而如果Server和Client不在同一个进程
// 那mRemote就是一个Binder.BinderProxy实例,那么此transact()方法就是Binder.BinderProxy的方法,他是一个本地方法
//
mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
finally
_reply.recycle();
_data.recycle();
return _result;
static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
/**
* 这个方法只是Stub的一个抽象方法,是在TestService中继承的时候重写了
* @param content
* @return
* @throws android.os.RemoteException
*/
public java.lang.String hello(java.lang.String content)
throws android.os.RemoteException;
在以上两不完成以后实际上就是创建了一个Server端,接下来就是Client的使用了。
(3)在Service(此处demo中是TestService)中继承Stub定义自己的Binder。
private class MyBinder extends CustomBinder.Stub
@Override
public String hello(String content) throws RemoteException
String con = "这是从Service发出来的内容..." + content;
Log.e(TAG, "TestService.MyBinder-->"+"hello()执行");
try
Thread.sleep(1000);
catch (InterruptedException e)
// TODO Auto-generated catch block
e.printStackTrace();
return con;
(4)在Activity中实现ServiceConnection接口,创建其实例。
private class MyServiceConnection implements ServiceConnection
@Override
public void onServiceConnected(ComponentName name, IBinder service)
showToast("服务已连接");
//mBinderConnection是CustomBinder类型的,这里就是将Binder驱动返回的IBinder对象转换成具体的我们定义的CustomBinder
mBinderConnection = CustomBinder.Stub.asInterface(service);
try
//这里就是客户端调用远程的hello()方法了。
String str = mBinderConnection.hello("来自Activity的问候");
Log.e(TAG,
"MainActivity.MyServiceConnection-->"
+ "onServiceConnected()执行,此时Service已经连接上,Server和Client可以通信了");
catch (RemoteException e)
e.printStackTrace();
@Override
public void onServiceDisconnected(ComponentName name)
mBinderConnection = null;
(5)调用bindService()即可。
AIDL跨进程的调用过程
当我们Server端(TestService)和Client端(MainActivity)都准备好了之后,客户端发起调用时,比如MainActivity中需要调用hello()方法,我们调用hello()之后这中间发生了什么呢?他的调用顺序是按照如下过程来的:
第一步:执行Stub的构造器,因为当我们调用bindService()的时候在Service中的onCreate中new了CustomBinder.Stub对象,从而调用了Stub的构造器。
第二步:执行了Stub的asInterface():这个是onServiceConnected()中获取Binder驱动发送过来的Stub实例。
第三步:就调用了Stub.Proxy的hello()方法了,因为TestService和当前Activity不是一个进程的,所以会使用Stub.Proxy实例的hello(),这个hello()会通过BinderProxy的transact()去调用Stub的onTransact()方法,然后就进入第四步。
第四步:调用了Stub的onTransact()方法,此方法就是用于调用服务端本地的hello()方法,在这里,这个“服务端本地”就是指Stub.hello()具体来说就是我们在TestService中继承Stub重写的那个hello()方法,也就是TestService.MyBinder.hello()。
AIDL源码分析
1、Client端获取远程Binder对象
就像上面我们的ServiceConnection中的onServiceConnected()方法中的那样,是客户端是通过Stub的asInterface()方法来获取远程具体对象的:
public void onServiceConnected(ComponentName name, IBinder service)
showToast("服务已连接");
//mBinderConnection是CustomBinder类型的,这里就是将Binder驱动返回的IBinder对象转换成具体的我们定义的CustomBinder
mBinderConnection = CustomBinder.Stub.asInterface(service);
这一步要注意,因为,如果服务端(TestService)和客户端(mainActivity)不在同一个进程,那么此处的onServiceConnectd()中的service参数就是一个TestService中我们定义的MyBinder实例,它对于程序员来说是一个本地的Binder;如果服务端和客户端不在一个进程中,此处的service参数就是一个android.os.Binder.BinderProxy实例,一定要记住这一点。好,接下来我们去看看CustomBinder.Stub的asInterface()方法如下:
public static com.example.appa.CustomBinder asInterface(
android.os.IBinder obj)
// 如果客户端和服务端还没建立连接就直接return null
if ((obj == null))
return null;
// 这里就会查找本地Binder对象,如果找到即iin不为null就说明Server端和Client端在同一个进程,
//那么此时obj就是一个Binder实例
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.appa.Test)))
return ((com.example.appa.CustomBinder) iin);
Log.e(TAG, "CustomBinder.Stub-->" + "asInterface()执行:" + iin);
// 如果没有找到即iin为null就说明Server和Client不在同一个进程,此时iin就是null了。
//然后就要去创建Test.Stub.Proxy实例,注意,这里创建Proxy的时候传递了一个obj,这个obj一定是Binder.BinderProxy的实例
return new com.example.appa.CustomBinder.Stub.Proxy(obj);
正如上面的注释那样,如果Server(此处的Server就是TestService)和Client(就是MainActivity)是同一个进程那么就会直接返回Binder实例,如果不在同一个进程就会返回一个Stub.Proxy实例。这是有很大区别的,如果在同一个进程那么方法调用就是直接本地调用了,如果不在同一个进程就需要代理Proxy去利用BinderProxy进行远程调用了。
2、客户端调用服务端方法
(1)服务端和客户端在同一个进
如果说服务端和客户端在同一个进程,即不指定TestService和Activity的process属性,那么当我们在客户端调用CustomBinder的hello()方法时就是直接调用了Stub的hello(实际上是TestService中的MyBinder重写的hello方法)方法,不需要走Stub.Proxy的流程。
(2)服务端和客户端不在同一个进程
这里我们将TestService的process属性取一个别名,就是让TestService运行在另一个进程,此时服务端和客户端就不在一个进程了,这时候我们在客户端调用服务端的hello()方法时,情况就不一样了,因为上面说了,当服务端和客户端不在一个进程时,实际上调用的就是Stub.Proxy的hello()方法,下面我们去看下Stub.Proxy的hello()方法:
@Override
public java.lang.String hello(java.lang.String content)
throws android.os.RemoteException
Log.e(TAG, "CustomBinder.Stub.Proxy-->" + "hello()执行");
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(content);
// 前面说过,只有当Server和Client不在同一个进程才会执行此代理的方法,而如果Server和Client不在同一个进程
// 那mRemote就是一个Binder.BinderProxy实例,那么此transact()方法就是Binder.BinderProxy的方法,
//他是一个本地方法,是交由Binder驱动去告诉服务端去执行onTransact(0方法。
mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
finally
_reply.recycle();
_data.recycle();
return _result;
static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
其实Stub.Proxy的hello()方法什么也没做,只是将一些必要的数据写入和读出Parcel,然后通过mRemote来调用transact()方法去告诉Binder驱动通知服务端调用真实的hello()方法。mRemote之前说过了,当服务端和客户端不在同一个进程时才会创建Stub.Proxy并且传递一个Binder.BinderProxy实例进来,
此mRemote就是一个Binder.BinderProxy实例,transact()方法自然就是BinderProxy的方法了,他是一个native方法,用于告诉Binder驱动去通知服务端调用onTransact()方法调用真实的hello()方法!也就是TestService.MyBinder的hello()方法!!!好,这一步我们说了客户端向服务端请求调用hello()方法,然而代理Stub.Proxy并没有直接去调用,而是告知Binder驱动。当我们通过mRemote调用transact()时客户端线程会被挂起,直到服务端有结果返回,确切的说是要等到Stub的onTransact()方法返回。
3、服务端响应客户端请求
注意:如果服务端和客户端不在一个进程,那么就不存在这一步了,请忽略。
上一步说了,客户端已经调用hello()向服务端发起请求,而那时候服务端还没有收到通知,因为客户端的请求被服务端的代理Stub.Proxy发送给Binder驱动了(通过BinderProxy的transac方法实现的),Binder驱动做一些必要的操作后再通知服务端有客户端请求了,你快去执行onTransact()方法来响应请求吧!接下来我们看下Stub的onTransact()方法:
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException
Log.e(TAG, "CustomBinder.Stub-->" + "onTransact()执行");
switch (code)
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_hello:
Log.e(TAG, "CustomBinder.Stub-->"
+ "TRANSACTION_hello执行:服务端执行本地hello方法");
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
// 这里调用了服务端本地的hello()方法,并且获得结果,将结果写回驱动,
// 然后驱动唤醒挂起的Client进程里面的线程并将结果返回。于是一次跨进程调用就完成了。
java.lang.String _result = this.hello(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
return super.onTransact(code, data, reply, flags);
其它不用管,我们就看上面注释的地方,这一行代码:
java.lang.String _result = this.hello(),它就是去调用了服务端(我们此时是处于服务端的情景之中)自己的hello()方法,也就是TestService.MyBinder的hello()方法,并返回结果,将结果写到reply中去,即写回Binder驱动,之后Binder驱动就唤醒还挂着的客户端线程,并将结果返回,这样,一个跨进程通信的过程就结束了。
小结
如果Server和Clienr在同一个进程,那么Server会直接调用Service中的相关方法,如果Server和Clienr不在同一个进程,那么就会通过跨进程通信远程调用,首先是Stub的代理类使用BinderProxy执行其transact(),这个方法是一个native的,里面进行了一系列的函数调用,最后就交给Binder驱动完成了;在通信过程中,Client进程陷入内核态,Client调用hello方法的线程挂起等待返回;驱动完成一系列的操作之后唤醒Server进程,调用了Server进程本地对象(Stub)的onTransact函数(实际上由Server端线程池完成)。我们再看Binder本地对象的onTransact方法(这里就是Stub类里面的此方法),然后onTransact()就调用了服务端的hello()方法并将结果写回Binder驱动,然后驱动唤醒挂起的Client进程里面的线程并将结果返回,一次跨进程远程调用就结束了。
Android中Binder相关接口
(1)IBinder
IBinder是一个接口,它代表了一种跨进程传输的能力;只要实现了这个接口,就能将这个对象进行跨进程传递;这是驱动底层支持的;在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。
(2)Binder
代表的其实就是Binder本地对象。BinderProxy类是Binder类的一个内部类,它代表远程进程的Binder对象的本地代理;这两个类都继承自IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder驱动会自动完成这两个对象的转换。
到此,我们基本理清了Server端和Client端的跨进程通信过程,那么我们是否想过,这一切都是建立在客户端获取到服务端对象的基础上的,也就是我们在Activity中实现ServiceConnection接口,他的onServiceConnected()方法返回给我们一个远程的服务端对象。那么我们是否考虑过,这个onServiceConnected()方法何时调用,即何时会返回给我们一个远程的对象?这就是bindService()所处理的了,下一篇我们就解开bindService()之谜。
binder详解(代码片段)
文章目录什么是BinderBinder的由来性能稳定性安全性Binder优势总结Binder通信机制进程隔离进程空间划分:用户空间(UserSpace)/内核空间(KernelSpace)系统调用:用户态与内核态Binder四个重要角色什么是BinderBinder是一种进程间通信... 查看详情
android进阶——framework核心之binder对象管理者servicemanager守护进程及其自身代理对象详解(代码片段)
...、service_manager.c#main函数完成servicemanager进程的初始化2.1、binder.c#binder_open函数初始化binder设备文件和完成内存映射2.2、binder.c#binder_become_context_manager函数执行将ServiceManager变成BinderIPC的上下文管理者2.3、配置selinux机制相关2.4、binde... 查看详情
android进阶——framework核心之binder对象管理者servicemanager守护进程及其自身代理对象详解(代码片段)
...、service_manager.c#main函数完成servicemanager进程的初始化2.1、binder.c#binder_open函数初始化binder设备文件和完成内存映射2.2、binder.c#binder_become_context_manager函数执行将ServiceManager变成BinderIPC的上下文管理者2.3、配置selinux机制相关2.4、binde... 查看详情
androidbinder框架层详解(代码片段)
在了解完binder在native层以及驱动层的基本流程之后(参考Android如何注册服务到ServiceManager;Android系统服务管家servicemanager启动过程详解),接下来这篇文章我们就来分析下binder在framework层(Java层)的具体原理与实现,... 查看详情
android进阶——binderipc之native服务的启动及代理对象的获取详解(代码片段)
文章大纲引言一、Binder线程池的启动1、ProcessState#startThreadPool函数来启动线程池2、IPCThreadState#joinThreadPool将当前线程进入到线程池中去等待和处理IPC请求二、Service代理对象的获取1、获取ServiceManager代理对象BpServiceManager2、调用BpSe... 查看详情
android进阶——binderipc之native服务的启动及代理对象的获取详解(代码片段)
文章大纲引言一、Binder线程池的启动1、ProcessState#startThreadPool函数来启动线程池2、IPCThreadState#joinThreadPool将当前线程进入到线程池中去等待和处理IPC请求二、Service代理对象的获取1、获取ServiceManager代理对象BpServiceManager2、调用BpSe... 查看详情
android进阶——framework核心之binderjava成员类详解(代码片段)
文章大纲引言一、BinderJava家族核心成员关系图二、BinderJava家族核心成员源码概述1、android.os.IBinder1.1、booleantransact(intcode,Parceldata,Parcelreply,intflags)sendacalltoanIBinderobject1.2、StringgetInterfaceDescriptor()1.3、booleanpingBinder()检测Binder是否存... 查看详情
pms启动apk安装流程详解(代码片段)
...端通信的业务函数,还定义了内部类Stub,该类从Binder派生并实现了IPackageManager接口PackageManagerService继承自IPackageManager.Stub类,由于Stub类从Binder派生,因此PackageManagerService将作为服务端参与Binder通信Stub定义了一个... 查看详情
android进阶——aidl详解(代码片段)
看这篇之前先看看binder:Android——Binder机制.1.简介AIDL(Android接口定义语言),可以使用它定义客户端与服务端进程间通信(IPC)的编程接口,在Android中,进程之间无法共享内存(用户空间)... 查看详情
android进阶——binderipc详解之学习binderipc前应该掌握的相关常识(代码片段)
...理1、内核态和用户态2、IPC步骤四、内核模块和驱动五、Binder1、BinderIPC概述2、Binder的优势2.1、Binder传输性能高2.2 查看详情
android系统服务管家servicemanager启动过程详解(代码片段)
...到移动设备耗电以及跨进程通信效率等因素,基于OpenBinder专门为进程通信开发了一套框架:binder。例如,客户端程序需要获取WindowManager,TelephonyManager等系统服务时,就需要通过binder这个中介来负责数据与指令的传... 查看详情
android进阶——framework核心之bindernative成员类详解(代码片段)
...ocalInterface(constString16&_descriptor)模板函数1.4、staticsp<IBinder>asBinder(constIInterface*)安全触发onAsBinder函数2、IBinder3、BBinder(Binder本地对象)3.1、transact和onTransact函数4、BpBinder4.1、BpBinder构造函数4.2、mHandle引用对象句柄4.3... 查看详情
openharmonyipc通讯详解(代码片段)
...ll)机制用于实现跨进程通信,不同的是前者使用Binder驱动,用于设备内的跨进程通信,而后者使用软总线驱动,用于跨设备跨进程通信。IPC和RPC通常采用客户端- 查看详情
细读《深入理解android内核设计思想》binder机制[下](代码片段)
...,对重点深入补充,输出结构清晰的精简版深入binder驱动内部binder_ioctlbinder_get_threadbinder_ioctl_write_readbinder_thread_writebinder_transactionbinder_thread_read小结binderQ&A如何找到目标进程Binder实体如何实现Binder线程的睡眠与唤醒最... 查看详情
binder(代码片段)
前言Binder是Android核心中的核心。Android各种服务都是通过Binder来实现进程间通讯的,我计划分三部分大概剖析一下binder的具体原理。Binder的具体使用案例源码分析大概流程实现最简单的binder正文binder是分为两部分的,一部... 查看详情
binder驱动(代码片段)
Binder驱动是Binder的最终实现,ServiceManager和Client/Service进程间通信最终都是由Binder驱动投递的。Binder驱动的代码位于kernel代码的 drivers/staging/android 目录下。主文件是 binder.h 和 binder.cBinder驱动的逻辑图进程间传... 查看详情
androidframework实战开发-binder通信java及jni部分源码分析(代码片段)
csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论android跨进程通信实战视频课程(加群获取优惠)1、第一部分进程与ServiceManager通信及客户端程序发起调用详解平时大部分获取Service... 查看详情
androidframework实战开发-binder通信java及jni部分源码分析(代码片段)
csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论android跨进程通信实战视频课程(加群获取优惠)1、第一部分进程与ServiceManager通信及客户端程序发起调用详解平时大部分获取Service... 查看详情