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

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


Android Binder框架实现目录:

Android Binder框架实现之Binder的设计思想
Android Binder框架实现之何为匿名/实名Binder
Android Binder框架实现之Binder中的数据结构
Android Binder框架实现之Binder相关的接口和类
Android Binder框架实现之Parcel详解之基本数据的读写
Android Binder框架实现之Parcel read/writeStrongBinder实现
Android Binder框架实现之servicemanager守护进程
Android Binder框架实现之defaultServiceManager()的实现
Android Binder框架实现之Native层addService详解之请求的发送
Android Binder框架实现之Native层addService详解之请求的处理
Android Binder框架实现之Native层addService详解之请求的反馈
Android Binder框架实现之Binder服务的消息循环
Android Binder框架实现之Native层getService详解之请求的发送
Android Binder框架实现之Native层getService详解之请求的处理
Android Binder框架实现之Native层getService详解之请求的反馈
Android Binder框架实现之Binder Native Service的Java调用流程
Android Binder框架实现之Java层Binder整体框架设计
Android Binder框架实现之Framework层Binder服务注册过程源码分析
Android Binder框架实现之Java层Binder服务跨进程调用源码分析
Android Binder框架实现之Java层获取Binder服务源码分析


前言

  继承上一篇博客Android Binder框架实现之Framework层Binder服务注册过程源码分析未完成的意愿我们接着继续分析,在上一篇博客中我们主要干了如下几件事情(当然前提是各位小伙伴有看前篇的博客):

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

服务被注册了,当然是被用来使用的而不是被当作花瓶的,那么Android必然也提供了对应的方法在在Java层获取Binder服务(可能是Framework层的也可能是Native层的),而今天的博客重点就是Java层怎么获取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,ActivityManagerProxy简称AMP, ActivityManagerNative简称AMN以上特此申明!并且在这里附上Android Binder的框架的整体设计图!
    在这里插入图片描述


一.Java层获取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);//详见章节1.6
            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_node)Binder引用对象(这个有点拗口啊),反之,将该服务对应的Binder本地对象地址发送给服务查询进程,即此处此时至少存在两个引用指向binder_node实体节点
  • 如果服务查询进程不是注册该服务的进程并且第一次查询该服务,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
    }

  在正式开始该流程分析前,我们先奉上readStrongBinder整体式时序图,既是为了对后续流程的一个概述,也是一个小结:

在这里插入图片描述

  依然是老配方和老套路,通过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.6再来分析。回到章节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;
}

1.5 ServiceManager.getService小结

  至此ServiceManager.getService(“activity”)就分析完毕了,通过前面我们深入源码级别的分析以及孜孜不倦的硬啃,让我们来人工翻译一下该段源码,最终得到如下终极结论,其最终等价于:

IBinder b = ServiceManager.getService("activity") = new BinderProxy(new BpBinder(handle));//这里的handle是贯穿始终的关键,其得来并不是凭空出现也不是杜撰出来的,而是通过SMP向Binder驱动查询而得来的,这个handle可以认为是客户端通向远程服务端的终极钥匙。

这里的handle是贯穿始终的关键,其得来并不是凭空出现也不是杜撰出来的,而是通过SMP向Binder驱动查询而得来的,这个handle可以认为是客户端通向远程服务端的终极钥匙。


1.6 ActivityManagerNative.asInterface

	//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() {
        	//等价于ServiceManager.getService("activity") = new BinderProxy(new BpBinder(handle));
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
}

  让我们继续回到章节一开篇获取AMS远程服务端代理AMP的源码,在我们通过ServiceManager.getService(“activity”)获取到BpBinder(handle)进而创建Java层BinderProxy(handle)后,接着调用asInterface方法,我们来看看该方法的实现,如下:

	//ActivityManagerNative.java
	//此时我们知道入参为BinderProxy
    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);
    }

通过前面我们的分析可知,此时的入参为IBinder子类BinderProxy,那么它的queryLocalInterface方法如何呢,我们来一探其神秘面纱(好吗,其实一点也不神秘,我们在Framework层Binder服务的注册源码过程分析中已经抽丝剥茧层层分析了),如下:

final class BinderProxy implements IBinder {
	public IInterface queryLocalInterface(String descriptor) {
        return null;
    }
}

此时的答案已经呼之欲出了,经过这么一番折腾以后我们终于获取到了AMS的服务端代理对象AMP,即最终获取了如下的逻辑代码:

new ActivityManagerProxy(new BinderProxy(new BpBinder(handle)))

1.7 AMP远程服务端代理获取流程小结

  至此我们终于获取到了AMS的远程代理端服务端对象AMP,此时AMP的的Binder层级关系和结构关系可以借助如下两个示意图表示:
