持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情
前言
上一篇文章我们从binder驱动层知道了启动binder后是如何监听数据读写的,那么当客户端需要向binder层请求远端服务层对象,并且涉及到数据传输时,客户端又是如何发起请求并且进行数据写入和监听数据输出的呢?
今天这篇文章我们就来看看客户端发送Binder请求后到底发生了什么?
一、ServiceManager
1、getIServiceManager
客户端首先肯定要获取到这个服务端对象or代理,提供这个serice的方法在ServiceManger的代码里
frameworks/base/core/java/android/os/ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
2、BinderInternal.getContextObject()
BinderInternal.getContextObject()是一个native函数
/frameworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
可以看到这里返回了一个ProcessState类对象
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState("/dev/binder");
return gProcess;
}
3、ProcessState
ProcessState::ProcessState(const char *driver)
: mDriverName(String8(driver))
//打开binder驱动
, mDriverFD(open_driver(driver))
, mVMStart(MAP_FAILED)
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
if (mDriverFD >= 0) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
可以看到这里调用了open_driver函数打开了binder驱动
static int open_driver(const char *driver)
{
//打开binder驱动
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
//验证binder版本
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
...
}
... 设置binder最大线程数
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
...
return fd;
}
可以看到这里主要的三部曲分别是:打开binder驱动,验证binder版本,设置binder最大线程数,后续的步骤在咱们的binder层已经进行了分析,主要是调用mmap进行了内存映射.
我们看下binder已经准备好后后续又做了哪些工作.
4、getContextObject
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
可以看到,这里传入的入参是0
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//查找或建立handle对应的handle_entry
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
//当handle为ServiceManager的特殊情况
//需要确保在创建binder引用之前,context manager已经被binder注册
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//创建BpBinder并保存下来以便后面再次查找
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
5、lookupHandleLocked
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
//新建一个handle_entry并插入到vector中
if (N <= (size_t)handle) {
handle_entry e;
e.binder = NULL;
e.refs = NULL;
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return NULL;
}
return &mHandleToObject.editItemAt(handle);
}
可以看到,这里获得了一个BpBinder对象,由于它还是native的对象,需要将它转换成java类型,
6、javaObjectForIBinder
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
//JavaBBinder返回true,其他类型发挥false
if (val->checkSubclass(&gBinderOffsets)) {
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
jobject object = static_cast<JavaBBinder*>(val.get())->object();
LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
// For the rest of the function we will hold this lock, to serialize
// looking/creation/destruction of Java proxies for native Binder proxies.
AutoMutex _l(gProxyLock);
BinderProxyNativeData* nativeData = gNativeDataCache;
if (nativeData == nullptr) {
nativeData = new BinderProxyNativeData();
}
// gNativeDataCache is now logically empty.
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
if (env->ExceptionCheck()) {
// In the exception case, getInstance still took ownership of nativeData.
gNativeDataCache = nullptr;
return NULL;
}
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
//如果object是刚刚新建出来的BinderProxy
if (actualNativeData == nativeData) {
//处理proxy计数
} else {
// nativeData wasn't used. Reuse it the next time.
gNativeDataCache = nativeData;
}
return object;
}
首先会有一个IBinder类型的判断,只有当IBinder的的实际类型为JavaBBinder的时候会返回true,其他子类均返回false.
可以看到,JavaBBinder类继承自BBinder,里面保存了对java层Binder对象的引用,所以直接走后面的if.返回里面的object.
native层的javaBBinder与java层的Binder是对应关系
接着实例化一个BinderProxyNativeData,接着调用gBinderProxyOffsets.mGetInstance
这里的gBinderProxyOffsets 对应的数据类型其实是BinderProxy
7、getInstance
private static BinderProxy getInstance(long nativeData, long iBinder) {
BinderProxy result;
try {
result = sProxyMap.get(iBinder);
if (result != null) {
return result;
}
result = new BinderProxy(nativeData);
} catch (Throwable e) {
// We're throwing an exception (probably OOME); don't drop nativeData.
NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer,
nativeData);
throw e;
}
NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData);
// The registry now owns nativeData, even if registration threw an exception.
sProxyMap.set(iBinder, result);
return result;
}
可以看到,这里是以iBinder作为key尝试从sProxyMap取出BinderProxy,如果取到值了就直接将它返回出去,如果没取到,用之前传进来的BinderProxyNativeData指针为参数实例化一个BinderProxy,并将其设置到sProxyMap中。
从这里可以看出每一个BinderProxy都是以单例的形式存在的,并且native层的BinderProxyNativeData与Java层的BinderProxy是一一对应的关系.
getInstance方法执行完毕后,接下来会判断BinderProxy是不是新建出来的,如果是新建出来的需要处理一下proxy计数.
8、getIServiceManager
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
此时再回到这个方法,我们知道BinderInternal.getContextObject()方法返回的值对应的类型是BinderProxy代理类,接着调用Binder.allowBlocking方法,这个方法只是改变了BinderProxy中的一个参数,允许其阻塞调用.
接着asInterface方法实例化了一个ServiceManagerProxy对象
二、ServiceManagerProxy
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;
}
...
可以看到ServiceManagerProxy实现了ISerivceManager接口,ISerivceManager暴露了若干实现方法,例如getService,addService等等.
1、AIDL
AIDL生成的代码对于Binder进行了进一步封装,<接口>.Stub
对应服务端Binder,<接口>.Stub.Proxy
标识客户端,内部持有一个mRemote实例(BinderProxy),aidl根据定义的接口方法生成若干个TRANSACTION_<函数名>
code常量,两端Binder通过这些code标识解析参数,调用相应接口方法。
换言之AIDL就是对BinderProxy.transact
和Binder.onTransact
进行了封装,使用者不必再自己定义每次通讯的code以及参数解析。
2、BinderProxy.transact
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
///检查Parcel大小
1108 Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
1109
1110 if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
1111 // For now, avoid spamming the log by disabling after we've logged
1112 // about this interface at least once
1113 mWarnOnBlocking = false;
1114 Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
1115 new Throwable());
1116 }
1117
1118 final boolean tracingEnabled = Binder.isTracingEnabled();
1119 if (tracingEnabled) {
1120 final Throwable tr = new Throwable();
1121 Binder.getTransactionTracker().addTrace(tr);
1122 StackTraceElement stackTraceElement = tr.getStackTrace()[1];
1123 Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
1124 stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
1125 }
1126 try {
1127 return transactNative(code, data, reply, flags);
1128 } finally {
1129 if (tracingEnabled) {
1130 Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
1131 }
1132 }
1133 }
static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
688 if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
689 // Trying to send > 800k, this is way too much
690 StringBuilder sb = new StringBuilder();
691 sb.append(msg);
692 sb.append(": on ");
693 sb.append(obj);
694 sb.append(" calling ");
695 sb.append(code);
696 sb.append(" size ");
697 sb.append(parcel.dataSize());
698 sb.append(" (data: ");
699 parcel.setDataPosition(0);
700 sb.append(parcel.readInt());
701 sb.append(", ");
702 sb.append(parcel.readInt());
703 sb.append(", ");
704 sb.append(parcel.readInt());
705 sb.append(")");
706 Slog.wtfStack(TAG, sb.toString());
707 }
708 }
可以看到这里我们的Parcel限制了数据传输的大小为800k,这也是我们序列化传输数据有限制的原因.
3、transactNative
这是一个native方法
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
// throws RemoteException
{
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
return JNI_FALSE;
}
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
IBinder* target = getBPNativeData(env, obj)->mObject.get();
if (target == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
return JNI_FALSE;
}
//log
...
status_t err = target->transact(code, *data, reply, flags);
//log
...
if (err == NO_ERROR) {
return JNI_TRUE;
} else if (err == UNKNOWN_TRANSACTION) {
return JNI_FALSE;
}
signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
return JNI_FALSE;
}
这里首先是获得native层对应的Parcel并执行判断,Parcel实际上功能是在native中实现的,java中的Parcel类使用mNativePtr成员变量保存了其对应native中的Parcel的指针
然后调用getBPNativeData函数获得BinderProxy在native中对应的BinderProxyNativeData,再通过里面的mObject域成员变量得到其对应的BpBinder,这个函数在之前分析javaObjectForIBinder的时候已经出现过了
4、BpBinder.transact
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.
//判断binder服务是否存活
if (mAlive) {
...
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
这里有一个Alive
判断,可以避免对一个已经死亡的binder
服务再发起事务,浪费资源,除此之外便是调用IPCThreadState
的transact
函数了
三、IPCThreadState
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, c
onst Parcel& data,Parcel* reply, uint32_t flags)
{
...
// 传输数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
if ((flags & TF_ONE_WAY) == 0) {
...
if (reply) {
// 等待远程数据的返回
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(nullptr, nullptr);
}
return err;
}
这里主要做的就两件事
-
- 通过
writeTransactionData
将数据写入到Parcel
中,对应的cmd
命令为BC_TRANSACTION
,这是请求码,对应的都是以BC_
开头命名,在service
端会通过这些请求码做不同的逻辑处理。
- 通过
-
- 通过
waitForResponse
来等待远端的数据返回,这里也有一个cmd
命令行,例如BR_REPLY
,这是返回码,对应的都是以BR_
开头命名的,在client
也会通过这些返回码做不同的逻辑处理
- 通过
总结
我们已经知道了Client
端主要通过BpBinder
的transact
方法与service
端进行通信,在BpBinder
的transact
方法中又通过IPCThreadState
的transact
方法将数据传递到service
端。
最终通过IPCThreadState
的writeTransactionData
方法 进行数据的读写,下一篇接着分析服务端收到客户端的请求后如何处理~