最近在公司有听到同事做的一个需求。就是一个非系统应用(不使用系统签名),通过额外的方法,将自身一个AIDL service的binder句柄通过ServiceManager.addService
接口注册到ServiceManager
中。那么其他应用就能通过ServiceManager.getService
来获取到该service提供的binder句柄,从而进行跨进程调用了。
首先这里定一个调调,那就是我们不评判这样实现是否有问题。我们之关注技术,这里我们想关注的点有:1)ServiceManager.addService
的流程;2)这种方式添加binder句柄到ServiceManager
后,代码是否运行在system_server
进程。下面所有分析的代码都是基于Android11_R17进行分析。
0. ServiceManager.addService流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public static void addService(String name, IBinder service) { addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT); } public static void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority) { try { // 1 getIServiceManager用来获取service_manager的一个代理binder // 2 通过addService进行service注册 getIServiceManager().addService(name, service, allowIsolated, dumpPriority); } catch (RemoteException e) { Log.e(TAG, "error in addService", e); } } |
ServiceManager.addService
的流程如上面代码所示,我们一般调用的都是两个参数的addService
方法,这个方法然后会继续调用四个参数的重构方法。四参的方法内部首先通过getIServiceManager
获取service_manager
中的代理Proxy,代码如下:
1 getIServiceManager获取service_manager binder代理
1 2 3 4 5 6 7 8 9 10 11 12 |
private static IServiceManager getIServiceManager() { if (sServiceManager != null) { return sServiceManager; } // 1.1 BinderInternal.getContextObject()用于获取service_manager的代理binder对象 // 1.2 ServiceManagerNative.asInterface用于将bpbinder转换为IServiceManager,方便进行binder调用 sServiceManager = ServiceManagerNative .asInterface(Binder.allowBlocking(BinderInternal.getContextObject())); return sServiceManager; } |
1.1 BinderInternal.getContextObject()
BinderInternal.getContextObject()
是一个native方法,实现在android_util_Binder.cpp
文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// 实现在android_util_Binder.cpp static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz) { sp<IBinder> b = ProcessState::self()->getContextObject(NULL); return javaObjectForIBinder(env, b); } // 实现在ProcessState.cpp中 sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/) { sp<IBinder> context = getStrongProxyForHandle(0); if (context == nullptr) { ALOGW("Not able to get context object on %s.", mDriverName.c_str()); } internal::Stability::tryMarkCompilationUnit(context.get()); return context; } |
首先首先调用了ProcessState::getContextObject
方法,然后通过javaObjectForIBinder
方法将native层的binder对象封装成Java层的binder对象并返回给调用者。ProcessState::getContextObject
方法内部再通过getStrongProxyForHandle(0)
找到0号的binder对象,0号的binder对象就是service_manager了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) { sp<IBinder> result; AutoMutex _l(mLock); //ProcessState维护了该进程的一个服务代理对象的列表,这里就是根据handle句柄 // 在当前进程的服务代理链表中查找指定的服务代理对象,并返回一个handle_entry 指针 handle_entry* e = lookupHandleLocked(handle); if (e != nullptr) { IBinder* b = e->binder; if (b == nullptr || !e->refs->attemptIncWeak(this)) { // service_manager的handle为0,所以这里判断如果获取的是service_manager // 需要通过PING一下,确保service_manager正在运行 if (handle == 0) { Parcel data; status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, nullptr, 0); if (status == DEAD_OBJECT) return nullptr; } // 创建一个BpBinder,属于Binder的代理对象 b = BpBinder::create(handle); e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } else { result.force_set(b); e->refs->decWeak(this); } } return result; } |
OK,BinderInternal.getContextObject()
过程中涉及的方法都已经介绍完毕,从最终的结果来看,ProcessState::getStrongProxyForHandle
方法最后返回的是0号BpBinder。Binder.allowBlocking
的作用是将BinderProxy的sWarnOnBlocking值置为false,这里我们就略过这部分代码,所以最终传给ServiceManagerNative.asInterface
的就是一个handle为0的BpBinder了。后面我们继续看下一步ServiceManagerNative.asInterface
方法的实现
1.2 ServiceManagerNative.asInterface
ServiceManagerNative.asInterface
的实现总体看还是比较简单的
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static IServiceManager asInterface(IBinder obj) { if (obj == null) { return null; } return new ServiceManagerProxy(obj); } public ServiceManagerProxy(IBinder remote) { mRemote = remote;想 mServiceManager = IServiceManager.Stub.asInterface(remote); } |
asInterface
方法内部直接创建的是ServiceManagerProxy
,ServiceManagerProxy
内部首先是保存这个service_manager的BpBinder句柄到mRemote
成员变量中;然后通过IServiceManager.Stub.asInterface
将BpBinder句柄转换为IServiceManager对象,并将其保存到mServiceManager
成员变量中。源码中IServiceManager是一个AIDL文件,在 源码编译的时候会将其转换为Java和C++代码。有兴趣的同学可以尝试反编译框架的代码,就可以看到IServiceManager反编译之后的实现了。后面有遇到对应的实现,我们再将反编译代码贴出来,这里我们只需要知道IServiceManager.Stub.asInterface
调用完后,返回的就是一个封装成ServiceManagerProxy类型的servcie_manager代理对象。
2. addService流程
上面第1部的一整套流程之后,通过分析getIServiceManager
我们获取到的是封装成ServiceManagerProxy类型的servcie_manager代理对象,然后就是通过调用getIServiceManager().addService(name, service, allowIsolated, dum pPriority);
进行addService操作。ServiceManagerProxy
是如何进行addService操作的
1 2 3 4 5 |
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority) throws RemoteException {的的 mServiceManager.addService(name, service, allowIsolated, dumpPriority); } |
可以看到,这里是直接调用成员变量mServiceManager
的addService方法,如第一部分我们讨论过的,mServiceManager
是IServiceManager的代理对象,IServiceManager是由AIDL编译而来,我们下面直接看AIDL编译后的addService代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(Stub.DESCRIPTOR); _data.writeString(name); _data.writeStrongBinder(service); _data.writeInt(allowIsolated ? 1 : 0); _data.writeInt(dumpPriority); if (this.mRemote.transact(3, _data, _reply, 0) || Stub.getDefaultImpl() == null) { _reply.readException(); _reply.recycle(); _data.recycle(); return; } Stub.getDefaultImpl().addService(name, service, allowIsolated, dumpPriority); } finally { _reply.recycle(); _data.recycle(); } } |
制造binder通信所需要的data parcel并填入对应的数据,这里重要的部分是调用了writeStrongBinder
。这部分代码我们简单的跟踪下,writeStrongBinder
会通过JNI调用到native层Parcel.cpp的同名方法,而Parcel.cpp的writeStrongBinder
会调用到flattenBinder
对传入的Binder对象进行扁平化操作,我们就从flattenBinder
开始进行分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
status_t Parcel::flattenBinder(const sp<IBinder>& binder) { flat_binder_object obj; ............... if (binder != nullptr) { BBinder *local = binder->localBinder(); if (!local) { BpBinder *proxy = binder->remoteBinder(); if (proxy == nullptr) { ALOGE("null proxy"); } const int32_t handle = proxy ? proxy->handle() : 0; obj.hdr.type = BINDER_TYPE_HANDLE; obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */ obj.handle = handle; obj.cookie = 0; } else { if (local->isRequestingSid()) { obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX; } obj.hdr.type = BINDER_TYPE_BINDER; obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs()); obj.cookie = reinterpret_cast<uintptr_t>(local); } } else { obj.hdr.type = BINDER_TYPE_BINDER; obj.binder = 0; obj.cookie = 0; } return finishFlattenBinder(binder, obj); } |
这段代码中,需要判断传进来的binder对象是BpBinder还是BBinder,然后如果是binder对象,就将其保存到flat_binder_object
的binder成员变量中,如果是binder句柄,即binder代理对象,这将句柄保存到flat_binder_object
的handle成员变量中。最后再通过finishFlattenBinder
调用完成数据的扁平化操作。
1 2 3 4 5 6 7 8 9 10 |
BBinder* BBinder::localBinder() { return this; } BBinder* IBinder::localBinder() { return nullptr; } |
OK,我们回到AIDL部分的addService操作,addService完成的Parcel数据的相关操作后,最后还是通过transact
方法将调用传递到service_manager中。如上面展示,在传递的过程中有对数据进行flattenBinder
操作,那么肯定也会对数据进行unflattenBinder
操作,unflattenBinder
的代码这里就不分析了,有兴趣的同学自行查看。紧接着我们看service_manager的addService是如何实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) { auto ctx = mAccess->getCallingContext(); // AID_APP为10000,即如果是普通的三方应用进行addService操作这里就会直接报错 if (multiuser_get_app_id(ctx.uid) >= AID_APP) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (!mAccess->canAdd(ctx, name)) { return Status::fromExceptionCode(Status::EX_SECURITY); } if (binder == nullptr) { return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (!isValidServiceName(name)) { LOG(ERROR) << "Invalid service name: " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } ............. // implicitly unlinked when the binder is removed if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } // 构造Service对象,并放入到mNameToService中 auto entry = mNameToService.emplace(name, Service { .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, .debugPid = ctx.debugPid, }); auto it = mNameToRegistrationCallback.find(name); if (it != mNameToRegistrationCallback.end()) { for (const sp<IServiceCallback>& cb : it->second) { entry.first->second.guaranteeClient = true; cb->onRegistration(name, binder); } } return Status::ok(); } |
从上面可以看到,我们最后将传入的binder和service name构造出一个struct Service
对象,并保存到mNameToService中,到这里我们的addService操作就完成了,可以看到这整个过程中,其实是没有进行进程拉起操作的。所以可以肯定的是如果应用将自身的binder服务句柄通过其他方法添加到service_manager中,其服务也只是运行在应用自身的进程。
其实我们额外再留意运行在service_manager中的服务,例如AMS、PMS等服务,我们会发现,这些服务都是service_manager在启动的时候,通过startBootstrapServices
、startCoreServices
等方法将AMS、PMS这些服务自己拉起,所以这些服务才会运行在service_manager中。
OK,这一篇分析完成。题外话,这一篇其实还是写了挺长时间的,主要是这个system_server的代码架构和之前Android O的代码架构相比,变化实在是稍微有点大了。