当前位置: 移动技术网 > 移动技术>移动开发>Android > Android Binder框架(Framework层获取Binder服务过程源码分析)

Android Binder框架(Framework层获取Binder服务过程源码分析)

2020年08月23日  | 移动技术网移动技术  | 我要评论
Android Binder框架实现之Framework层Binder服务获取过程源码分析前言

Android Binder框架实现之Framework层获取Binder服务过程源码分析

前言


  • 从整体高度出发了解了Android Framework层Binder的设计以及实现,并且概括总结了Android Framework层的BInder怎么和Native 层Binder贯通从而达到Android Binder框架整体实现的
  • 全方位分析了Android Framewrok层Binder服务注册过程

服务被注册了,当然是被用来使用的而不是被当作花瓶的,那么Android必然也提供了对应的方法在Framewrok层获取Binder服务,而今天的博客将会接着继续分析Framework层获取Binder服务过程。

  • 注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:
framework/base/core/java/android/os/
  ---IInterface.java
  ---IServiceManager.java
  ---ServiceManager.java
  ---ServiceManagerNative.java(内含ServiceManagerProxy类) framework/base/core/java/android/os/
  ---IBinder.java
  ---Binder.java(内含BinderProxy类) ---Parcel.java

framework/base/core/java/com/android/internal/os/
  ---BinderInternal.java

framework/base/core/jni/
  ---AndroidRuntime.cpp
  ---android_os_Parcel.cpp
  ---android_util_Binder.cpp
  
frameworks/native/libs/binder/BpBinder.cpp
frameworks/native/include/binder/IBinder.h
frameworks/native/libs/binder/Binder.cpp
frameworks/native/include/binder/Parcel.h
frameworks/native/libs/binder/Parcel.cpp
frameworks/base/core/jni/core_jni_helpers.h
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks//base/core/java/android/app/ActivityThread.java 
  • 为了后续的书写方便会将ActivityManagerService简述为AMS,ServiceManager简述为SM,ServiceManagerProxy简述为SMP,ServiceManagerNative简述为SMN,以上特此申明!并且在这里附上Android Binder的框架的整体设计图!
    在这里插入图片描述


一 Framework层获取Binder服务过程

在上一篇博客中我们以AMS为例讲述了怎么将其注册到servicemanager中,这里我们依然以它为例讲述怎么获取到它的代理端ActivityManager的,我们通常的获取手段如下:

 //ActivityManagerNative.java static public IActivityManager asInterface(IBinder obj) { if (obj == null) { return null; } IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor); if (in != null) { return in; } return new ActivityManagerProxy(obj); } private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { IBinder b = ServiceManager.getService("activity");//详见章节1.1 if (false) { Log.v("ActivityManager", "default service binder = " + b); } IActivityManager am = asInterface(b); if (false) { Log.v("ActivityManager", "default service = " + am); } return am; } }; } 

1.1 ServiceManager.getService

 //ServiceManager.java private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>(); public static IBinder getService(String name) { try { IBinder service = sCache.get(name);//从Hash表中查询是否有合适的,如果没有则向servicemanager服务大管家查询 if (service != null) { return service; } else { return getIServiceManager().getService(name); } } catch (RemoteException e) { Log.e(TAG, "error in getService", e); } return null; } 

这里可以看到设计了一个缓存机制,即每次获取服务前都会查找缓存HashMap<String, IBinder> sCache = new HashMap<String, IBinder>()中是否有合适的,我们这里是第一次查询ACTIVITY_SERVICE ,则缓存中肯定是不存在,于是通过getIServiceManager().getService(name)来向ServiceManager进程查询服务。但是小伙们是不是有个疑问,我咋没有看到将获取到的服务添加到sCache中去呢,是的我也带着这个疑问仔细查看了下源码,发现确实提供了一个方法可以将相关服务添加到该缓存中去(但是我咋没有看到调用该方法啊,我还是不死心),如下

 //ServiceManager.java public static void initServiceCache(Map<String, IBinder> cache) { if (sCache.size() != 0) { throw new IllegalStateException("setServiceCache may only be called once"); } sCache.putAll(cache); } 

但是我咋没有看到调用该方法啊,我还是不死心,终于在ActivityThread.java类中的bindApplication方法中有找到了(至于bindApplication方法吗我想对于Android 应用进程启动的小伙们来说应该都很熟悉,不是很了解的可以移步到Android 应用进程启动大揭秘中),如下:

 //ActivityThread.java public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) { if (services != null) { // Setup the service cache in the ServiceManager ServiceManager.initServiceCache(services); } ... } 

getIServiceManager()方法已经在Android Binder框架实现之Framework层Binder服务注册过程源码分析中进行了详细分析,该函数返回一个ServiceManagerProxy对象,因此调用ServiceManagerProxy对象的getService函数来完成服务查询。


1.2 ServiceManagerProxy.getService

 //ServiceManagerNative.java 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; } 

我们通过前面的博客Android Binder框架实现之Parcel详解一分析应该知道了Parcel是用来打包传递数据的一个载体,此时我们将相关要传递的数据打包到Parcel中后,其中存储内容如下:
在这里插入图片描述

