Android-Framework:Binder全解析(二,进阶学习

ServiceManager.getService

//frameworks/base/core/java/android/os/ServiceManager.java
public static IBinder getService(String name) {
try {
//先从缓存中查看
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, “error in getService”, e);
}
return null;
}

可以看到首先从缓存中去取,如果没有的话就去创建一个,请求获取服务过程中,如果缓存中不存在的话,再通过binder交互来查询相应的服务。创建的方法是rawGetService方法。

rawGetService

//frameworks/base/core/java/android/os/ServiceManager.java
//省略部分代码
private static IBinder rawGetService(String name) throws RemoteException {

final IBinder binder = getIServiceManager().getService(name);
/*
*
*/
return binder;
}

getIServiceManager()

//frameworks/base/core/java/android/os/ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}

是通过ServiceManagerNative.asInterface()方法来获取ServiceManager对象,asInterface方法的参数中是调用了BinderInternal.getContextObject()方法。这是一个native方法。

getContextObject()

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}

由于本小节是讲解Java的,这里就不做过多的讲解了。对于ProcessState::self()->getContextObject()这个方法,等价于new BpBinder(0)。即BinderInternal.getContextObject()方法最后是获取BpBinder对象。

那么回过头来看asInterface方法的具体实现:

ServiceManagerNative.asInterface

//frameworks/base/core/java/android/os/ServiceManagerNative.java
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}

return new ServiceManagerProxy(obj);
}

采用了单例模式获取ServiceManagerasInterface()返回的是ServiceManagerProxy(简称SMP)对象。所以最后getIServiceManager() 方法等价于new ServiceManagerProxy(new BinderProxy())

既然getIServiceManager()获取到的是ServiceManagerProxyServiceManager.getService(name)方法就是调用的ServiceManagerProxy.getService(name)的方法。我们先看一下ServiceManagerProxy是怎么被初始化的:

ServiceManagerProxy初始化

//frameworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
}

mRemoteBinderProxy对象,该BinderProxy对象对应于BpBinder(0),其作为binder代理端,指向native层大管家service Manager。还记得BpBinder对象吗?在上一节,我们讲到了这个BpBinder对象于BBinder对象是一对一的,客户端拿着BpBinder去找BBinder,然后服务端的BBinder去做真正的事情。

emmm

好像有点懵逼了

没关系,我们捋一捋

在Java层,我们首先通过Native方法获得BpBinder对象。BpBinder对象中的handler为0的的时候,就指向的是ServiceManager了。

接下来构造一个ServiceManagerProxy,ServiceManagerProxy持有BpBinder。内部的工作也全部都是BpBinder去做的。

简单说就是获取ServiceManager,相当于你找人办事,但是人家架子很大不会自己来,先派给你一个小弟(ServiceManagerProxy),你想做什么就吩咐小弟,小弟手里拿着手机(BpBinder),你吩咐小弟任务以后,小弟通过手机拨打对应号码(BBinder)告诉办事的人。

ServiceManagerProxy.getService(name)

//frameworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
//mRemote为BinderProxy
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
//从reply里面解析出获取的IBinder对象
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
}

由上可知,framework层的ServiceManager的调用实际的工作确实交给SMP的成员变量BinderProxy;而BinderProxy通过jni方式,最终会调用BpBinder对象;可见上层binder架构的核心功能依赖native架构的服务来完成的。mRemote.transact这行代码将调用BinderProxy.transact方法,最终获得到的数据将会被赋值到reply对象中。

BinderProxy.transact

//frameworks/base/core/java/android/os/Binder.java
final class BinderProxy implements IBinder {
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);
}
}

最终BinderProxy.transact方法调用了Native方法,从这里开始进入了Native层。Java层的工作到这里就结束了。

Native层

android_os_BinderProxy_transact

//frameworks/base/core/jni/android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{

//java Parcel转为native Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);

//gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);

//此处便是BpBinder::transact(), 经过native层
status_t err = target->transact(code, *data, reply, flags);

return JNI_FALSE;
}

最终调用BpBinder.transact的方法来进行

BpBinder.transact

//frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
//
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}

如果看过我上一篇文章的话,看到这里已经会发现一个很熟悉的身影。没错就是IPCThreadState。在上一篇文章中,也出现了这个IPCThreadState。这也是个单例模式,每个线程只有一个哦。

到这里接下来的事情基本上和上一篇中的如出一辙,我这里大概过一下把~

IPC.transact

status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); //数据错误检查
flags |= TF_ACCEPT_FDS;

if (err == NO_ERROR) {
// 传输数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}

if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}

// 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
//reply对象不为空
err = waitForResponse(reply);
}else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}

transact主要过程:

  • 先执行writeTransactionData()Parcel数据类型的mOut写入数据,此时mIn还没有数据;
  • 然后执行waitForResponse()方法,循环执行,直到收到应答消息. 在waitForResponse()方法中会调用talkWithDriver()跟驱动交互,收到应答消息,便会写入mIn, 则根据收到的不同响应吗,执行相应的操作。

上一篇文章中也将到过,这里再说一次~

  • mIn 用来接收来自Binder设备的数据,默认大小为256字节;
  • mOut用来存储发往Binder设备的数据,默认大小为256字节。

IPC.talkWithDriver

//frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel reply, status_t acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
//此处是真正的与内核交互的方法
if ((err=talkWithDriver()) < NO_ERROR) break;

cmd = mIn.readInt32();
switch (cmd) {
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
//当reply对象回收时,则会调用freeBuffer来回收内存
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t
>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t
>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {

}
}
}
case :…
}
}

return err;
}

status_t IPCThreadState::talkWithDriver(bool doReceive)
{

//和Binder驱动通信的结构体
binder_write_read bwr;
//mIn是否有可读的数据,接收的数据存储在mIn
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

bwr.write_size = outAvail;
//将要发送给Binder设备的消息填充到与Binder通信的结构体中
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 Driver进行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;

} while (err == -EINTR); //当被中断,则继续执行

return err;
}

接下来会通过ioctl方法于Binder驱动进行交互,这个交互的调用链是如下

进入驱动。binder_ioctl -> binder_ioctl_write_read -> binder_thread_write,最终会将命令和数据插入到ServiceManagertodo队列中。 这个的叙述可以参考上一篇的内容。

那么接下来ServiceManager在不断地从队列中取事务并处理,当service manager进程收到该命令后,会执行do_find_service() 查询服务所对应的handle,然后再binder_send_reply()应答 发起者,发送BC_REPLY协议,然后调用binder_transaction(),再向服务请求者的Todo队列 插入事务。接下来,请求服务的进程在执行talkWithDriver的过程执行到binder_thread_read(),处理Todo队列的事务.(这部分不明白的小伙伴一定要看我上一篇文章)。

waitForResponse方法中,收到消息以后这个reply就不为空,此时会进入reply的ipcSetDataReference方法中,由于这个reply是Parcel对象,其实就是调用了Parcel的ipcSetDataReference方法将ServiceManager返回过来的数据设置到parcel对象中。waitForResponse()执行完BR_REPLY之后,便返回到IPCThreadState::transact()中;然后层层返回,直到退回到Java层的ServiceManagerProxy.getService方法,然后调用reply的readStrongBinder方法,最终调用的Native的方法nativeReadStrongBinder()方法。

nativeReadStrongBinder

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr) {
Parcel* parcel = reinterpre

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

t_cast<Parcel*>(nativePtr);
if (parcel != NULL) {

return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}

Parcel::readStrongBinder

上一篇:使用Parcel打包TS代码,这可能是学习TS阶段最简单的打包工具


下一篇:parcel打包出现No entries found.报错