跨进程调用
ServiceManager内部存储的只是Binder的一个代号。为什么会有个BpBinder和BBinder之分呢?BpBinder是给客户端使用的,BBinder用来给服务端使用。他们都是对Binder的封装。这样可以更好地适配Binder驱动。
我们在客户端调用一个函数的时候,到底是如何实现对Service端的访问的呢?下面就从源码角度来分析这个流程:
以客户端尝试调用服务端的addPerson方法为例:
private ILeoAidl myService;
myService.addPerson(new Person("leo", 3));
之后会进入这里:
@Override public void addPerson(com.enjoy.leoservice.Person person) throws android.os.RemoteException {
// 序列化是跨进程通信的必须。
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((person!=null)) {
_data.writeInt(1);
person.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
// 关键调用
boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().addPerson(person);
return;
}
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
这里的mRemote实际上就是一个IBinder的实现对象。那么它实际是谁呢?因为我们是在客户端调用的,所以这个Binder对象实际上就是BinderProxy。这是因为我们在上一篇文章中分析过,客户端拿到的只能是服务端的代理。
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
// ...
try {
// 这里就会进入JNI的世界了。
return transactNative(code, data, reply, flags);
} finally {
if (transactListener != null) {
transactListener.onTransactEnded(session);
}
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
}
}
之后就进入了Native的世界去继续操作了,这里的obj就是binderproxy。这里也同时完成了数据格式的转化,这也是为什么Binder需要使用Parcel进行序列化的原因。这里的target就是C++层的BpBinder。
JNI函数的注册是在Zygote init注册的时候完成的。然后继续上图,看一看getBpNativeData的实现:
这里的target就是BpBinder。
这个IPCThreadState,每个线程都会有一个,ProcessState,每个进程都会有一个。关于IPCThreadState,由于每一次通信都会创建一个,这也就解释了为什么会有Binder线程池的说法。因为这个IPCThreadState就是线程池中的一个线程。
而在transact函数中。最终会走到这里:
其中waitForResponse就是他的一个IPCThreadState的一个函数,这里边,不停地通过一个死循环去读驱动:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) {
uint32_t cmd;
int32_t err;
while (1) {
// 去驱动把数据读出来
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
IF_LOG_COMMANDS() {
alog << "Processing waitForResponse Command: "
<< getReturnString(cmd) << endl;
}
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;
case BR_ACQUIRE_RESULT: {
ALOG_ASSERT(acquireResult != nullptr, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY: {
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(nullptr,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
talkWithDriver中,就有ioctl函数。就是去读取驱动,或者写驱动:
status_t IPCThreadState::talkWithDriver(bool doReceive) {
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
binder_write_read bwr;
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// 我们不想写任何东西,如果我们还在读取input buffer里剩下的数据,而调用者要求读取下一条数据。
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// ...省略IF_LOG_COMMANDS
// 实际调用驱动
int ret = ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr);
// ...
}
客户端通过Binder完成通信的整体源码流程总结:
app发起调用:service.addPerson() → BinderProxy.transact() → android_util_binder.android_os_BinderProxy_transact() → BpBinder.transact() → IPCThreadState::transact → IPCThreadState::waitForResponse → talkWithDriver → ioctl
不过我们依然存在以下的疑问:
- BinderProxy什么时候出现的?
- android_util_binder是什么?
- BpBinder是什么?
- IPCThreadState是什么?
我们以ServiceManager如何完成client端的调用来分析这几个类到底是什么。
我们通过ServiceManager去获取一个服务的时候,一般都会调用getService方法,它的具体实现是这样的:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(rawGetService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
private static IBinder rawGetService(String name) throws RemoteException {
// 获取Binder对象。
final IBinder binder = getIServiceManager().getService(name);
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager,拿到的实际上就是ServiceManager的一个Binder代理对象。
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
// ServiceManagerNative中
public static IServiceManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
// ServiceManager is never local
return new ServiceManagerProxy(obj);
// 返回的就是一个ServiceManager代理。
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
mServiceManager = IServiceManager.Stub.asInterface(remote);
}
// BinderInternal.getContextObject()
public static final native IBinder getContextObject();
这里的IServiceManager其实就是一个AIDL。
我们发现,这里写的AIDL强转的方式,和我们自己在应用程序中写的AIDL其实是一样的:
ServiceManager由于是服务的管理类,所有的跨进程通信,只要是用AIDL的,就肯定需要它,那么我们必然无法通过ServiceConnection去获取它了,因为ServiceConnection也是ServiceManager中间的一环,如果ServiceManager不存在,那么ServiceConnection也无法触发。**ServiceManager相当于网络通信中的DNS服务器,它的地址是固定的。**我们获取ServiceManager对象的方式也和传统方式不同。那么是怎么拿到的呢?继续上边的getContextObject(),后边在android_util_Binder.cpp中会继续执行:
static const JNINativeMethod gBinderInternalMethods[] = {
/* name, signature, funcPtr */
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
{ "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
{ "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
{ "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
{ "handleGc", "()V", (void*)android_os_BinderInternal_handleGc },
{ "nSetBinderProxyCountEnabled", "(Z)V", (void*)android_os_BinderInternal_setBinderProxyCountEnabled },
{ "nGetBinderProxyPerUidCounts", "()Landroid/util/SparseIntArray;", (void*)android_os_BinderInternal_getBinderProxyPerUidCounts },
{ "nGetBinderProxyCount", "(I)I", (void*)android_os_BinderInternal_getBinderProxyCount },
{ "nSetBinderProxyCountWatermarks", "(II)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
};
然后会进入这里继续执行:
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
// 去Native层构建一个IBinder对象,实际拿到的就是BpBinder。
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
// 上边拿到的BpBinder,这个是一个Native对象,需要通过下边的转化成Java对象才能给Java使用。
return javaObjectForIBinder(env, b);
}
ProcessState,每一个进程启动的时候都会首先启动。用来表示进程的状态。里边主要用来管理Binder驱动的初始化,Binder线程池的初始化,为我们的ServiceManager提供支持。
ProcessState::self()->getContextObject(NULL)中:
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/) {
// handle句柄0代表的就是serviceManager,所以这里调用getStrongProxyForHandle函数的参类。
return getStrongProxyForHandle(0);
}
// 如果对应的BpBinder对象不存在,就直接new一个出来
wp<IBinder> ProcessState::getWeakProxyForHandle(int32_t handle) {
wp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
// 如果对应的BpBinder对象不存在,就直接new一个出来,这也解释了为什么客户端拿到的是BpBinder。
b = new BpHwBinder(handle);
result = b;
e->binder = b;
if (b) e->refs = b->getWeakRefs();
} else {
result = b;
e->refs->decWeak(this);
}
}
// 如果对应的BpBinder对象不存在,就直接new一个出来
return result;
}
BpBinder是对驱动的封装。
javaObjectForIBinder(env, b)中:
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) {
// It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
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;
// 利用反射完成object的创建,这个其实就是代理类。gBinderProxyOffsets也是在int_register_android_os_BinderProxy完成初始化的,(jlong) val.get()代表的是BpBinder所在的地址
jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get()/*BpBinder地址*/);
if (env->ExceptionCheck()) {
// In the exception case, getInstance still took ownership of nativeData.
return NULL;
}
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
if (actualNativeData == nativeData) {
// Created a new Proxy
uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed);
uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed);
if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) {
// 多线程下确保只有一个线程能修改warn计数
if (gProxiesWarned.compare_exchange_strong(numLastWarned,
numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed)) {
ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
}
}
} else {
delete nativeData;
}
return object;
}
gBinderProxyOffsets.mGetInstance,实际上是在BinderProxy里边完成实际的初始化的。
从上边的流程总结下,这就是ServiceManager的整体封装流程:
源码的调用流程:
ServiceManagerProxy(Stub.proxy)->IServiceManager.Stub.Proxy.getService()->android_util_binder.android_os_BinderProxy_transact()->BinderProxy.transact()->BpBinder.transact()
学后检测
单选题
1. 在Android Binder通信体系中,客户端通过ServiceManager拿到的Binder对象在Java层实际是哪类对象?
A. BBinder
B. BpBinder
C. BinderProxy
D. IBinder.Stub
答案:C
解析: ServiceManager返回的是BpBinder(C++层),然后用javaObjectForIBinder转换为Java层的BinderProxy对象。
2. 以下哪一项不是Android常见的进程间通信方式?
A. 管道
B. Socket
C. Binder
D. EventBus
答案:D
解析: EventBus是进程内的事件分发,不涉及IPC。
多选题
3. 关于Binder机制的说法,哪些是正确的?
A. Binder驱动是内核空间的虚拟设备
B. BBinder用于服务端,BpBinder用于客户端
C. 每个线程有独立的IPCThreadState实例
D. Binder通信完全不需要序列化
答案:A、B、C
解析: Binder需要序列化(用Parcel),D项错误。
4. 关于ServiceManager的获取,以下哪些说法是正确的?
A. 其地址在系统中是固定的
B. getContextObject()会返回一个BpBinder
C. 获取过程会用到JNI
D. 只能通过ServiceConnection拿到ServiceManager
答案:A、B、C
解析: D错误,ServiceManager不能用ServiceConnection获取。
判断题
5. BinderProxy对象在服务端创建,客户端使用。(判断对错)
答案:错
解析: BinderProxy是客户端用于代理服务端的Binder的Java对象,服务端只会有BBinder。
6. talkWithDriver方法中会通过ioctl与Binder驱动交互。(判断对错)
答案:对
解析: 源码清晰表明,最终系统调用是ioctl。
简答题
7. 为什么Binder通信的数据需要使用Parcel进行序列化?
答案:
因为跨进程通信需要将复杂的Java对象转化为可以跨进程传递的字节流,Binder驱动只认原始二进制格式,Parcel高效地实现了数据的序列化与反序列化。
8. 简述Binder通信过程中,客户端调用addPerson后,数据如何一步步送达服务端?
答案:
- 客户端AIDL代理类封装参数到Parcel
- 调用BinderProxy.transact,进入JNI(transactNative)
- JNI找到C++层BpBinder对象
- BpBinder.transact通过IPCThreadState发送数据
- IPCThreadState::talkWithDriver调用ioctl与Binder驱动通信
- 数据由驱动路由到服务端,服务端BBinder收到,回调onTransact,反序列化数据并执行业务逻辑
源码填空题
9. 填空:在ProcessState::getContextObject(NULL)函数里,handle为( )的BpBinder代表ServiceManager。
答案:0
解析: ServiceManager的Binder handle固定为0。
10. 填空:javaObjectForIBinder方法会将native层BpBinder包装成Java层的( )对象。
答案:BinderProxy
解析: 用于Java层跨进程代理。
开放编程题
11. 简述如何在Android中自定义AIDL服务,并让不同进程的Activity与之通信?
答案:
- 创建.aidl文件,定义接口和数据结构
- Service端实现Stub,注册Service并在AndroidManifest声明
android:process属性- 客户端复制.aidl到相同包路径下,通过bindService绑定远程Service
- 在onServiceConnected中用
asInterface获取代理对象,调用方法即可