在这里插入图片描述

在这里插入图片描述

获取到AMP以后,我们可以像操作本地类一样借助AMP来通过AMS完成相关的其对应的服务提供的相关功能,至于AMS具体提供了那些功能,这个就不是我们所关系的了。



二 .获取Framework层Binder服务源码总结


2.1 远程服务代理端获取后怎么组装的

  至此Framework层获取Binder服务过程源码分析就告一段落了,这里主要重点分析了应用层进程(即第三方应用)怎么借助SMP将服务查询数据组装然后通过Binder驱动发送到到servicemanager进程的,至于servicemanger进程怎么查询服务和将查询结果通过Binder驱动返回至的本篇章没有重点分析,这个过程详见Android Binder框架实现之Native层getService的实现。而我们这里只需要知道第三方进程查询远程服务在用户空间通过IBinder binder = reply.readStrongBinder()从而获得servicemanager进程查询到的远程服务端的代理对象端,而查询到的服务代理端handle句柄引用怎么一步步的组装成AMP,其中涉及的关键逻辑可以通过如下的处理逻辑图来表示:

在这里插入图片描述

  • 首先从servicemanager进程返回来的Parcel对象中取出flat_binder_object

  • 然后根据Binder引用对象的描述符句柄(即handle)创建BpBinder对象,在创建Java层负责通信的BinderProxy对象

  • 最后创建和业务相关的XXXProxy对象,这样就得到了所查询得到的服务的代理对象通过该代理对象就可以向该服务的本地对象发送RPC远程调用请求。


2.2 Android远程服务查询流程简单总结

  虽然我们本篇的重点没有放在此处,但是我们还是简单小结一下Android远程服务查询流程吗,这个只是一个整体概括,其中牵涉的细节就多了去了,不是三言两句就能OK的。其核心步骤如下(这里省去了怎么获取servicemanager进程代理端的流程,即获取SMP):

  • 客户端进程将要查询的服务名称(我们这里的是"acvity"发送给servicemanager进程
  • servicemanager进程根据服务名称在自身用户空间中的全局服务链表中查找对应的服务,并得到servicemanager进程引用该服务的句柄值
  • servicemanager进程将查询得到的句柄值发送给Binder驱动
  • Binder驱动根据句柄值在ServiceManager进程的binder_proc中查找该Binder引用对象
  • 如果服务查询进程不是注册该服务的进程,则在服务查询进程的binder_proc中创建根据前面步骤查询到的Binder引用对象指向的Binder实体节点(binder_node)Binder引用对象(这个有点拗口啊),反之,将该服务对应的Binder本地对象地址发送给服务查询进程,即此处此时至少存在两个引用指向binder_node实体节点
  • 如果服务查询进程不是注册该服务的进程并且第一次查询该服务,Binder驱动会为服务查询进程创建引用该服务Binder节点的Binder引用对象,并将该引用对象句柄值返回到客户进程的用户空间中
  • 客户进程得到本进程引用服务的Binder引用对象的句柄值后,创建服务代理对象

其查询请求过程可以使用如下伪代码来表示:

  • 注册的服务的进程和查询服务的进程不相同,其查询逻辑伪代码如下:
SMP(name)---> 
	Binder驱动--->
		servicemanager(handle)--->
			Binder驱动--->servicemanger(binder_ref)--->binder_node--->client(binder_ref)--->client(handle)
  • 注册的服务的进程和查询服务的进程相同,其查询逻辑伪代码如下:
SMP(name)---> 
	Binder驱动--->
		servicemanager(handle)--->
			Binder驱动--->servicemanger(binder_ref)--->binder_node--->JavaBBinder

到这里真的要over了,最后奉上servicemanager进程、服务注册进程(system_server)、服务查询进程之间的关系如图如下:

在这里插入图片描述



写在最后

  Java层获取Binder服务源码分析基本就告一段落了,虽然源码分析over了!但是我相信基本没有小伙伴可以一口气可以看完,并且各位小伙伴们也不要指望能一下子理解清楚,这个过程中一定会有迷惘失落,有高兴也会有高兴。不要问我怎么知道的,因为我也是这么过来的。好了就到这里了,欢迎小伙伴们评论和点赞。最后我还想补充一句就是,对于Binder这仅是一个开端,希望各位小伙伴真的能领略到Binder的美!在本篇博客我们获取到了Java层Binder服务端的代理对象,那么我们在接下来的篇章中将要介绍怎么通过代理端IXXXServiceProxy来跨进程调用远端Java层Binder服务,详见博客Android Binder框架实现之Java层Binder服务跨进程调用源码分析的分析。

猜你喜欢

转载自blog.csdn.net/tkwxty/article/details/108165937