前段时间一直在看有关Binder的知识,最近刚好有时间,总结一些一些知识,希望和大家交流学习。
说起Binder我相信大家学android开发的多多少少都对binder有些了解,binder机制作为android进程间通信的一种机制,在Android底层中应用的非常多。我们都知道Android系统是基于LInux内核开发的,Linux内核提供了丰富的进程间通信的机制,如:管道、信号、消息队列、共享内存和套接字等,但是Android系统并没有采用传统的进程间通信机制,而是开发了一套新的进程间通信的机制BInder,当然采用Binder肯定有一些优势,与传统的进程间通信相比,BInder进程通信机制在进程间传输数据的时候,只需要执行一次拷贝操作,因此,在效率和内存节省方面有一定的优势。
接下来我们就开始谈谈Binder了,Binder说白了就是Android中的一个类,它实现了Ibinder接口,从Android-Framework角度来说,Binder是ServiceManager连接各种Manager(ActivityManager、WindowManager等)和相应的Manager_Service的桥梁;下面有一张他们之间的图
Binder在进行进程间通信的时候,每一个Server进程和Client进程都维护一个Binder线程池来处理进程间的通信要求,Service组件在启动时,会将自己注册到一个Service Manager组件中,以便Client组件可以通过Service Manager组件找到它。上图中Binder驱动程序和Service Manager由系统提供,Client和Service由应用程序实现,接下来我已我们Android中最常用的AIDL为例讨论一下
编写一个AIDL程序需要以下几步:
首先我们看看服务端程序需要的步骤:
(1)首先编写你的类(book.java)文件,这个类必须实现Parcelable接口进行序列化。
(2)编写与该类相同的名的aidl文件(book.aidl)
(3)编写接口文件(IBookManager.aidl),此接口即客户端请求时的接口
(4)实现服务端的service(BookManagerService),该service为客户端实际进行服务(主要实现Stub类)
接下来我们看看客户端要实现的步骤:
客户端其实与服务端很多地方相似:
(1)我们这一块需要将服务端的所有AIDL文件拷贝带客户端,这里的报名必须与服务端一致,因为存在序列化与反序列化问题
(2)编写客户端Activity,绑定服务端service
(3)实现ServiceConnection,在onServiceConnected方法中,将讲IBinder转化为AIDL接口类型,然后调用远程服务
(4)如果远程服务比较耗时,可以将调用方法从主线程中分离出来,开一个子线程,这样程序就不会崩溃
好吧,大家现在估计也是很懵逼的吧,我再给大家理一遍然后就上代码了:
首先大家可以看到,当我们新建一个AIDL文件之后,在gen文件夹下会生成一个对应的AIDL文件,他是系统为我们自动生成的一个接口类,继承自android.os.IInterface接口,其中有几个比较重要的类和方法这里我给大家一一说明:
首先是stub类,这个Stub类继承BInder实现了我们定义的AIDL接口,这个类也是我们客户端在实际要用到的类,在这个类中有一个asInterface方法,他的参数是一个IBinder接口,他返回了另一个Stub的内部类proxy,这个proxy类真正实现了AIDL接口,每当客户端通过Stub的asInterface方法获取到该类时,调用具体的接口方法时,proxy类里面会调用transact,当客户端和服务端都位于一个进程时,方法调用就不会走跨进程的transact过程,如果不在同一个进程的话将会交给Proxy的处理,这里transact有几个参数第一个参数为请求的方法类型,接下来_data与_reply他们两个是一个parcel类型,其中分别封装客户端的请求信息和服务端反馈的信息,然后底层通过Bindler传送到onTransact方法中,他会从客户端传过来的参数中判断客户端请求的是那个方法,里面的请求信息是什么,接下来会将数据写入,返回到客户端。
上面就是BInder跨进程的的整个流程,下面就是上代码了:
AIDL文件
Book.java
package com.binderpro.aidl;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable{
private String name;
private int price;
private int bookId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Book(String name, int price) {
super();
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Book [name=" + name + ", price=" + price + "]";
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel arg0, int arg1) {
// TODO Auto-generated method stub
arg0.writeInt(bookId);
arg0.writeString(name);
arg0.writeInt(price);
}
public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>(){
@Override
public Book createFromParcel(Parcel arg0) {
// TODO Auto-generated method stub
return new Book(arg0);
}
@Override
public Book[] newArray(int arg0) {
// TODO Auto-generated method stub
return new Book[arg0];
}
};
private Book(Parcel in){
bookId = in.readInt();
name = in.readString();
price = in.readInt();
}
}
Book.aidl
package com.binderpro.aidl;
parcelable Book;
IBookManager
package com.binderpro.aidl;
import java.util.List;
import com.binderpro.aidl.Book;
interface IBookManager {
List<Book> getBookList();
void addBook(in Book book);
}
BookManagerService
package com.example.binderpro;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import com.binderpro.aidl.Book;
import com.binderpro.aidl.IBookManager;
public class BookManagerService extends Service {
private static final String TAG = "BMS";
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
public BookManagerService() {
// TODO Auto-generated constructor stub
}
private Binder mBinder = new IBookManager.Stub() {
@Override
public List<Book> getBookList() throws RemoteException {
// TODO Auto-generated method stub
return mBookList;
}
@Override
public void addBook(Book book) throws RemoteException {
// TODO Auto-generated method stub
mBookList.add(book);
}
};
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
mBookList.add(new Book("android", 1));
mBookList.add(new Book("ios", 2));
}
public IBinder onBind(Intent intent){
return mBinder;
}
}
接下来是客户端代码,aidl文件同上
MainActivity.java
package com.example.binderpro;
import java.util.List;
import com.binderpro.aidl.Book;
import com.binderpro.aidl.IBookManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
}
@Override
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
// TODO Auto-generated method stub
IBookManager bookManager = IBookManager.Stub.asInterface(arg1);
List<Book> list;
try {
list = bookManager.getBookList();
Log.i("Tag", list.toString());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent("com.example.binderpro.BookManagerService");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unbindService(mConnection);
}
}
最后是系统根据AIDL文件生成的java代码;
IBookManager代码比较长,我删除了一部分
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: G:\\android_code\\Binderpro\\src\\com\\binderpro\\aidl\\IBookManager.aidl
*/
package com.binderpro.aidl;
public interface IBookManager extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements
com.binderpro.aidl.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.binderpro.aidl.IBookManager";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.binderpro.aidl.IBookManager
* interface, generating a proxy if needed.
*/
public static com.binderpro.aidl.IBookManager asInterface(
android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.binderpro.aidl.IBookManager))) {
return ((com.binderpro.aidl.IBookManager) iin);
}
return new com.binderpro.aidl.IBookManager.Stub.Proxy(obj);
}
@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.binderpro.aidl.Book> _result = this
.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addBook: {
data.enforceInterface(DESCRIPTOR);
com.binderpro.aidl.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.binderpro.aidl.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.binderpro.aidl.IBookManager {
private android.os.IBinder mRemote;
@Override
public java.util.List<com.binderpro.aidl.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.binderpro.aidl.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data,
_reply, 0);
_reply.readException();
_result = _reply
.createTypedArrayList(com.binderpro.aidl.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addBook(com.binderpro.aidl.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);
}
}
今天大概就讲这么多,最近我也正在研究一些关于Binder底层的东西,可能后续感觉自己能力到了会写一些关于Binder底层的东西,因为Binder实在太复杂了,在linux驱动层好多都是C代码,在底层都是以好多结构体和一些红黑树,hash表,引用链组织起来,其中一些Binder线程池、同步、缓冲区、死亡通知之间的关联十分复杂,有兴趣的可以看看罗升阳的《Android系统源码情景分析》这本书对于Binder底层机制讲的非常好。