从app bindService分析binder客户端

2023-12-15 03:44

本文主要是介绍从app bindService分析binder客户端,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从 bindService() 分析 Binder 客户端

大家都知道的是 Binder 采用的是 C/S 架构思想,由 Client 端发起调用请求,由 Server 执行请求并返回结果(没有结果)。

写 App 程序进行 IPC 调用时,需要在调用端中 bindService 获取服务端的 Binder 接口对象,再调用方法。这篇文章尝试通过 bindService 方法的核心调用过程,分析Binder客户端的流程。

bindService()

我们在 Activity 中写到的 bindService(Intent service, ServiceConnection conn, BindServiceFlags flags) 调用到的是 ContextWrapper 中的方法。

// frameworks/base/core/java/android/content/ContextWrapper.java@UnsupportedAppUsage
Context mBase;@Override
public boolean bindService(@NonNull Intent service, @NonNull ServiceConnection conn,@NonNull BindServiceFlags flags) {return mBase.bindService(service, conn, flags);
}

ContextWrapper.bindService 调用到了 mBase.bindService(service, conn, flags),最终会调用到 ContextImpl.bindService() 方法。

@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {warnIfCallingFromSystemProcess();return bindServiceCommon(service, conn, Integer.toUnsignedLong(flags), null,mMainThread.getHandler(), null, getUser());
}private boolean bindServiceCommon(Intent service, ServiceConnection conn, long flags,String instanceName, Handler handler, Executor executor, UserHandle user) {IServiceConnection sd;// ......try {IBinder token = getActivityToken();// ......service.prepareToLeaveProcess(this);  // 同一进程内,内部的比较 leavingPackage=false// 下面是执行的 bindService 过程中的一个关键方法调用int res = ActivityManager.getService().bindServiceInstance(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),sd, flags, instanceName, getOpPackageName(), user.getIdentifier());// ......return res != 0;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}
}

获取 AMS binder对象

主要关注主要流程的实现,因此移除一些代码,全部的代码放开很占篇幅。很多更深层源码的理解,涉及到更深的知识,也有超出我理解的范围的地方,请不吝赐教。

bindServiceCommon() 方法中,主要流程调用到了

int res = ActivityManager.getService().bindServiceInstance(mMainThread.getApplicationThread(), getActivityToken(), service,service.resolveTypeIfNeeded(getContentResolver()),sd, flags, instanceName, getOpPackageName(), user.getIdentifier());

这条语句中,先通过 ActivityManager.getService() 获取到 ActivityManagerServiceBinder 对象。

// frameworks/base/core/java/android/app/ActivityManager.java@UnsupportedAppUsage
public static IActivityManager getService() {return IActivityManagerSingleton.get();
}// 定义 singleton 对象。
@UnsupportedAppUsage
private static final Singleton<IActivityManager> IActivityManagerSingleton =new Singleton<IActivityManager>() {@Overrideprotected IActivityManager create() {// 从  ServiceManager 中获取 AMS 的 binder 对象final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);final IActivityManager am = IActivityManager.Stub.asInterface(b);return am;}};

基于当前分析的流程,getService(String name) 的参数值是 Context.ACTIVITY_SERVICE

// frameworks/base/core/java/android/os/ServiceManager.java@UnsupportedAppUsage
private static IServiceManager sServiceManager;// IServiceManager 这是接口类型,对应的是 IServiceManager.aidl 文件编译后得到的java类型。
@UnsupportedAppUsage
private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));return sServiceManager;
}// 执行的逻辑比较简单,在缓存列表中查找 name 对应的 Binder 对象,
@UnsupportedAppUsage
public static IBinder getService(String name) { // 此时这里的值是 Context.ACTIVITY_SERVICEtry {IBinder service = sCache.get(name);if (service != null) {return service;} else {return Binder.allowBlocking(rawGetService(name));  // 这是获取 Binder 对象的关键。}} catch (RemoteException e) {Log.e(TAG, "error in getService", e);}return null;
}private static IBinder rawGetService(String name) throws RemoteException {final long start = sStatLogger.getTime();final IBinder binder = getIServiceManager().getService(name);final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start);final int myUid = Process.myUid();final boolean isCore = UserHandle.isCore(myUid);// ......  后续的代码中,并没有对 binder 对象作出关键的修改。return binder;
}

