Android Framework实战开发-binder通信java及jni部分源码分析
Posted Android高级知识分享官
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Framework实战开发-binder通信java及jni部分源码分析相关的知识,希望对你有一定的参考价值。
csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论
1、第一部分进程与ServiceManager通信及客户端程序发起调用详解
平时大部分获取ServiceManager中的某一个服务,一般都是最后都是ServiceManager.getService这种方式:
//ServiceManager.java中
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(getIServiceManager().getService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
这里getIServiceManager()如下:
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
这里最后也是调用了BinderInternal.getContextObject(),这里getContextObject是个native方法,所以继续追到了native层:
这个对应native方法在:
frameworks\\base\\core\\jni\\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::self()->getContextObject,获取了native层面的IBinder对象,然后再调用javaObjectForIBinder把这个对象进行转换成java对象
先来看 ProcessState::self()->getContextObject方法:
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
这里其实是调用getStrongProxyForHandle(0),记住哦这里传递handle的参数是0,因为ServiceManager的一个应用固定就是0,他是我们跨进程通信一切一切的基础,几乎所有跨进程通信都是需要通过它
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
这刚开始handle_entry肯定为null,所以这里其实就是new BpBinder(0)对象进行返回,那么这里大家就应该清楚,最后进程获取ServiceManager对应的IBinder对象,其实本质就是BpBinder对象,这个对象由对应的handle值,通过这个handle值传递到了驱动,驱动就可以知道与哪个进程进行通信,0当然是ServiceManager进程。
到这里我们就获取的一个BpBinder,但是这个是也是native层面的,怎么把它变成java层面的对象呢?这里就需要来看javaObjectForIBinder(env, b)方法:
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
//。。省略
//这里构造出了gBinderProxyOffsets的java对象
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
// The proxy holds a reference to the native object.
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());//这里吧val这个c++的对象指针设置到gBinderProxyOffsets.mObject这个java属性中
val->incStrong((void*)javaObjectForIBinder);
// The native object needs to hold a weak reference back to the
// proxy, so we can retrieve the same proxy if it is still active.
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
//前面只是基于val建立对应的java对象,及java对象可以直接拿到val指针,但是我们进程也需要val指针可以获取到java对象,这个就是,来关联
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
// Also remember the death recipients registered on this proxy
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
// Note that a new object reference has been created.
android_atomic_inc(&gNumProxyRefs);
incRefsCreated(env);
}
return object;
}
其中的gBinderProxyOffsets修改看如下:
const char* const kBinderProxyPathName = "android/os/BinderProxy";
static int int_register_android_os_BinderProxy(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, "java/lang/Error");
gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
clazz = FindClassOrDie(env, kBinderProxyPathName);
gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
"(Landroid/os/IBinder$DeathRecipient;)V");
gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
。。省略
}
其实本质都是通过jni方式来构造
好了那么回到最初始:
ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
这个里面allowBlocking可以暂时忽略,名字它只是个和阻塞不阻塞相关,BinderInternal.getContextObject()本身就已经是BinderProxy类型对象了,所以asInterface其实就是:
new ServiceManagerProxy(obj);这里obj其实就是ServiceManagerProxy类中的mRemote,通信时候其实都是调用这个mRemote的transact方法
那接下来获取了ServiceManager已经分析的很清楚了,那么看看他的一个getSevice方法,这里其实addService肯定也是完全类似的,就只需要分析一个既可以:
那么我们来看getIServiceManager().getService(name)方法:
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
这里看看出,它首先要进行跨进程通信就要准备好数据包Parcel,data代表要传递过去的,reply代表要传递回来的,然后再调用最关键的mRemote.transact,这里前面分析过了mRemote本质是BinderProxy类型,故来看BinderProxy的transact(注意BinderProxy类在Binder.java这个文件中):
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
。。省略
try {
return transactNative(code, data, reply, flags);
} finally {
if (tracingEnabled) {
Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
}
}
}
这里其实就是调用transactNative 对应的jni 方法在:
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
。。省略
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
。。省略
//printf("Transact from Java code to %p sending: ", target); data->print();
status_t err = target->transact(code, *data, reply, flags);
。。省略
}
这里其实就是获取BinderProxy中的mObject对象,因为他存储是c++层面的BpBinder对象地址,故target其实就是调用BpBinder的transact:
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
这里看看到最后又调用到了IPCThreadState的transact方法
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
。。省略
if (err == NO_ERROR) {
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
writeTransactionData主要目的就是把数据组装成驱动的binder_transaction_data结构体
然后又会根据是否为oneway区分,但是最后都是调用waitForResponse方法:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
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 {
。。省略
}
}
。。省略
}
这里循环调用talkWithDriver,然后获取结果。驱动部分我们下一节会讲解,这里我们到这里就知道,binder通信在自己进程最后都会调用到talkWithDriver来与binder驱动进行通信。
这里就直接给出返回结果为对应的Serivce的handle,然后利用这个handle构造出对应的BpBinder即这一部分就完全和IServiceManager的获取是一样的,只不过ServiceManager是直接new BpBinder(0)
而远程服务则是需要先从ServiceManager中获取handle,然后再new BpBinder(handle)
至此为止,我们就分析清楚了客户端发起一个跨进程调用的java到jni的所有流程
2、服务进程的方法被调用流程从上到下详解
服务端的方法被调用流程相比客户端的主动发起调用流程更加难分析,这里我们可以分成2个部分来进行分析:
2.1 native层的BBinder执行分析:
因为这里只涉及到native层面,相对不用把java部分搞一起,相对分析起来会简单,讲解完了这一部分在去讲解java端怎么运行相对就会简单很多,如果一起讲解相对理解难度会非常大。
我们前面应该知道,native层面进行跨进程通信时候,服务端主要负责实现一个BBinder类,它最主要的方法就是onTransact方法:
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0) {
ALOGD( "Service onTransact, code = %d" , code);
switch (code) {
case FUNC_CALLFUNCTION:
callFunction();
break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
return 0;
}
这里其实就是已经进入了我们的服务端的方法具体方法实现了,那么到底是怎么一步步到这里呢?
这里当然大家可以采用以前我们说过的用类似java的打印调用堆栈方法来追踪。这里我们后面再给大家展示既可以,本节课就暂时不讲啦。
那首先来看看到 IPCThreadState::self()->joinThreadPool( true);这个方法就代表会一直不断来读取驱动发过来数据
do {
。。省略
result = getAndExecuteCommand();
。。省略
}
} while (result != -ECONNREFUSED && result != -EBADF);
其实他就是在不断执行getAndExecuteCommand
status_t IPCThreadState::getAndExecuteCommand()
{
。。省略
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
。。省略
result = executeCommand(cmd);
。。省略
}
return result;
}
这里是不是talkWithDriver会与驱动进行通信获取了对应result和数据写入了mIn中,读取cmd,然后调用了executeCommand(cmd)方法
status_t IPCThreadState::executeCommand(int32_t cmd)
{
。。省略
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
if (tr.target.ptr) {
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
if ((tr.flags & TF_ONE_WAY) == 0) {
sendReply(reply, 0);
}
。。省略
}
break;
。。省略
return result;
}
这里省略的大部分,我们主要关心case BR_TRANSACTION:情况
有这句关键代码:
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);
这里是不是大概可以看出一个BBinder指针调用对应的transact方法,好像我们发现了真相是吧?都看到transact了,那么继续看看transact方法,因为我们自己没有实现过这个transact,只是重写了onTransact(注意哦,这里的BBinder类在Binder.cpp中):
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
..省略
switch (code) {
..省略
default:
err = onTransact(code, data, reply, flags);
break;
}
..省略
return err;
}
这里是不是就看到了我们的onTransact,这里就是真正调用到我们自己写的服务的onTransact方法中。
那这里好像就讲完了粗略流程。但是还有许多细节哦,比如
reinterpret_cast<BBinder*>(tr.cookie)->transact()
这里面的tr.cookie我们猜想肯定是我们自己的SampleService这个继承BBinder对象的类。但是它是到底怎么一步步变成了这里的tr.cookie 我们并不清楚,那么我们就来详细分析一下:
那么首先得回到最开始ServiceManager的addService:
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
以上是关于Android Framework实战开发-binder通信java及jni部分源码分析的主要内容,如果未能解决你的问题,请参考以下文章
千里马Android Framework实战开发-native程序之间binder通信实战案例分析
千里马Android Framework实战开发-native程序之间binder通信实战案例分析
千里马Android Framework实战开发-native程序之间binder通信实战案例分析
Android Framework实战开发-socketpair介绍及它在android系统源码使用分析