binder学习笔记
来源:互联网 发布:淘宝多少级能上直通车 编辑:程序博客网 时间:2024/06/06 15:11
binder是android系统服务与应用进程之间的桥梁,可以说是整个android系统的基石.
1. binder概述
binder机制主要分为Java层,native层和驱动层.其中Java层和native层运行在用户空间,驱动层运行在内核空间.Java层主要是应用进程的接口, 通过jni调用到native层,主要实现在native层和驱动层.binder驱动通过内存映射达到一次拷贝就实现进程间通信的目的.从设计模式看,binder使用了代理模式,在java层和native层都有本地端和代理端.以AMS为例,在java层的本地端为ActivityManagerNative,而AMS是他的子类,ActivityManagerNative又是Binder的子类.其实所有android系统服务都是Binder的子类.在java层对应代理端和本地端的还有BinderProxy与Binder.而在native层的本地端是BBinder, 代理端是BpBinder. 下面借用一张http://gityuan.com的图.
binder层次图
Binder通信涉及三个进程,client进程,service进程和service manager进程.service manager进程是binder进程通信的大管家,系统在启动的时候将系统服务(AMS,PMS,WMS等)注册到service manager中,在注册过程中,service manger进程会给服务创建binder本地对象JavaBBinder,JavaBBinder持有Java服务的对象引用.应用进程访问这些系统服务时需要先从service manager处获取服务的远程代理对象.应用进程自己的service组件不需要在service manager上注册,其他应用进程如果需要使用,直接绑定service即可,绑定的过程实际上是通过AMS直接获取应用service的binder代理对象.
binder架构图
2.通信流程
一次binder通信大体上可分为以下4个步骤:
1) client进程调用service manager的getService(0方法获取服务发远程代理对象.
在执行getService()过程中,service manager先为目标服务进程创建native层Binder代理对象BpBinder,并把驱动传上来的句柄值handle传进BpBinder,然后为目标服务进程创建 java层的代理对象BinderProxy,并把BpBinder作为参数mObject传进BinderProxy,最后用BinderProxy作为参数mRemote为目标服务进程创建远程代理对象xxxServiceProxy.
2) client进程发起与service进程的通信
这一步就按照java层,native层和驱动层分为3个小步骤
java层: client进程在获取service的远程代理后,可以使用service提供的各种服务.具体实现是通过远程代理xxxServiceProxy调用mRmote的transact()方法,而mRemote是
BinderProxy对象,也就是说最终调用了BinderProxy对象的transact()方法.
native层: BinderProxy通过jni进入native后,首先将java层的parcel对象转换为C++的parcel对象,然后获取服务端在native的binder代理对象BpBinder,最后调用BpBinder的
transact()方法将数据拷贝到内核空间.之后client进程向binder驱动发起ioctl请求,最后循环调用talkWithDriver()方法并阻塞在这里一直到接收到BR_XXX命令才会结束该过程,
驱动层: binder驱动根据拷贝到内核空间数据中的BpBinder对象的handle值找到目标进程,并将内核空间中存储通信数据的这段内存映射到目标服务进程的用户空间中,并给目标
进程发送BC_TRANSACTION命令.
3) 目标进程的处理并返回
目标进程在收到命令后,调用服务的JavaBBinder的onTransact()方法,经过几次调用最终调到目标service的onTransact()方法,并在该方法中做相应处理.处理完后将结果写入
reply并用同样的方法拷贝到binder驱动中.
4) client进程接收返回结果
client进程因为一直阻塞在waitForResponse()中,接收到返回结果后,停止阻塞,继续后面的动作.
==================================================================================================================================
下面以startActivity为例,详细介绍一次binder通信流程:
1.frameworks/base/core/java/android/app/Activity.java
public void startActivity(Intent intent)方法
在该类中经过几次调用,最后调到下面的方法
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options)
2.frameworks/base/core/java/android/app/Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options)
关键语句:
int result = ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
该语句首先获得service manager的代理ServiceManagerProxy
然后用ServiceManagerProxy获取ActivityManagerService的代理ActivityManagerProxy
class ServiceManagerProxy implements IServiceManager { public ServiceManagerProxy(IBinder remote) { mRemote = remote; } public IBinder asBinder() { return mRemote; } public IBinder getService(String name) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IServiceManager.descriptor); data.writeString(name); mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0); IBinder binder = reply.readStrongBinder(); reply.recycle(); data.recycle(); return binder; }}getService()方法通过调用readStrongBinder()方法,首先创建了AMS的native层的binder代理对象BpBinder,并把驱动传上来的句柄值传给BpBinder并作为成员变量mHandle.该句 柄值是IPC通信目标进程的标示,binder驱动会根据该值寻找通信的目标进程. 然后根据BpBinder创建Java层的binder代理BinderProxy.最后根据BinderProxy创建AMS的远程代理ActivityManagerProxy.
3. frameworks/base/core/java/android/app/ActivityManagerNative.java@ActivityManagerProxy
在ActivityManagerProxy里面执行startActivity(args...)方法
该方法里面的关键语句:mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
mRemote是一个BinderPoxy对象
4. frameworks/base/core/java/android/os/Binder.java@BinderProxy
进入BinderProxy类
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); return transactNative(code, data, reply, flags); } public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException; 在BinderProxy类中调用了jni方法transactNative(args...)5.frameworks/base/core/jni/android_util_Binder.cpp
JNI方法定义:
static const JNINativeMethod gBinderProxyMethods[] = { /* name, signature, funcPtr */ {"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder}, {"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive}, {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor}, {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact}, {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath}, {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath}, {"destroy", "()V", (void*)android_os_BinderProxy_destroy},};进入android_os_BinderProxy_transact(args...)方法static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException{ Parcel* data = parcelForJavaObject(env, dataObj); (1) if (data == NULL) { return JNI_FALSE; } Parcel* reply = parcelForJavaObject(env, replyObj); (2) if (reply == NULL && replyObj != NULL) { return JNI_FALSE; } IBinder* target = (IBinder*) (3) env->GetLongField(obj, gBinderProxyOffsets.mObject); ...... //printf("Transact from Java code to %p sending: ", target); data->print(); status_t err = target->transact(code, *data, reply, flags); (4) //if (reply) printf("Transact from Java code to %p received: ", target); reply->print(); ...... return JNI_FALSE;}(1)(2)先将java层的parcel转换为c++的parcel
(3)获得AMS的binder代理对象BpBinder
(4)用BpBinder对象传输数据
6.frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ // Once a binder has died, it will never come back to life. if (mAlive) { status_t status = frIPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT;}
7.frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ ............ if (err == NO_ERROR) { LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(), (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY"); err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); } ........... return err;}三个重要的参数:
handle是目标进程标识符
BC_TRANSACTION是与驱动通信的命令
data是需要传送的进程间通信数据
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer){ binder_transaction_data tr; tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */ tr.target.handle = handle; tr.code = code; tr.flags = binderFlags; tr.cookie = 0; tr.sender_pid = 0; tr.sender_euid = 0; const status_t err = data.errorCheck(); if (err == NO_ERROR) { tr.data_size = data.ipcDataSize(); tr.data.ptr.buffer = data.ipcData(); tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); tr.data.ptr.offsets = data.ipcObjects(); } else if (statusBuffer) { tr.flags |= TF_STATUS_CODE; *statusBuffer = err; tr.data_size = sizeof(status_t); tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer); tr.offsets_size = 0; tr.data.ptr.offsets = 0; } else { return (mLastError = err); } mOut.writeInt32(cmd); mOut.write(&tr, sizeof(tr)); return NO_ERROR;}将需要传送的数据转换为binder_transaction_data
先写命令,再写数据.
8. frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::write(const void* data, size_t len){ void* const d = writeInplace(len); if (d) { memcpy(d, data, len); return NO_ERROR; } return mError;}
在Parcel.cpp中,将通信命令和通信数据拷贝到了内核缓存区,也就是位于内核空间的内存区域.
9.frameworks/native/libs/binder/IPCThreadState.cpp
在将数据拷贝到内核缓存区后,调用waitForResponse方法等待结果
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){ uint32_t cmd; int32_t err; while (1) { if ((err=talkWithDriver()) < NO_ERROR) break; ...... switch (cmd) { case BR_TRANSACTION_COMPLETE: ...... case BR_DEAD_REPLY: ...... case BR_FAILED_REPLY: ...... case BR_ACQUIRE_RESULT: ...... case BR_REPLY: ...... default: err = executeCommand(cmd); if (err != NO_ERROR) goto finish; break; } }finish: ...... return err;}
该方法循环调用talkWithDriver()与驱动交互,talkWithDriver()有两个作用,第一个是告诉驱动有一个IPC请求,要求处理,第二是从驱动中读取返回数据,并根据不同的情况进行处理.
到此为止,上半段分析结束,及从应用进程到binder驱动的流程结束.下面进行下半段的分析,及由binder驱动到服务进程.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在第2步里面说过,BpBinder的mHandle可以指明目标进程.由于所有服务在启动的时候都将自己注册到了service manager里面,并且service manager在循环等待其他进程的通信请求.所以在应用进程将BC_TRANSACTION命令和通信数据data发送到binder驱动的时候,binder驱动就会根据mHandle找到目标进程AMS,并将BC_TRANSACTION命令和通信数据data分发给目标进程AMS,并调用AMS的binder本地对象JavaBBinder的onTranscat()方法.
10.frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder{public: JavaBBinder(JNIEnv* env, jobject object) : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)) ......... jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags); jthrowable excep = env->ExceptionOccurred(); .........private: JavaVM* const mVM; jobject const mObject;};JavaBBinder的成员变量mObject是一个Java服务,在此处就是AMS,从方法CallBooleanMethod(args...)可以看出调用了AMS的execTransact(args...)方法,而AMS本身并无此方法,所以是调用了AMS父类Binder的execTransact(args...)方法.
11.frameworks/base/core/java/android/os/Binder.java
// Entry point from android_util_Binder.cpp's onTransact private boolean execTransact(int code, long dataObj, long replyObj, int flags) { Parcel data = Parcel.obtain(dataObj); Parcel reply = Parcel.obtain(replyObj); // theoretically, we should call transact, which will call onTransact, // but all that does is rewind it, and we just got these from an IPC, // so we'll just call it directly. boolean res; // Log any exceptions as warnings, don't silently suppress them. // If the call was FLAG_ONEWAY then these exceptions disappear into the ether. try { res = onTransact(code, data, reply, flags); } catch (RemoteException e) { ........ } checkParcel(this, code, reply, "Unreasonably large binder reply buffer"); reply.recycle(); data.recycle(); return res; }首先将参数dataObj和replyobj由C++的Parcel转换为Java的Parcel.
然后调用ActivityManagerNative.java的onTransact(code, data, reply, flags)方法.
12.frameworks/base/core/java/android/app/ActivityManagerNative.java
@Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case START_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); String callingPackage = data.readString(); Intent intent = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); IBinder resultTo = data.readStrongBinder(); String resultWho = data.readString(); int requestCode = data.readInt(); int startFlags = data.readInt(); ProfilerInfo profilerInfo = data.readInt() != 0 ? ProfilerInfo.CREATOR.createFromParcel(data) : null; Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null; int result = startActivity(app, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options); reply.writeNoException(); reply.writeInt(result); return true; } ...... }
13. frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
最后调用AMS的startActivity()方法。先将通信数据data都读出来作为参数并传入AMS,在AMS里面执行完startActivity方法后将启动结果写入reply传回应用进程.
到此,一个startActivity的进程间通信请求就由应用进程发送到了系统进程中的AMS.
- android学习笔记--binder
- Android学习笔记--Binder
- Android学习笔记--Binder
- Android学习笔记--Binder
- Android 学习笔记 binder
- binder学习笔记
- Binder 驱动学习笔记
- Android学习笔记--Binder
- Binder学习笔记
- Android学习笔记--Binder
- Android学习笔记--Binder
- Android学习笔记--Binder
- Binder学习笔记
- Binder学习笔记
- binder学习笔记
- Android Binder学习笔记
- 学习Binder笔记
- Binder、AIDL学习笔记
- 源文件名长度大于文件系统支持的长度。请尝试将其移动到具有较短路径名称的位置,或者在执行此操作前尝试将其重命名为较短的名称--解决办法
- python中的字典
- iOS学习之路09
- 模拟退火学习笔记
- 《近匠》 | 探索一站式智能硬件开发的最佳解决方案
- binder学习笔记
- vue.js的学习
- addbinary
- 个人测试
- 3d全景图
- Unity —— 针对DynamicBone插件的迭代来实现布料模拟
- iOS学习之路10
- spring-session整合redis实现session共享
- 关于spring AOP 的初步学习