getService() 调用到 Binder.allowBloking()

// frameworks/base/core/java/android/os/Binder.java// 方法的返回还是传入的 binder
public static IBinder allowBlocking(IBinder binder) {try {if (binder instanceof BinderProxy) {((BinderProxy) binder).mWarnOnBlocking = false;} else if (binder != null && binder.getInterfaceDescriptor() != null&& binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {Log.w(TAG, "Unable to allow blocking on interface " + binder);}} catch (RemoteException ignored) {}return binder;
}

allowBlocking 方法中,没有处理具体的修改,针对传入的 binder 也没有作出影响执行流程的修改。因此,回到 ServiceManager.getService() 方法中,关键的执行流程在 rawGetService(name) 方法中。

ServiceManager.rawGetService(String name) 方法中,关键在

final IBinder binder = getIServiceManager().getService(name); // 这个 binder 对象值最终方法返回的对象。

getIServiceManager() 返回的是 IServiceManager 类型,对应的是 IServiceManager.aidl 文件编译后得到的java接口类型。在它的实现中,调用 ServiceManagerNative.asInterface() 方法。

// frameworks/base/core/java/android/os/ServiceManagerNative.javapublic final class ServiceManagerNative {private ServiceManagerNative() {}// 参数 obj 将是获取到的服务端的 Binder 对象,整个设计是 代理模式 。@UnsupportedAppUsagepublic static IServiceManager asInterface(IBinder obj) {if (obj == null) {return null;}// ServiceManager is never localreturn new ServiceManagerProxy(obj);}
} 

ServiceManagerNative 的方法中返回的是带有 Binder 对象的 ServiceManagerProxy 代理类。

紧接着:要知道 ServiceManagerNative.asInterface(IBinder) 是从怎么获取到的?

从方法调用上,返回到 ServiceManager.getIServiceManager() 方法中,之前分析到 Binder.allowBlocking(IBinder) 方法内并没有对参数作出关键的修改,因此 Binder 需要从BinderInternal.getContextObject() 的调用中获取。

// frameworks/base/core/java/com/android/internal/os/BinderInternal.java@UnsupportedAppUsage
public static final native IBinder getContextObject();

从上面这个方法定义可知,这是一个 JNI 调用,需要知道 getContextObject() 方法对应的 C/C++ 层的具体实现函数。

要在 Android 系统中找 JNI 接口定义的注册位置, jni 接口是属于java虚拟机的一部分,因此大概的位置应该要在 VM 相关的代码中查找,就查找到 AndroidRuntime.cpp 看看是不是会有与 Binder 注册有关的函数。

static const RegJNIRec gRegJNI[] = {// ....
}

可以看到这个数组的声明,在这里可以看到很多 register_* 的函数注册,可以搜索到 register_android_os_Binder 的注册,进而查找到文件 android_util_Binder.cpp 文件,对应的 register_android_os_Binder 函数定义也有。

另一个查找方式就是全局搜索文件内容 getContextObject,再过滤信息找到 JNI 定义位置。

在查找到 Binder 相关注册函数在文件 android_util_Binder.cpp 文件。