通过前面的博客分析我们也知道了ServiceManagerProxy代理服务端变量mRmote指向BinderProxy(0),而BinderProxy(0)又将会指向BpBinder(0),其数据结构关系如下:
在这里插入图片描述
至于BpBinder怎么借助BInder驱动将请求查询服务发送请求发送到servicemanager进程中的这个我们就不分析了,该过程可以参见Android Binder框架实现之Native层getService的实现过程,这里我大概介绍下基本过程:

  • 客户端进程将要查询的服务名称(我们这里的是"acvity")发送给servicemanager进程
  • servicemanager进程根据服务名称在自身用户空间中的全局服务链表中查找对应的服务,并得到servicemanager进程引用该服务的句柄值
  • servicemanager进程将查询得到的句柄值发送给Binder驱动
  • Binder驱动根据句柄值在ServiceManager进程的binder_proc中查找Binder引用对象;
  • 如果服务查询进程不是注册该服务的进程,则在服务查询进程的binder_proc中根据Binder节点查找服务查询进程引用该Binder节点的Binder引用对象,反之,将该服务对应的Binder本地对象地址发送给服务查询进程;
  • 如果服务查询进程不是注册该服务的进程并且第一次查询该服务,Binder驱动会为服务查询进程创建引用该服务Binder节点的Binder引用对象,并将该引用对象句柄值返回到客户进程的用户空间中;
  • 客户进程得到本进程引用服务的Binder引用对象的句柄值后,创建服务代理对象

好吗,上面的总结我也不指望小伙们能一下子理解清楚(能理解捋顺的小伙伴也不会看这个博客了),小伙们在这里只需要有一个概念就是通过上面的mRemote.transact然后借助Binder驱动会从servicemanager查询的结果返回到客户端进程中的reply的Parcel容器数据里,然后该返回结果中存在一个句柄值可以通过Binder驱动调用到远端服务进程就OK了。


1.3 Parcel.readStrongBinder

 //Parcel.java private static native IBinder nativeReadStrongBinder(long nativePtr); public final IBinder readStrongBinder() { return nativeReadStrongBinder(mNativePtr);//详见章节1.4 } 

依然是老配方和老套路,通过JNI调用到Native层进行相关的处理。这里的readStrongBinder可以认为是前面注册服务中writeStrongBinder的逆向过程。

1.4 android_os_Parcel_readStrongBinder

//android_os_Parcel.cpp static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel != NULL) { //这里的javaObjectForIBinder是不是很熟悉,在注册服务中我们有讲述到主要是将BpBinder(C++)转换成Java层的BinderProxy //我们这里只重点关注parcel->readStrongBinder() return javaObjectForIBinder(env, parcel->readStrongBinder());//详见章节1.4.1 } return NULL; } 

此处android_os_Parcel_readStrongBinder函数的逻辑可以分为两层:

1.4.2 Parcel::readStrongBinder

status_t Parcel::readStrongBinder(sp<IBinder>* val) const { return unflatten_binder(ProcessState::self(), *this, val);//详见1.4.3 } sp<IBinder> Parcel::readStrongBinder() const { sp<IBinder> val; readStrongBinder(&val); return val; } 

前有注册服务时候的flatten_binder扁平化Binder对象,现有unflatten_binder反扁平化Binder对象,你们是全家桶是吗!前饼果子来一套,切克闹!

1.4.3 unflatten_binder

//Parcel.cpp status_t unflatten_binder(const sp<ProcessState>& proc, const Parcel& in, sp<IBinder>* out) { //flat_binder_object应该是熟悉面孔了吗,主要用来解析Parcel中的存储的Binder数据类型 const flat_binder_object* flat = in.readObject(false); if (flat) { switch (flat->type) { case BINDER_TYPE_BINDER: ... case BINDER_TYPE_HANDLE://会走该分支,因为我们是跨进程获取Binder服务的代理端 //该过程主要是通过获取远程服务端引用的句柄,创建BpBinder *out = proc->getStrongProxyForHandle(flat->handle);//详见章节1.4.4 return finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in); } } return BAD_TYPE; } 

这里的flat_binder_object结构体是我们的老熟人了,其被设计用来解析存储Parcel中的Bidner对象类型数据(即可以是Binder实体服务,也可以是Binder引用对象,男女通吃老少皆宜!)。然后我们知道此时从Binder驱动中读取回来的是远程Binder服务的Binder引用类型,所以会走BINDER_TYPE_HANDLE分支,该分支干的事情吗也不多,主要如下:

  • 通过Binder驱动返回的远程BInder的引用句柄handle创建一个BpBinder(handle)
  • 接着调用finish_unflatten_binder返回

1.4.4 unflatten_binder

//ProcessState.h struct handle_entry { IBinder* binder; RefBase::weakref_type* refs; }; Vector<handle_entry>mHandleToObject; //ProcessState.cpp ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle) { const size_t N=mHandleToObject.size(); 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); } sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) { sp<IBinder> result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle);//查询mHandleToObject列表中是否有该handle的记录,即该进程以前是否有获取过该服务 if (e != NULL) {//找到了 // We need to create a new BpBinder if there isn't currently one, OR we // are unable to acquire a weak reference on this current one.  See comment // in getWeakProxyForHandle() for more info about this. IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { if (handle == 0) {//这里的handle为0是专属席位,是给ServiceManagerProxy的,所以我们和此处无缘 Parcel data; status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, NULL, 0); if (status == DEAD_OBJECT) return NULL; } //根据handle创建BpBinder b = new BpBinder(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; } 

经过重重险阻,最终创建了指向AMS Binder服务端的BpBinder代理对象。而我们在章节1.4中说过javaObjectForIBinder将native层BpBinder对象转换为Java层BinderProxy对象。 这里我们通过ServiceManager.getService最终获取了指向目标Binder服务端的代理对象BinderProxy。但是我们知道BinderProxy是用来和Binder驱动进行通信的,那么怎么和服务端的业务逻辑牵涉起来呢,这个我们章节1.5再来分析。回到章节1.4.3还有最后一个小点finish_unflatten_binder看看它干了啥,其实没有干啥:

//Parcel.cpp inline static status_t finish_unflatten_binder( BpBinder* /*proxy*/, const flat_binder_object& /*flat*/, const Parcel& /*in*/) { return NO_ERROR; } 

本文地址:https://blog.csdn.net/tkwxty/article/details/108165937

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网