Binder学习笔记(一)

本文详细解析了Android中AIDL与Binder的工作原理,包括Binder驱动、ServiceManager的作用及其实现,以及如何通过AIDL创建匿名服务进行跨进程通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
	}
	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public void writeToParcel(Parcel out, int arg1) {
		// TODO Auto-generated method stub
		out.writeInt(bookId);
		out.writeString(bookName);		
	}	
	public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {

		@Override
		public Book createFromParcel(Parcel in) {
			// TODO Auto-generated method stub
			return new Book(in);
		}

		@Override
		public Book[] newArray(int size) {
			// TODO Auto-generated method stub
			return 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() {
		
		@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 IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return mBinder;
	}
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.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(){
		@Override
		public void onServiceConnected(ComponentName arg0, IBinder service) {
			// TODO Auto-generated method stub
			IBookManager 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();
			}
	
		}
		@Override
		public void onServiceDisconnected(ComponentName arg0) {
			// TODO Auto-generated method stub	
		}
		
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Intent intent = new Intent("org.yi.Action");
		bindService(intent,mConnection,Context.BIND_AUTO_CREATE);
		
	}
	@Override
	protected void onDestroy() {
		unbindService(mConnection);
		super.onDestroy();
	}
}
注意,这里组件service的acrtion配置成org.yi.Action.

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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值