// frameworks/base/core/jni/android_util_Binder.cppint register_android_os_Binder(JNIEnv* env)
{if (int_register_android_os_Binder(env) < 0)return -1;if (int_register_android_os_BinderInternal(env) < 0)  // 看到 BinderInternal 类的注册函数return -1;if (int_register_android_os_BinderProxy(env) < 0)return -1;// ......return 0;
}const char* const kBinderProxyPathName = "android/os/BinderProxy";static int int_register_android_os_BinderProxy(JNIEnv* env)
{// ...... 加载 Java 层的异常类。// JNI调用,找到 Java 层类 android.os.BinderProxy,得到 jclass 对象。jclass clazz = FindClassOrDie(env, kBinderProxyPathName);gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);gBinderProxyOffsets.mGetInstance = GetStaticMethodIDOrDie(env, clazz, "getInstance","(JJ)Landroid/os/BinderProxy;");gBinderProxyOffsets.mSendDeathNotice =GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice","(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");clazz = FindClassOrDie(env, "java/lang/Class");gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;");return RegisterMethodsOrDie(env, kBinderProxyPathName,gBinderProxyMethods, NELEM(gBinderProxyMethods));
}static const JNINativeMethod gBinderInternalMethods[] = { // BinderInternal 方法对应关系/* name, signature, funcPtr */{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },// ...... 其他要注册的函数
};// BidnerInternal java类的包限定名的目录形式
const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";static int int_register_android_os_BinderInternal(JNIEnv* env)
{jclass clazz = FindClassOrDie(env, kBinderInternalPathName); // 找到java类// ......BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);return RegisterMethodsOrDie(env, kBinderInternalPathName,gBinderInternalMethods, NELEM(gBinderInternalMethods));
}

在函数 int_register_android_os_BinderInternal() 中进行了函数的注册,在函数数组 gBinderInternalMethods[] 的第一个看到了要查找的目标 getContextObject ,对应的函数是 android_os_BinderInternal_getContextObject (实现在 android_util.Binder.cpp 文件)。

// frameworks/base/core/jni/android_util_Binder.cppstatic jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{sp<IBinder> b = ProcessState::self()->getContextObject(NULL);return javaObjectForIBinder(env, b);
}

ProcessState 是每一个进程创建起都有的进程对象。

// frameworks/native/libs/binder/ProcessState.cppsp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{// 获取 IBinder 对象并返回。sp<IBinder> context = getStrongProxyForHandle(0); // 参数 0 是 servicemanager 进程idif (context) {// The root object is special since we get it directly from the driver, it is never// written by Parcell::writeStrongBinder.internal::Stability::markCompilationUnit(context.get());} else {ALOGW("Not able to get context object on %s.", mDriverName.c_str());}return context;
}sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{sp<IBinder> result;std::unique_lock<std::mutex> _l(mLock);if (handle == 0 && the_context_object != nullptr) return the_context_object;// 在数组Vector在中查找 handle_entry,若刚开始数组大小是 0,系统会创建一个 handle_entry,放入到数组中。handle_entry* e = lookupHandleLocked(handle); if (e != nullptr) {IBinder* b = e->binder;  // 在数组是大小是0的情况下,这里的 binder=nullptr。if (b == nullptr || !e->refs->attemptIncWeak(this)) {if (handle == 0) {  // 本篇幅中,这个 handle 传入的就是 0。IPCThreadState* ipc = IPCThreadState::self();CallRestriction originalCallRestriction = ipc->getCallRestriction();ipc->setCallRestriction(CallRestriction::NONE);Parcel data;status_t status = ipc->transact(0, IBinder::PING_TRANSACTION, data, nullptr, 0);ipc->setCallRestriction(originalCallRestriction);if (status == DEAD_OBJECT)return nullptr;}// 创建 BpBinder 对象。sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);e->binder = b.get();if (b) e->refs = b->getWeakRefs();result = b;} else {result.force_set(b);e->refs->decWeak(this);}}return result;
}

这里获取到了 C/C++ 层的 IBinder(实际是 BpBinder) 对象。

Binder 客户端 获取 Binder 对象执行到这里获取到 IBinder 对象。我们再往回逐步查看ProcessState::getContextObject() -> android_util_Binder::android_os_BinderInternal_getContextObject() 。 在 C/C++层获取到 IBinder 对象之后,调用了 javaObjectForIBinder() 函数。

// frameworks/base/core/jni/android_util_Binder.cppjobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{if (val == NULL) return NULL;if (val->checkSubclass(&gBinderOffsets)) {jobject object = static_cast<JavaBBinder*>(val.get())->object();LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);return object;}BinderProxyNativeData* nativeData = new BinderProxyNativeData();nativeData->mOrgue = new DeathRecipientList;nativeData->mObject = val;// 通过JNI调用 android.os.BinderProxy::getInstance() 方法,创建Java层 BinderProxy 对象。jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());if (env->ExceptionCheck()) {return NULL;}BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);if (actualNativeData != nativeData) {delete nativeData;}return object;
}

