Android-Binder 简析
前言
对于Android来说,Binder的重要性怎么说都不为过。不管是我们的四大组件Activity、Service、BroadcastReceiver、ContentProvider,还是经常在应用中使用到的各种ServiceManager,其背后都是Binder在支撑。然而Binder机制又不是三言两语能够描述得清楚的,因此本文通过对一个简单的AIDL Demo进行分析,让读者对Binder有个初步的认识,要想深入了解Binder背后的原理,可以参考最后的延伸阅读。
Demo
首先我们通过AIDL新建一个跨进程通信的Demo,然后在代码中简单分析Binder的运行过程。
Server Module
我们先新建一个提供接口的AIDL服务端module,服务端主要提供AddBook和getBookList两个功能,其目录如下:

IBookManager.AIDL
// IAIDLServer.aidl
package com.nancyyihao.aidlserver;
import com.nancyyihao.aidlserver.Book;
// Declare any non-default types here with import statements
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
Book.java
package com.nancyyihao.aidlserver;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by jumper on 2016/9/7.
*/
public class Book implements Parcelable {
private String bookName;
private int bookId;
public Book(){}
public Book(int bookId, String bookName){
this.bookId = bookId ;
this.bookName = bookName ;
}
public Book(Parcel parcel){
bookName = parcel.readString();
bookId = parcel.readInt();
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(bookName);
dest.writeInt(bookId);
}
public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>(){
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
Book.AIDL
package com.nancyyihao.aidlserver;
parcelable Book;
BookManagerService
package com.nancyyihao.aidlserver;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by jumper on 2016/9/7.
*/
public class BookManagerService extends Service {
private static final String TAG = "BMS";
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
// to distinguish with client module, we set the book id different from client module
mBookList.add(new Book(3,"Android"));
mBookList.add(new Book(4,"iOS"));
}
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
} ;
}
Client Module
把Server module的代码拷贝一份(AIDL包名不能变),然后新建一个MainActivity即可
MainActivity
package com.nancyyihao.aidlserver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.nancyyihao.R;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
Log.e("trace", "onServiceConnected");
try {
List<Book> bookList = bookManager.getBookList();
Log.e(TAG, "query book list, list type:" + bookList.getClass().getCanonicalName());
Log.e(TAG, "query book list:" + bookList.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Intent intent = new Intent();
intent.setAction("com.nancyyihao.startservice");
intent.setPackage("com.nancyyihao.aidlserver"); // server's package name
Log.e("trace", "bindService");
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
}
分析
把代码写好后,build一下,就能看到自动生成了一个IBookManager.Java文件
IBookManager.Java

package com.nancyyihao.aidlserver;
// Declare any non-default types here with import statements
public interface IBookManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.nancyyihao.aidlserver.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.nancyyihao.aidlserver.IBookManager"; // Binder Indentifier
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.nancyyihao.aidlserver.IBookManager interface,
* generating a proxy if needed.
*/
public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) {
return ((com.nancyyihao.aidlserver.IBookManager) iin); // local Binder
}
return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); // remote Binder
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.nancyyihao.aidlserver.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.nancyyihao.aidlserver.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.nancyyihao.aidlserver.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.nancyyihao.aidlserver.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.nancyyihao.aidlserver.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException;
public void addBook(com.nancyyihao.aidlserver.Book book) throws android.os.RemoteException;
}
Client先调用bindService启动服务,会调用BookManagerService的onCreate方法,接着调用onBind方法,该方法会返回远程的Binder---mBinder,该Binder包含getBookList和AddBook两个方法的具体实现。
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
} ;
当Client和server成功建立连接时,就会调用Client的onServiceConnected(name, service)方法把远程的mBinder回调给Client,此时的service就是远程的mBinder对象
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IBookManager bookManager = IBookManager.Stub.asInterface(service);
Log.e("trace", "onServiceConnected");
try {
List<Book> bookList = bookManager.getBookList();
} catch (Exception e) {
e.printStackTrace();
}
}
Client端通过asInterface方法把mBinder转成AIDL接口,如果是本进程内的Binder就直接返回,否则返回内部代理类proxy
public static com.nancyyihao.aidlserver.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.nancyyihao.aidlserver.IBookManager))) {
return ((com.nancyyihao.aidlserver.IBookManager) iin); // local Binder
}
return new com.nancyyihao.aidlserver.IBookManager.Stub.Proxy(obj); // remote Binder
}
接着执行
try {
List<Book> bookList = bookManager.getBookList();
} catch (Exception e) {
e.printStackTrace();
}
此时的bookManager通过asInterface方法转换后,返回的实际上是本地的proxy类
private static class Proxy implements com.nancyyihao.aidlserver.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.nancyyihao.aidlserver.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.nancyyihao.aidlserver.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
通过代码我们可以看到proxy类其实也是一个IBookManager接口,调用bookManager.getBookList()其实是调用Proxy.getBookList。
@Override
public java.util.List<com.nancyyihao.aidlserver.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.nancyyihao.aidlserver.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.nancyyihao.aidlserver.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
在Proxy.getBookList方法中调用了mRemote.trasact()
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
Client就是在这里和Server进行远程通信的!把需要的参数放data中,服务端执行完后把接口写到result里。从代码中可以看到transact方法中调用了onTransact方法。我们再看看onTransact方法有啥东西。
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
......
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.nancyyihao.aidlserver.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
......
}
直接调用了this.getBookList方法返回结果,这个this到底是哪个对象?前面提到mRemote其实是远程中的Binder对象,其代码如下
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
mBookList.add(book);
}
} ;
this.getBookList其实就是mRemote.getBookList,就是上面代码中的mBinder.getBookList!然后把返回结果放到result中即可。至此,整个通信过程分析完毕。
总结
Client是通过本地的Proxy类像Server发起通信
Client通过ServerConnection接口回调收到Server远程Binder对象
IPC过程发生在transact方法中,该方法会挂起直到服务端返回结果,因此不能在主线程调用远程服务。

