Android Binder
1.Binder实例
Step-1. Activity使用startService()函數來啟動Service。
Step-2. Activity調用bindService()来绑定Service。亦即,Activity建立与Service之间的连结(Connection)。
Step-3. Activity調用IBinder接口的transact()函数,透过底层Binder Driver驱动而间接調用到Binder基类的execTransact()函数,转而調用 myBinder的onTransact()函数。
package com.example.test2;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.util.Log;
public class MainActivity extends Activity {
private Mp3Binder mp3bind;
private ServiceConnection mConnection =new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder ibinder) {
Log.e("MainActivity", "----------");
mp3bind = (Mp3Binder)ibinder;
Log.e("MainActivity", "+++++++++++");
if(mp3bind == null)
{
Log.e("MainActivity", "pProxy null");
}
else
{
Log.e("MainActivity", "pProxy notnull");
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeString("playing");
try
{
mp3bind.transact(1, data, reply, 0);
//mStatus = reply.readString();
System.out.println("---"+reply.readString());
}
catch (Exception e)
{
e.printStackTrace();
}
}
Log.e("MainActivity", "pProxy aaaa");
}
@Override
public void onServiceDisconnected(ComponentName name)
{
// TODO 自动生成的方法存根
Log.e("MainActivity", "pProxy bbbb");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent("com.example.test2.REMOTE_SERVICE"));
bindService(new Intent("com.example.test2.REMOTE_SERVICE"),
mConnection, Context.BIND_AUTO_CREATE);
}
}
package com.example.test2;
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Message;
import android.os.Parcel;
import android.util.Log;
/**
* 实现具体方法
* @author chenhan
*
*/
public class Mp3Binder extends Binder
{
private Context ctx;
public Mp3Binder(Context cx)
{
ctx= cx;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException
{
reply.writeString(data.readString()+ " mp3");
//Log.e("mp3Binder", data.readString());
if(code == 1)
{
Log.e("mp3Binder", "mp3Binder : play");
}
else if(code == 2)
{
Log.e("mp3Binder", "mp3Binder : stop");
}
return true;
}
}
package com.example.test2;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class Mp3RemoteService extends Service {
private IBinder mBinder = null;
@Override
public void onCreate()
{
Log.e("mp3RemoteService", "mp3RemoteService : start");
mBinder = new Mp3Binder(getApplicationContext());
Log.e("mp3RemoteService", "mp3RemoteService : over");
}
@Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
}
2.Binder原理
所谓建好了服务绑定(Bind)之后,就如同建好了跨进程的桥梁。之后,就能随时透过这桥梁而进行从myActivity調用到myService的跨进程IPC通信。绑定了服务之后,就能从myActivity調用BinderProxy(透过IBinder接口)的IBinder接口,执行了transact()函数。如下图:
在上图里,从JNI本地模块拉了一条红色虚线,表示这并非直接的通信途径。也就是,实际上是透过底层Binder Driver驱动才調用到BBinder的IBinder接口。如下图:
3.Binder通信
Binder是一种基于C/S的架构,主要包括四个部分:服务端(Server),客户端(Client),Binder驱动,ServiceManager。Binder是Android系统中非常重要的一种IPC机制,如果你想研究Frameworks,必须先对Binder机制诱有一定的认识,否则是无法看懂Frameworks源码的。上述四个部分分别在不同的进程中,他们之间的交互都是通过Binder实现,现在站在宏观的角度来分析Server,Client,ServiceManager之间的关系,如下图:
Android需要建立一套新的IPC机制来满足系统对通信方式,传输性能和安全性的要求,这就是Binder。Binder基于 Client-Server通信模式,传输过程只需一次拷贝,为发送发添加UID/PID身份,既支持实名Binder也支持匿名Binder,安全性 高。
所谓将数据从进程A传递到进程B,就是将进程A的某块用户空间(0~3G)的内容复制到进程B的某块用户空间(0~3G)的内存中。
因此,为了将数据从一个进程A复制到另一个进程B,我们需要:
1. 切换到内核态。因为只有内核态才能访问所有进程的用户态空间。
2. 将数据从进程A的用户态空间读出。
3. 在进程B的用户态空间中找一块内存空间,为其分配物理内存,然后将数据复制到该物理内存处。
4. 然后,进程B就可以从其用户空间读到数据了。
Binder Driver是如何在进程间传递数据的。其实,Binder driver要做的事情就是上面我们所列出的那几个步骤。
不过,对于每个进程,Binder driver会在进程打开binder driver后,通过ioctl系统调用为每个进程预先找一块用户态和内核态的内存空间,做为Binder buffer使用。
请注意,对于一个进程而言,其Binder buffer在用户态和内核态的内存被映射到了同样的物理内存地址。
下面我们看看利用Binder进行通信的两个进程之间是如何传递数据的:
1. Client进程有一块内存内容需要传递给Server进程
2. 切换到内核态
3. Binder driver读Client进程的用户态空间(0~3G)的这块内存内容
4. Binder driver将读出的内容复制到Server进程的Binder buffer中
5. 然后,当Server进程执行时,就能够在其用户态空间(0~3G)读传过来的内容了。因为Binder Buffer也被映射到了Server进程的用户态空间。
6. 当Server进程处理完读出的消息后,然后需要将处理的结果存放在一块用户态空间的内存中,希望将其返回给Client进程
7. 切换到内核态
8. Binder driver读Server进程的用户态空间(0~3G)的处理结果
4. Binder driver将读出的内容复制到Client进程的Binder buffer中
5. 然后,当Client进程执行时,就能够在其用户态空间(0~3G)读传过来的内容了。因为Binder Buffer也被映射到了Client进程的用户态空间。
这就是Binder driver如何实现进程间通信的。