这个函数的作用即是将 C/C++ 层的 BpBinder 对象的数据转换成 Java 层 BinderProxy 对象数据。

执行完这个函数后,就会将 android.os.BinderProxy 对象作为 Java 层 getContextObject() 的返回值返回。这样ServiceManager::getIServiceManager() 执行完成,返回到 ServiceManager::rawGetService() 方法。

private static IBinder rawGetService(String name) throws RemoteException {final long start = sStatLogger.getTime();// 上述一切的重点在于 getIServiceManager() 任何获取 Client 端的 BinderProxy(BpBidner)。// 它返回的就是 ServiceManagerProxy,其中封装有 BinderProxy 对象。final IBinder binder = getIServiceManager().getService(name);// ......return binder;
}

在这里将 binder 返回,再返回到 ActivityManager.getService() 的最初位置,接着调用 bindServiceInstance() 方法。

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javafinal ActiveServices mServices;public int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,String resolvedType, IServiceConnection connection, long flags, String instanceName,String callingPackage, int userId) throws TransactionTooLargeException {return bindServiceInstance(caller, token, service, resolvedType, connection, flags,instanceName, false, INVALID_UID, null, null, callingPackage, userId);
}private int bindServiceInstance(IApplicationThread caller, IBinder token, Intent service,String resolvedType, IServiceConnection connection, long flags, String instanceName,boolean isSdkSandboxService, int sdkSandboxClientAppUid,String sdkSandboxClientAppPackage,IApplicationThread sdkSandboxClientApplicationThread,String callingPackage, int userId)throws TransactionTooLargeException {// ......try {// ......synchronized (this) {return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,sdkSandboxClientAppPackage, sdkSandboxClientApplicationThread,callingPackage, userId);}} finally {Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
}

这样来完成从 Client 端获取到 Server 端的 Binder 代理,从而调用到 Server 端的方法。

后续会上一张图

这篇关于从app bindService分析binder客户端的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/494984

相关文章

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

Linux中的more 和 less区别对比分析

《Linux中的more和less区别对比分析》在Linux/Unix系统中,more和less都是用于分页查看文本文件的命令,但less是more的增强版,功能更强大,:本文主要介绍Linu... 目录1. 基础功能对比2. 常用操作对比less 的操作3. 实际使用示例4. 为什么推荐 less?5.

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

Java集成Onlyoffice的示例代码及场景分析

《Java集成Onlyoffice的示例代码及场景分析》:本文主要介绍Java集成Onlyoffice的示例代码及场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 需求场景:实现文档的在线编辑,团队协作总结:两个接口 + 前端页面 + 配置项接口1:一个接口,将o

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File

C#使用MQTTnet实现服务端与客户端的通讯的示例

《C#使用MQTTnet实现服务端与客户端的通讯的示例》本文主要介绍了C#使用MQTTnet实现服务端与客户端的通讯的示例,包括协议特性、连接管理、QoS机制和安全策略,具有一定的参考价值,感兴趣的可... 目录一、MQTT 协议简介二、MQTT 协议核心特性三、MQTTNET 库的核心功能四、服务端(BR

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

C#继承之里氏替换原则分析

《C#继承之里氏替换原则分析》:本文主要介绍C#继承之里氏替换原则,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#里氏替换原则一.概念二.语法表现三.类型检查与转换总结C#里氏替换原则一.概念里氏替换原则是面向对象设计的基本原则之一:核心思想:所有引py

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

PostgreSQL 序列(Sequence) 与 Oracle 序列对比差异分析

《PostgreSQL序列(Sequence)与Oracle序列对比差异分析》PostgreSQL和Oracle都提供了序列(Sequence)功能,但在实现细节和使用方式上存在一些重要差异,... 目录PostgreSQL 序列(Sequence) 与 oracle 序列对比一 基本语法对比1.1 创建序