Android Framework:Binder全解析(二)这篇
作者
前言
在上一篇中我们分别从Native层到内核层讲解了系统服务是如何注册,那这篇从Java层开始讲,系统服务是如何获取的。
Java层
小伙伴想想我们平常接触系统服务最多的时候是什么时候?
是不是就是获取系统服务呢?没错,那我们就从获取系统服务开始。
首先以我们最基础的使用方式getSystemService()
这个方法开始
getSystemService()
var manager=getSystemService(Service.AUDIO_SERVICE) as AudioManager
一般情况下我们是这样使用的。但是这个AudioManager
到底是如何实现的呢?
其实它也是通过获取Service来实现的。我们来看看它的方法
AudioManager.getService
//android.media.AudioManager.java
private static IAudioService getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
sService = IAudioService.Stub.asInterface(b);
return sService;
}
AudioManager
是通过AIDL的方式获取的真正的系统服务。
大家要注意这里的ServiceManager
和上一篇中native层的ServiceManager
是不一样的,这个是Java层的。我们来看一下这个Java层ServiceManager
是如何做的。
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<IBinder> 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);
}
采用了单例模式获取ServiceManager
,asInterface()
返回的是ServiceManagerProxy
(简称SMP)对象。所以最后getIServiceManager()
方法等价于new ServiceManagerProxy(new BinderProxy())
既然getIServiceManager()
获取到的是ServiceManagerProxy
,那ServiceManager.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;
}
}
mRemote
为BinderProxy
对象,该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,最终会将命令和数据插入到ServiceManager
的todo队列中。 这个的叙述可以参考上一篇的内容。
那么接下来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 = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
Parcel::readStrongBinder
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
readStrongBinder()
会调用unflatten_binder()
来解析Parcel中的数据。
Parcel.unflatten_binder
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->type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
//进入该分支
*out = proc->getStrongProxyForHandle(flat->handle);
//创建BpBinder对象
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
ProcessState.getStrongProxyForHandle
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//查找handle对应的资源项
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
...
//当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
经过该方法,最终创建了指向Binder服务端的BpBinder
代理对象。经过javaObjectForIBinder
方法将native层BpBinder对象转换为Java层BinderProxy
对象。 也就是说通过getService()最终获取了指向目标Binder服务端的代理对象BinderProxy。
小结
getService的核心过程:
public static IBinder getService(String name) {
...
Parcel reply = Parcel.obtain(); //此处还需要将java层的Parcel转为Native层的Parcel
BpBinder::transact(GET_SERVICE_TRANSACTION, *data, reply, 0); //与Binder驱动交互
IBinder binder = javaObjectForIBinder(env, new BpBinder(handle));
...
}
javaObjectForIBinder
作用是创建BinderProxy
对象,并将BpBinder
对象的地址保存到BinderProxy
对象的mObjects
中。 获取服务过程就是通过BpBinder来发送GET_SERVICE_TRANSACTION
命令,与实现与binder驱动进行数据交互。
请求服务getService()
过程,就是向servicemanager
进程查询指定服务,当执行binder_transaction
()时,会区分请求服务所属进程情况。
- 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建
binder_ref
对象,指向服务进程中的binder_node
;即创建了一个针对于请求服务进程的一个手机号,然后请求进程就可以通过得到一个小弟(BpBinder),让小弟记住这个手机号,就可以找到对应的服务人员(BBinder),然后就可以让服务人员办事了。- 最终
readStrongBinder
(),返回的是BpBinder对象;
- 最终
- 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
- 最终
readStrongBinder
(),返回的是BBinder对象的真实子类;
- 最终
一张图来总结一下:
喜欢的话留个赞再走呗,有任何技术问题都可以评论区留言,都会回复的哦~
Android 开发相关源码精编解析
随着Android开发行业逐渐饱和,对Android开发者的面试要求也越来越高,是否掌握底层源码,便是考验一名Android开发者的重要一环。面试被问到源码问题答不出来,会掉身价、砍薪资尚且不谈,甚至连面试都过不了!
网上各类源码解析的文章博客五花八门、良莠不齐。杂乱、要么内容质量太浅,零散、碎片化,总看着看着就衔接不上了。
所以特意将我在疫情期间花了4个月整理出来的《Android 开发相关源码精编解析》分享出来大家
由于内容较多,避免影响到大家的阅读体验,在此只截图展示目录部分,487详细完整版的《Android 开发相关源码精编解析》电子书文档可以在我的GitHub获取百度网盘下载地址。。也欢迎大家找我探讨Android技术问题~
目录:一共18节,487页PDF,包括MMKV 源码,ARouter 源码,AsyncTask 源码,Volley 源码,Retrofit 源码,OkHttp 源码,ButterKnife 源码,Okio 源码,SharedPreferences 源码,EventBus 源码,Android 自定义注解初探,View 的工作机制源码分析,Android 触摸事件分发机制源码分析,Android 按键事件分发机制源码分析,深入解析 Handler 源码,深入解析 Binder 源码,深入解析 JNI 源码,深入解析 Glide 源码。
《Android 开发相关源码精编解析》电子书文档可以在我的GitHub获取百度网盘免费下载地址。