从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

相关文章

Python手搓邮件发送客户端

《Python手搓邮件发送客户端》这篇文章主要为大家详细介绍了如何使用Python手搓邮件发送客户端,支持发送邮件,附件,定时发送以及个性化邮件正文,感兴趣的可以了解下... 目录1. 简介2.主要功能2.1.邮件发送功能2.2.个性签名功能2.3.定时发送功能2. 4.附件管理2.5.配置加载功能2.6.

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

macOS怎么轻松更换App图标? Mac电脑图标更换指南

《macOS怎么轻松更换App图标?Mac电脑图标更换指南》想要给你的Mac电脑按照自己的喜好来更换App图标?其实非常简单,只需要两步就能搞定,下面我来详细讲解一下... 虽然 MACOS 的个性化定制选项已经「缩水」,不如早期版本那么丰富,www.chinasem.cn但我们仍然可以按照自己的喜好来更换

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit