← 返回文章流

Android Binder源码分析:添加服务和获取服务解析

通过ServiceManager添加服务和获取服务分别为addService和getService,两者流程上其实是有一些类似的,其中我们可以看到binder通讯的全过程。为了让内容更有意义,添加服务选择从Java层的代码触发,获取服务则选择从Native层触发。 添加服务 我们以添加ActivityManagerService为例分析添加一个Service。首先先画个简单的流程图,介绍涉及到的类和调用的方法,不过步骤进行了省略,详细看后面的代码解析。 ServiceManagerProxy请求添加Service 其代码在ActivityManagerService的setSystemProcess方法当中,具体调用如下: 1 2 ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO); 具体实现如下: 1 2 3 4 5 6 7 8 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority) { try { getIServiceManager().addService(name, service, allowIsolated, dumpPriority); } catch (RemoteException e) { } } 其中getIServiceManager的代码我们已经分析过了,我们之前拿到的IServiceManager的实例为ServiceManagerProxy,这里可以直接去看它的这个方法: 1 2 3 4 public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority) throws RemoteException { mServiceManager.addService(name, service, allowIsolated, dumpPriority); } 这里调用了mServiceManager的同名方法,而这个成员变量的初始化如下: 1 mServiceManager = IServiceManager.Stub.asInterface(remote); 这里的remote就是我们之前构造函数传入的BinderProxy,而上面的函数后我们发获取到的对象则为IServiceMaanager.Stub.Proxy,我们可以看一下它的同名方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Override public void addService(java.lang.String name, android.os.IBinder service, boolean allowIsolated, int dumpPriority) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(name); _data.writeStrongBinder(service); _data.writeBoolean(allowIsolated); _data.writeInt(dumpPriority); boolean _status = mRemote.transact(Stub.TRANSACTION_addService, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } 这里我们看到就是把设置的数据和binder写入到Parcel之后 调用transact。这里我们可以看一下Parcel首先是写入了InterfaceToken,也就是IServiceManager的描述符,其次才是其他内容。我们主要关注一下如何写入Binder的。其最终调用的方法在android_os_Parcel.cpp中,代码如下: 1 2 3 4 5 6 7 8 9 10 static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel != NULL) { const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object)); if (err != NO_ERROR) { signalExceptionForError(env, clazz, err); } } } 我们主要关注第5行,这里有一个ibinderForJavaObject,用于从javaobject中拿到binder的native对象,我们可以看一下其源码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) { if (obj == NULL) return NULL; // 如果是Binder实例 if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); return jbh->get(env, obj); } // 如果是BinderProxy实例 if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { return getBPNativeData(env, obj)->mObject; } return NULL; } BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) { return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData); } 这个地方会判断我们的传过来的javaobject是Binder的实例还是BinderProxy的实例,前者对应Binder的服务端,后者对应的是客户端,我们刚刚传过来的AMS则是服务端。这里是从javaobject拿到mObject成员变量,对应native的类JavaBBinderHolder,最后调用它的get方法拿到JavaBinder对象。此处算是完成了我们Java层的Binder在Native层的对应对象的获取。现在就可以看看Parcel的writeStrongBinder方法了: 1 2 3 status_t Parcel::writeStrongBinder(const sp<IBinder>& val) { return flattenBinder(val); } 其中又调用了flattenBinder,这个方法比较长,我们先一点点的贴代码: 1 2 3 4 5 6 7 BBinder* local = nullptr; if (binder) local = binder->localBinder(); if (local) local->setParceled(); if (isForRpc()) { ... } 这里binder是我们刚刚的拿到的JavaBBinder,它的localBinder()实现如下: 1 2 3 BBinder* BBinder::localBinder() { return this; } 也就是说返回了自己。另外这里我们不是RPC,所以其中的代码我们不需要关注,继续看后面的代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 flat_binder_object obj; if (binder != nullptr) { if (!local) { ...//如果我们传入的不是BBinder,而是BpBinder执行这里的逻辑,省略 } else { int policy = local->getMinSchedulerPolicy(); int priority = local->getMinSchedulerPriority(); if (policy != 0 || priority != 0) { // override value, since it is set explicitly schedBits = schedPolicyMask(policy, priority); } obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS; .... obj.hdr.type = BINDER_TYPE_BINDER; obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs()); obj.cookie = reinterpret_cast<uintptr_t>(local); } } else { ... } obj.flags |= schedBits; 上面的代码主要是将binder的一些参数拍平放到flat_binder_object当中。其中binder是放置到cookie字段,binder的弱引用放到了binder字段。 1 2 3 4 status_t status = writeObject(obj, false); if (status != OK) return status; return finishFlattenBinder(binder); 这里才开始真正的把数据写入 ,可以先看看这个writeObject方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData) { const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity; const bool enoughObjects = mObjectsSize < mObjectsCapacity; if (eno

来自 码农明明桑作者主页
在原博客阅读全文 (新标签页打开)

以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

一起聊聊 0

尊重不同观点

还没有评论。欢迎分享第一个想法。

RSS SUBSCRIPTIONS

选择 RSS 订阅

把博客汇的文章添加到你常用的阅读器。

关注文章 RSS 订阅本订阅需要登录后使用