图片和文中Demo来自《Android开发技术探索》
源码下载
延伸阅读
Android-Binder 简析的更多相关文章
- Android MVP 简析
原地址:https://segmentfault.com/a/1190000003927200 在Android中应用MVP模式的原因与方法的简析,写的简单易懂.
- Android : SELinux 简析&修改
一 SELinux背景知识 SELinux出现之前,Linux上的安全模型叫DAC,全称是Discretionary Access Control,翻译为自主访问控制.DAC的核心思想很简单,就是: ...
- Android View 简析
基于android 4.4上源码分析: setContentView流程: getwindow() ->setContentView() -> installDecor() -> a ...
- android:installLocation简析
在Froyo(android 2.2,API Level:8)中引入了android:installLocation.通过设置该属性可以使得开发者以及用户决定程序的安装位置. android:inst ...
- Android Drawable 简析
Drawable 是开发中经常用到的一个概念,我们经常用它去设置 View 的背景,背景可以一个颜色值,也可以是一张资源图片,还可以是一个自定义的 Drawable等等.这篇文章就简单说下 Drawa ...
- Android -- ImageLoader简析
图片的内存缓存实现 Image-Loader库有一个较完整的内存缓存实现,使用者可以根据需要选择已经实现的策略,也可以定制自己项目中需要的策略. 内存缓存实现代码在memory和memory.impl ...
- Android -- 多媒体播放之MediaPlayer使用内部实现简析
Android -- MediaPlayer内部实现简析 在之前的博客中,已经介绍了使用MediaPlayer时要注意的内容.如今,这里就通过一个MediaPlayer代码实例,来进一步分析Media ...
- Java Android 注解(Annotation) 及几个常用开源项目注解原理简析
不少开源库(ButterKnife.Retrofit.ActiveAndroid等等)都用到了注解的方式来简化代码提高开发效率. 本文简单介绍下 Annotation 示例.概念及作用.分类.自定义. ...
- Android 启动过程简析
首先我们先来看android构架图: android系统是构建在linux系统上面的. 所以android设备启动经历3个过程. Boot Loader,Linux Kernel & Andr ...
- Android RecycleView + CardView 控件简析
今天使用了V7包加入的RecycleView 和 CardView,写篇简析. 先上效果图: 原理图: 这是RecycleView的工作原理: 1.LayoutManager用来处理RecycleVi ...
随机推荐
- c#中RadioButtonList选中后不整体刷新页面保持选中状态
c#中用asp的RadioButtonList控件总会遇到选中了,然后跟着就刷新整体页面,又变为没有选中状态. <%@ Page Language="C#" AutoEven ...
- Spring 对数据库的支持
DAO DAO是用于访问数据的对象,大多数时候,我们将数据保存在数据库中,但这不是唯一选择. 用户也可以将数据保存在数据文件或者LDAP中 DAO屏蔽了数据操作的具体细节 Spring本质上希望能够以 ...
- [HNOI2015][bzoj4011] 落叶枫音 [拓扑DP]
题面 传送门 思路 首先有一个结论(应该是有比较大的利用价值的): 有向无环图的生成外向树树个数等于所有入度非0的点的入度乘积 然后这道题里面,唯一不合拍的因素就是这里有一条可能成环的边 我们可以把这 ...
- BZOJ4888 [Tjoi2017]异或和 【树状数组】
题目链接 BZOJ4888 题解 要求所有连续异或和,转化为任意两个前缀和相减 要求最后的异或和,转化为求每一位\(1\)的出现次数 所以我们只需要对每一个\(i\)快速求出\(sum[i] - su ...
- JAVA本地文本读取---解决中文乱码
import java.io.*; public class ReadFile { public static void main(String[] args) { try { File file = ...
- 学习C++ -> 向量(vector)
一.向量的介绍 向量 vector 是一种对象实体, 能够容纳许多其他类型相同的元素, 因此又被称为容器. 与string相同, vector 同属于STL(Standard Template Lib ...
- UVaLive5059 Playing With Stones
数学问题 博弈 SG函数 我总觉得这题做过的……然而并没有记录 看上去是一个nim游戏的模型. 手推/打表找一下前几项的规律,发现x是偶数时,sg[x]=x/2,x是奇数时,sg[x]=sg[x di ...
- python Error Message: command 'gcc' failed with exit status 1
参考:[ CSDN ] 解决方法 yum install gcc libffi-devel python-devel openssl-devel
- [bzoj1026][SCOI2009]windy数——数位dp
题目 求[a,b]中的windy数个数. windy数指的是任意相邻两个数位上的数至少相差2的数,比如135是,134不是. 题解 感觉这个题比刚才做的那个简单多了...这个才真的应该是数位dp入门题 ...
- Linux/Android——input_handler之evdev (四) 【转】
转自:http://blog.csdn.net/u013491946/article/details/72638919 版权声明:免责声明: 本人在此发文(包括但不限于汉字.拼音.拉丁字母)均为随意敲 ...