Binder学习笔记(一)

来源:互联网 发布:锐捷交换机端口聚合 编辑:程序博客网 时间:2024/06/08 16:14

Android提供了多种IPC机制,比如文件共享,使用Messenger,也可以使用ContentProviderSocketAIDL,基于AIDL服务的IPC,就要用到Binder。要了解Binder,不仅要熟悉它在java层的框架,还要设计其在native层的实现,过程十分复杂。

说到Binder,主要设计到4个部分,Binder驱动,ServiceManager,服务端和客户端。

(1binder驱动:binder的核心,实现binder的底层操作。

(2SerciceManager:提供Binder的名称到引用对象的转换服务。有点类似于DNS

(3)服务端:Binder服务的提供者,也就是binder实体对象

(4)客户端:得到服务端binder实体对象的引用对象,并调用服务端的方法。

先从最简单的 ServiceManager说起,为什么说它类似于DNS呢,因为每一个Binder服务,都有一个唯一的字符串标识,只要这个Binder服务向ServiceManager注册了,那么客户就可以通过这个字符串标识查询到这个Binder服务的引用对象。但是ServiceManager是一个单独的进程,对于其他进程的请求查询,它相当于一个Service,其他的进程是怎么找到ServiceManager的呢?其实,ServiceManager比较特殊,它不用注册,它向Binder驱动发送BINDER_SET_CONTEXT_MGR命令,binder驱动会创建ServiceManager对象实体,并在binder驱动硬性的规定了0代表ServiceManager,这样,其他的进程就可以通过binder驱动的0直接得到ServiceManager的引用对象。这样,binder服务就可以在ServiceManager中注册了,客户进程就可以通过在ServiceManager查询得到这个Binder服务的引用对像了。

但是不是所有的Binder服务是可以在ServiceManager中注册的,只有root进程或者System进程才可以在ServiceManager注册服务,如ActivityManagerService。这类服务称为Biner实名服务。普通应用开发的binder服务只能是匿名服务。匿名服务无法在ServiceManager注册,也就无法通过ServiceManager查询到,那么匿名服务怎么IPC通信呢,其实也是通过BInder,在JAVAAndroid提供了组件Service的方式来包装和使用匿名服务。当我们在客户端通过bindService()发送一个Intent时候,根据该Intent启动一个Service,在组件Service中的binder对象随之启动,然后这个biner对象通过onServiceConnected()传回到客户端,这样客户端得到组件servicebinde引用对象了,得到这个引用对象后,客户端就可以向在本地进程中调用方法一样调用组件service中的方法了。(注:不要将组件servicebinder服务端弄混淆了,在这里只是借用组件service来实现binder的匿名服务)

当我们使用IntentBinder来进行传输数据时,就要把数据进行序列化,序列化在android平台上提供了两种方法,一种是继承Serializable接口I,一种继承Parcelable接口。Serializablejava的序列化接口,使用起来简单但是开销很大,序列化和反序列化过程需要大量的I/O操作,ParcelableAndroid中的序列化方式,使用起来麻烦但是效率很高,更适合于Android平台上。在java开发进程间通信中,应用binder的主要是AIDLAIDLandroid提供的一个跨进程通信的方式,它主要利用binder机制,下面提供一个AIDL的例子来创建一个binder匿名服务并和客户端进行跨进程通信。

这个例子就是在一个应用A中创建一个组件service,这个service实现两个方法,addbook()getBookList()。然后另外一个应用B中调用这两个方法,应用B充当客户端。这里两个应用要传递book这个对象,所以book是进行序列化和反序列化,这里我给出序列化代码。

public class Book implements Parcelable{public int bookId;public String bookName;public Book(int bookId,String bookName){this.bookId = bookId;this.bookName = bookName;}@Overridepublic int describeContents() {// TODO Auto-generated method stubreturn 0;}@Overridepublic void writeToParcel(Parcel out, int arg1) {// TODO Auto-generated method stubout.writeInt(bookId);out.writeString(bookName);}public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {@Overridepublic Book createFromParcel(Parcel in) {// TODO Auto-generated method stubreturn new Book(in);}@Overridepublic Book[] newArray(int size) {// TODO Auto-generated method stubreturn new Book[size];}};private Book(Parcel in){bookId= in.readInt();bookName = in.readString();}}
接下来我们要申明AIDL接口,在接口中申明service要实现的两个方法,eclipse会自动把AIDL文件转化为java文件。新建Java包,里面有3个文件,Book.java,Book.aidl

IBookManager.aidlBook.java文件代码上面已经给出。下面,我给出Book.aidlIBooManager.aidl代码。

book.aidl如下:

package com.ryg.chapter_2.aidl;parcelable Book;

 因为book对象继承Parcelable序列化的,所以要写aidl文件申明

IBookManager.aidl如下:

package com.ryg.chapter_2.aidl;import com.ryg.chapter_2.aidl.Book;interface IBookManager{List<Book> getBookList();void addBook(in Book book);}

这时候你看project下面的gen文件,它自动把这两个aidl文件转化成了java文件。我们也可以自己写出这些java文件的,AIDL让我们只要申明接口就自己帮我们转换了,为

我们节省了不少事。

写完了这几个文件后,我们就可以实现组件Service了。

远程服务端实现:

public class BookManagerService extends Service{private static final String TAG = "BMS";private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();private Binder mBinder = new IBookManager.Stub() {@Overridepublic List<Book> getBookList() throws RemoteException {// TODO Auto-generated method stubreturn mBookList;}@Overridepublic void addBook(Book book) throws RemoteException {// TODO Auto-generated method stubmBookList.add(book);}};@Overridepublic IBinder onBind(Intent arg0) {// TODO Auto-generated method stubreturn mBinder;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();mBookList.add(new Book(1,"Android"));mBookList.add(new Book(2,"Ios"));}}
至此,应用A即远程服务端的代码实现了。

接下来,我们应用B即客户端的实现。

将应用A中的book.java,book.aidl,IBookManager.aidl的3个文件拷贝到应用B的工程文件下,放在一个包中,且这个包的名字和应用A中放这3个

文件的包名字要一致(不要将这包名同时作为这两个应用的启动包名,不然会冲突)。

 客户端实现比较简单了,代码如下:

public class BookManagerActivity extends Activity implements OnClickListener{private static final String TAG = "BookManagerActivity";private ServiceConnection mConnection = new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName arg0, IBinder service) {// TODO Auto-generated method stubIBookManager bookManager = IBookManager.Stub.asInterface(service);try{list = bookManager.getBookList();Book newBook = new Book(3,"android开发");Log.i(TAG,"query book list,list type:"+list.getClass().getCanonicalName());Log.i(TAG,"query book list:"+list.toString());} catch (RemoteException){e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName arg0) {// TODO Auto-generated method stub}};@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent("org.yi.Action");bindService(intent,mConnection,Context.BIND_AUTO_CREATE);}@Overrideprotected void onDestroy() {unbindService(mConnection);super.onDestroy();}}
注意,这里组件service的acrtion配置成org.yi.Action.

整个AIDL流程讲完了,下一篇将对AIDL文件自动生成的java文件和binderq驱动进行分析,






0 0
原创粉丝点击