先不分析 Native 、 Kerne 内核层 的 Binder源码。万物由简入繁,从最简单 Binder 在java 应用层使用说起 , 我们知道 Binder的使用可以借助 Messenger 和 AIDL 。 对于这两种的使用就不在多说了 , AIDL和Messenger 只不过是帮我们生成模板代码 ,简化我们的使用 , Binder在java层最终使用的都要通过如下写法。
Binder在java层的使用
server 端代码。
public class BinderService extends Service
{
private static final String DESCRIPTOR = "BinderService";
private static final String TAG = "BinderService";
private MyBinder mBinder = new MyBinder();
public IBinder onBind(Intent t)
{
return mBinder;
}
private class MyBinder extends Binder
{
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException
{
switch (code)
{
case 0x110:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = _arg0 * _arg1;
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
};
}
BinderService 需要在AndroidMenifest中注册 。
<service android:name=".BinderService" >
<intent-filter>
<action android:name="com.jansir.binder.demo" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
client端代码。
private IBinder mProxyBinder;
private ServiceConnection mServiceConntion = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{ //获取server的binder代理对象
mProxyBinder = service;
}
};
public void bindService(View view){
Intent intentPlus = new Intent();
intentPlus.setAction("com.jansir.binder.demo");
boolean res = bindService(intentPlus, mServiceConntion, Context.BIND_AUTO_CREATE);
}
public void callServer(View view){
if (mProxyBinder != null){
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try
{
//方法标注远程服务名称
_data.writeInterfaceToken("BinderService");
_data.writeInt(50);
_data.writeInt(12);
mProxyBinder.transact(0x110, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show();
} catch (RemoteException e){
e.printStackTrace();
} finally{
_reply.recycle();
_data.recycle();
}
}
}
这是一个典型的C/S 通信模式。 什么是C/S通信模式?
C/S通信模式即客户(client)/ 服务器(server)模型。 以我们日常使用最多的Http 来说 , 一次完整的Http短连接通信主要分为以下几个步骤 :
1.建立连接;
2.发送请求信息;
3.获取响应信息;
4.关闭连接。
Binder在java使用层设计思想
Binder 的设计思想和上述大致相同 , client 通过bindService 和 server建立连接 ,然后client 通过 server 返回的 BinderProxy 调用server方法发送请求信息 , 最后获取server的响应信息 , 通过 unbindService 关闭连接。 说完Binder的设计思想 , 接下来说下Binder的设计原理 :
Binder的设计原理
想要理解Binder的设计原理, 就不得不思考一个问题,为什么要有Binder ?
Android系统基于Linux内核 ,现有的Linux的IPC机制种类 :1.共享内存 2.管道 3.消息队列 4.socket 等 ,关于Linux的IPC 更详细的介绍, 可以看这篇 linux基础——linux进程间通信(IPC)机制总结
我们需要的IPC 机制 , 是性能好、安全性高、开发者使用不繁琐,可以看到这些传统的Linux 通信机制根本不满足我们对于IPC的要求。
那Binder是怎么做到高性能的呢? 先来看下这张图
可以看到用户空间和内核空间只发生一次数据拷贝 , 性能够好了吧 。 但我还想性能更加好,能不能连一次数据拷贝都不用?
我看你就是在刁难Binder , 一次数据都不拷贝那明显是不行的。任何毫无关系的两方需要通信肯定是需要借助第三方的 。比如你看我的文章现在就是要借助平台 , 文章就是通信的内容 , 如果没有内容你也不知道我在说什么,也就无法通信了。 所以binder机制也是如此,不发生数据的拷贝肯定是无法通信的。 好了,干说了这么多原理还是没提。先别急,再来说说上图的内存映射吧。
mmap 内存映射,简而言之就是将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间<---->用户空间两者之间需要大量数据传输等操作的话效率是非常高的。
再来一张图
现在可以用一句很长的话来总结Binder原理了 。
server端Binder 实体借助Binder驱动与内核空间mmap建立映射关系,然后注册到ServiceManager中。client端从ServiceManager中获取到server的binder代理(或者引用),通过copy_from_user将数据copy到内核空间, server因为存在映射关系也能获取到内核空间的数据,server通过修改内存间接的修改内核空间数据 ,双方通过内核空间的数据进行通信。
啊原来Binder 这么简单 , 我懂了,我这就去手写一个。
但Binder源码横跨 应用 、framework、JNI 、Native、内核 、物理内存层 。牵涉到JAVA 、C++ 、C 语言。 一句话也只能说个大概原理。接下来我们就以实际问题去分析Binder吧。
分析实际问题之前先说说Binder的总体架构。
Binder的总体架构
先来看下Binder总体架构图和总体类图
关键类图
可以看到无论是Framework 和 Native 层 ,其实都是对Binder的封装而已。通过层层调用,最终都是通过ioctl去操作内核层达到通信的目的。
对Binder中的架构和类有个大概了解后,我们就以实际问题去分析Binder吧。
还记得文章开始的那个在java层使用的demo吗 , server端的Binder 实体 , 通过onBind 返回给客户端 。我们知道客户端使用的是BinderProxy ,并不是server端的Binder 实体,两个进程无论如何都不能使用同一个对象, 那么它是如何在变成BinderProxy的呢? 带着这个问题我们分析下,binder 引用(句柄)是怎么从server端 传递到client的。
Binder 引用(句柄)的传递过程
先看下 server端的Binder 的实例化过程
private MyBinder mBinder = new MyBinder();
MyBinder 继承自android.os.Binder , 我们看下android.os.Binder的构造函数
public Binder(@Nullable String descriptor) {
mObject = getNativeBBinderHolder();
}
getNativeBBinderHolder 会调到/frameworks/base/core/jni/android_util_Binder.cpp 的方法,返回的是binder在native对象的引用地址。
JavaBBinderHolder 持有JavaBBinder ,JavaBBinder 才是关键对象, 我们看下JavaBBinder 就行了。
// frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder
{
public:
// 构造函数
JavaBBinder(JNIEnv* env, jobject /* Java Binder */ object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
{
......
}
// 获取我们 Java 中实例化的 Binder 对象
jobject object() const
{
return mObject;
}
protected:
// Native 层 JavaBBinder 的 onTransact 函数
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
// 将 JavaVM convert2 JNIEnv
JNIEnv* env = javavm_to_jnienv(mVM);
// 回调 java 中 Binder 对象的 execTransact 方法
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
// ......
if (code == SYSPROPS_TRANSACTION) {
// 回调父类的 onTransact 函数
BBinder::onTransact(code, data, reply, flags);
}
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
private:
JavaVM* const mVM; // JavaVM 指针对象, 用于获取 JNIEnv*
jobject const mObject; // Java 中的 Binder 对象, 即我们在 Java 中创建的实例
};
从上述代码可以看到 JavaBBinder 继承了 BBinder, 它内部持有了 JavaVM 和 Java 中的 Binder 对象实例, 因此 JavaBBinder 是 Native 层 BBinder 与 Java 层 Binder 连接的桥梁。
总结
java层的Binder 对象与 Native 层的 BBinder 对应。
还记得在service 的onBind 方法中将 Java 层 Binder 对象返回吗?那么这个对象返回到哪里去呢?
这个时候就要先看看bindService 流程了,流程图如下。
这里的进程需要先搞清楚,AMS、WMS、PMS等都是在 system_server进程 , 而system_server进程是由Zygote fork 创建出来的。Zygote 和serviceManager 都是由天字一号进程init创建出来的。
如图
server onBind 被调用时机
onBind方法在server进程的ActivityThread 中被调用
ActivityManager.getService() 就是我们的AMS的binder Proxy 对象 , 接下来看看AMS的binder Proxy 对象 的publishService方法。 注意这里不能直接查看AMS.java类中的publishService方法
而是先看IActivityManager的Proxy类中publishService的方法, 调用AMS的publishService方法需要先经过aidl编译生成的IActivityManager.Stub.Proxy.class,
这里才是调到AMS的publishService方法。 这个_arg2就是client的binder引用对象。看以看到_arg2会传给AMS , 而AMS又会把这个传给我们的client 端 。看来client端的binder对象就是在AMS中生成的 。 我们跟进 _arg2 = data.readStrongBinder()看看 。最终又会调到native 层的 readStrongBinder方法。
//android.os.Parcel
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
native 层 parcel->readStrongBinder()
javaObjectForIBinder 方法就是将native 的IBinder转换成jave的IBinder 并返回。我们来看下Parcel 类的 readStrongBinder方法。
readNullableStrongBinder -> unflatten_binder(ProcessState::self(), *this, val)
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->hdr.type) {
// 我们在flatten中的Type就是这个!
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
最终会调到Parcel#finish_unflatten_binder , 直接返回一个NO_ERROR
回到最初分析的android_os_Parcel_readStrongBinder方法 , 此方法内部会调用一个javaObjectForIBinder方法, 这个方法是在android_util_Binder.cpp类中
//android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
jobject object = static_cast<JavaBBinder*>(val.get())->object();
return object;
}
BinderProxyNativeData* nativeData = new BinderProxyNativeData();
nativeData->mOrgue = new DeathRecipientList;
nativeData->mObject = val;
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
return object;
}
搜索gBinderProxyOffsets
可以看到javaObjectForIBinder 这个方法就是在native中构建出java 层的BinderProxy 对象将返回给java层 。 在client 端BinderProxy与 native层的BpBinder建立联系 。
AMS 将BinderProxy 返回给clien端代码如下。
//com.android.server.am.ActivityManagerService
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
try {
if (r != null) {
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
//调用client端
c.conn.connected(r.name, service, false);
}
}
}
}
//下面的代码在client 进程调用 , IServiceConnection.Stub
private static class InnerConnection extends IServiceConnection.Stub {
@UnsupportedAppUsage
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
//android.app.LoadedApk
public void doConnected(ComponentName name, IBinder service, boolean dead) {
if (service != null) {
//调用client onServiceConnected 将service返回
mConnection.onServiceConnected(name, service);
}
}
总结
server端的Binder 实体对象 ,在AMS 所属的system_server进程被转换成BinderProxy 对象然后传给了client端 。server 端Binder 和client 端BinderProxy 对象的联系如下图。
你以为这就完了 ? 还有client端的BinderProxy的transact 方法流程还没分析。
BinderProxy#transact 方法分析
client端的BinderProxy的transact方法中只有这一个return 。
transactNative 顾名思义应该是调用到native中去了。
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
IBinder* target = getBPNativeData(env, obj)->mObject.get();
if (target == NULL) {
//binder被回收了
jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
return JNI_FALSE;
}
//这里会调到BpBinder#transact方法
status_t err = target->transact(code, *data, reply, flags);
return JNI_FALSE;
}
进入BpBinder#transact方法
调用到IPCThreadState#transact 方法
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
// 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
//不需要等待服务端的返回结果的情况
err = waitForResponse(nullptr, nullptr);
}
return err;
}
transact主要过程: 先执行writeTransactionData()已向Parcel数据类型的mOut写入数据,此时mIn还没有数据; 然后执行waitForResponse()方法,循环执行,直到收到应答消息. 调用talkWithDriver()跟驱动交互,收到应答消息,便会写入mIn, 则根据收到的不同响应吗,执行相应的操作。 IPCThreadState#waitForResponse方法
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break; //当存在error则退出循环
//每当跟Driver交互一次,若mIn收到数据则往下执行一次BR命令
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
//只有当不需要reply, 也就是oneway时 才会跳出循环,否则还需要等待.
if (!reply && !acquireResult) goto finish; break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT; goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION; goto finish;
case BR_REPLY: ... goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
finish:
if (err != NO_ERROR) {
if (reply) reply->setError(err); //将发送的错误代码返回给最初的调用者
}
return err;
}
在这个过程中, 收到以下任一BR_命令,处理后便会退出waitForResponse()的状态:
- BR_TRANSACTION_COMPLETE: binder驱动收到BC_TRANSACTION事件后的应答消息; 对于oneway transaction,当收到该消息,则完成了本次Binder通信;
- BR_DEAD_REPLY: 回复失败,往往是线程或节点为空. 则结束本次通信Binder;
- BR_FAILED_REPLY:回复失败,往往是transaction出错导致. 则结束本次通信Binder;
- BR_REPLY: Binder驱动向Client端发送回应消息; 对于非oneway transaction时,当收到该消息,则完整地完成本次Binder通信;
talkWithDriver 方法 , 用于与BinderDriver 交互。
//mOut有数据,mIn还没有数据。doReceive默认值为true
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {
//接收数据缓冲区信息的填充。当收到驱动的数据,则写入mIn
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// 当同时没有输入和输出数据则直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//ioctl执行binder读写操作,经过syscall,进入Binder驱动。调用Binder_ioctl
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
...
} while (err == -EINTR);
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
调用ioctl去操作BinderDriver , BinderDriver 方面就不去分析了 ,后面再出文章分析 。
放一张大致流程图。
对于此文如果分析有出入请务必指出 , 另外文中的图涉及到版权问题请联系我删除。
部分参考文章:
Android Binder框架实现之Binder的设计思想