Android Framework实战开发-binder通信java及jni部分源码分析

Android 进阶——Framework核心 之Binder Java成员类详解(三) Framework核心 之Binder Java成员类详解 阅读详情
AI摘要

本文深入探讨了Android系统的跨进程通信机制Binder,详细解析了客户端如何通过ServiceManager获取Service,并调用其方法的过程。文章首先分析了ServiceManager如何获取并返回Service的IBinder对象,涉及java到jni的转换,再到BpBinder的创建。接着,解释了服务端BBinder的onTransact方法如何被调用,以及服务端如何响应客户端的调用请求。通过对Parcel、BinderProxy、BBinder等关键组件的剖析,展示了Binder通信的完整流程。

csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论

android跨进程通信实战视频课程(加群获取优惠)

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;
    }

这里是不是把自己的service通过Parcel 的writeStrongBinder写入了,那来看看writeStrongBinder:

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}

接下来看看flatten_binder:

status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;
。。省略
    if (binder != NULL) {
        IBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    }
。。省略
    return finish_flatten_binder(binder, obj, out);
}

这里我们可以看到binder->localBinder();它是用来判断是不是本地binder对象:

BBinder* BBinder::localBinder()
{
    return this;
}

明显这里就返回了自己,所以返回是SampleService,那就是进入以下:

  	obj.type = BINDER_TYPE_BINDER;
	obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
	obj.cookie = reinterpret_cast<uintptr_t>(local);

这里大家是不是看到了一个cookie 东西,它赋值为了local也就是我们的SampleService这个BBinder类对象

2.2 java端的Binder执行与到native层映射分析

2.1 已经清楚binder驱动是怎么调用到native的BBinder的,但同学们肯定又会问,我们平时写的代码都是java层面,请问java层又是怎么个流程呢?这个其实java当然也是基于native层面的BBinder来实现的,具体我们来看代码:
假设是调用java层的ServiceManager来addService

    ServiceManager.addService("MyService", new MyService());//注册服务
//其中的MyService是真正的实现服务端的实现类,这里是不是看出和native层BBinder的要素是不是基本一致,
//最主要是onTransact这个实现,其实这里是由native层面调用过来的,稍后解密
public class MyService extends Binder implements IMyService{

  public MyService() {
    this.attachInterface(this, DESCRIPTOR);
  }

  @Override
  public IBinder asBinder() {
    return this;
  }

  /** 将MyService转换为IMyService接口 **/
  public static com.test.frameworkBinder.IMyService asInterface(android.os.IBinder obj) {
   。。省略
  }

  /**  服务端,接收远程消息,处理onTransact方法  **/
  @Override
  protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    throws RemoteException {
    switch (code) {
    。。省略
    case TRANSACTION_say: {
      data.enforceInterface(DESCRIPTOR);
      String str = data.readString();
      sayHello(str);
      reply.writeNoException();
      return true;
    }
    }
    return super.onTransact(code, data, reply, flags);
  }

  /** 自定义sayHello()方法   **/
  @Override
  public void sayHello(String str) {
    System.out.println("MyService:: Hello, " + str);
  }


}

那么首先我们来看ServiceManager.addService干了啥:
在ServiceManagerNative.java

    public void addService(String name, IBinder service, boolean allowIsolated)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        data.writeStrongBinder(service);
        data.writeInt(allowIsolated ? 1 : 0);
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }
    

这里调用的是data.writeStrongBinder(service);来把我们service写入:
在Parcel.java

   public final void writeStrongBinder(IBinder val) {
        nativeWriteStrongBinder(mNativePtr, val);
    }

调用是nativeWriteStrongBinder,是个native方法
base\core\jni\android_os_Parcel.cpp

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);
        }
    }
}

其实他也是调用的native的Parcel类的writeStrongBinder方法,这个方法上一节讲过,但是这里大家看参数是一个java层面的object,所以调用了ibinderForJavaObject(env, object)方法来进行转换,这个方法也就是java层面到native可以打通的一个核心:

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL;
    }

    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return (IBinder*)
            env->GetLongField(obj, gBinderProxyOffsets.mObject);
    }
    return NULL;
}

这里我们业务是本地实现的Binder对象,所以不是gBinderProxyOffsets.mClass,是我们的gBinderOffsets.mClass,这里看看这个gBinderOffsets.mClass:

const char* const kBinderPathName = "android/os/Binder";

static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);

    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");

    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

这方法里面对gBinderOffsets相关的方法和属性进行了设置,大家可以看到mClass 类名其实是android/os/Binder,而我们的MyService本身就是继承android.os.Binder对象,同时注意这里还对execTransact和mObject进行了声明

在回到ibinderForJavaObject:

if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL;
    }

这里会发现从MyService中的mObject对象获取了native层面的JavaBBinderHolder(有个疑问为啥可以获取,java层mObject什么时候变成了JavaBBinderHolder指针,这个稍后解答),然后再调用了JavaBBinderHolder的get方法,就可以获取一个native层面的BBinder对象:

class JavaBBinderHolder : public RefBase
{
public:
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            mBinder = b;
        }
        return b;
    }

    sp<JavaBBinder> getExisting()
    {
        AutoMutex _l(mLock);
        return mBinder.promote();
    }

private:
    Mutex           mLock;
    wp<JavaBBinder> mBinder;
};

这里可以看到get方法确实会在方法里面构造一个JavaBBinder返回,而且大家注意哦,这里是不是还把java层的jobject传递给了JavaBBinder,目前其实就是为了后续JavaBBinder肯定先收到驱动的调用,但是这里JavaBBinder他也要调用到Java层面。

class JavaBBinder : public BBinder
{
public:
    JavaBBinder(JNIEnv* env, jobject object)
        : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
    {
        ALOGV("Creating JavaBBinder %p\n", this);
        android_atomic_inc(&gNumLocalRefs);
        incRefsCreated(env);
    }

    bool    checkSubclass(const void* subclassID) const
    {
        return subclassID == &gBinderOffsets;
    }

    jobject object() const
    {
        return mObject;
    }

protected:
。。省略

    virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
    {。。省略
        JNIEnv* env = javavm_to_jnienv(mVM);
	
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);

        return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
    }
。。省略
private:
    JavaVM* const   mVM;
    jobject const   mObject;
};

到这里JavaBBinder 即它本身也是BBinder相信大家就已经明白,上节课native时候就已经分析过了,最后binder的读取线程会调用到onTransact这个方法,我们看这里是不是有一个CallBooleanMethod方法来调用到java端,这里是调用了gBinderOffsets.mExecTransact方法,它对于是java层Binder的execTransact方法:

  // Entry point from android_util_Binder.cpp's onTransact
    private boolean execTransact(int code, long dataObj, long replyObj,
            int flags) {
     。。省略
        try {
           。。省略
            res = onTransact(code, data, reply, flags);
        } catch (RemoteException|RuntimeException e) {
           。。省略
        } finally {
           。。省略
        }
      。。省略
        return res;
    }

大家看这里他就会调用onTransact,这个onTransact方法当然就调用到了子类MyService的onTransact,故是不是整个java层面到native层面的穿透是不通了
最后解答一下,JavaBBinderHolder什么时候放到了java层mObject,这里我们肯定就来搜索new JavaBBinderHolder的地方:

static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    。。省略
    jbh->incStrong((void*)android_os_Binder_init);
    env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
}

这里大家可以看出是在android_os_Binder_init方法,它把JavaBBinderHolder对象指针赋值给了mObject,这个方法一看就是jni的一个方法,:

    { "init", "()V", (void*)android_os_Binder_init },

名字其实可以知道是Binder.java的init方法,而且init是native的
果然Binder.java定义声明如下:
private native final void init();
这里看看init是在哪里被调用的:

 public Binder() {
        init();
。。省略
    }

他是在Binder()默认构造方法中执行,回到开始MyService 是不是继承Binder:
class MyService extends Binder
所以子类构造会先执行父类构造
4、总结类图
在这里插入图片描述

Android NDK实现Binder服务和客户端 需要在系统源码下编译,或者提取出对应的头文件亦可。这里需要注意Android4.x以后系统SeLinux如果打开,系统级需要配置对应的sepolicy才能使用。测试阶段推荐直接setenforce 0关闭鉴权即可 立即下载

相关推荐

java绑定源码-BinderSample:AndroidBinderDemo示例程序,分别从Android应用层(Java)、framewo

java绑定源码 BinderSample Binder sample程序,分为app, framework, native三大类,每一类生成的可执行文件都位于/Output文件夹相应的子文件下。 示例程序 说明 NativeBinderDemo 从Native角度编写的Binder Demo程序 FrameworkBinderDemo 从framework角度编写的Binder Demo程序 AppBinderDemo 从Apk角度编写的Binder Demo程序 一、 Native Binder 1.1 源码结构 ClientDemo.cpp: 客户端程序 ServerDemo.cpp:服务端程序 IMyService.h:自定义的MyService服务的头文件 IMyService.cpp:自定义的MyService服务 Android.mk:源码build文件 1.2 分层图 1.3 运行 首先将这两个ServerDemo,ClientDemo可执行文件push到手机 adb push ServerDemo /system/bin adb push ClientDemo /sy

[转]android jni层binder使用/进程通信实例

Recently, I’ve decided to begin my own hardware journey. The most important part is to choose a proper operating system. I’ve tried to use several embedded Linux systems, but got many portable and deve

3272

3D点云目标检测Complex-YOLO(训练篇)(一)———KITTI数据集预处理与制作

KITTI dataset Download dataset KITTI 3D Object Detection Evaluation 2017 link 下载四个部分,共41.4GB 解压后为四部分内容(相机校准矩阵calib、RGB图像image_2、标签label_2、点云数据velodyne) 对应的testing和training数据。其中,training数据为7481张(图片和点云对应的场景),testing数据 7518张(无label_2数据)。 Data Preprocess

“知识最大的敌人不是无知,而是错觉” 7151

Binder的JNI调用

JANI的注册 Zygote的启动流程 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/

fw_2012的专栏 403

研一脑电小白日记 之 EEGLAB预处理实战指南

本文为脑电研究新手提供了一份详尽的EEGLAB预处理实战指南。从MATLAB与EEGLAB环境搭建、使用NeuracleEEGFileReader插件导入BDF格式数据开始,逐步讲解了电极定位、滤波、降采样、ICA去伪迹等核心步骤,旨在帮助初学者高效完成脑电数据预处理,为后续分析奠定坚实基础。

weixin_29230649的博客 557

相控阵多功能雷达工作模式识别技术综述

本文综述了相控阵雷达工作模式识别技术的研究进展。首先介绍了相控阵雷达的典型工作模式分类及其信号特征参数,包括搜索模式(VS、RWS、TWS)、跟踪模式(STT、MTT、TAS)和其他模式(SAM、SAR)等。随后重点阐述了基于信号特征的识别方法,包括时域特征(PRI分析、脉冲幅度包络、数据率)、频域特征(载频变化、调制方式)和混合特征分析方法。最后讨论了当前技术面临的挑战与发展趋势,包括复杂信号环境下的识别难题、新型雷达技术的适应需求以及深度学习技术的应用前景。该领域的研究对电子侦察和威胁评估具有重要意义。

Grow into a more wonderful you 1805

android 系统核心机制binder(10)binder java层JNI初始化

系列文章解读&说明: Android系统核心机制binder的分析主要分为以下部分: android 系统核心机制binder(01)C语言简谈binder android 系统核心机制binder(02)binder驱动层原理 android 系统核心机制binder(03)binder C++层实现 android 系统核心机制binder(04)binder C++层 Te...

wangdsh的博客 1216

OpenClaw 核心命令深度解析:/think high、/reasoning on、/verbose on 功能与实战指南

本文深入解析OpenClaw框架的三大核心命令:/think high实现极限深度推理,突破常规思考瓶颈;/reasoning on提供透明化推理过程,增强决策可信度;/verbose on控制详细输出级别。文章从技术架构、实现原理、配置方法和典型场景四个维度,详细阐述了各命令的功能特性与实战应用,包括法律分析、代码调试和商业决策等复杂场景的最佳实践。同时提供了多级配置方案和资源消耗参考,帮助用户根据任务复杂度灵活调配AI资源,实现效率与深度的最优平衡。

qq_43344878的博客 943

Android基础——JNI机制

通过使用jni实现java和C/C++的互相调用

weixin_44901971的博客 1069

Delta并联机构运动学正逆解:从理论建模到Matlab实战

本文深入解析了Delta并联机构运动学正逆解的核心原理与实战方法。通过几何建模,清晰阐述了其“逆解简单、正解复杂”的特性,并详细推导了基于一元二次方程的逆解解析算法与采用牛顿-拉弗森迭代法的正解数值算法。文章结合完整的Matlab代码实例,从符号推导到数值求解,提供了从理论到实践的完整实现路径,助力机器人开发者掌握Delta并联机构的运动学分析。

weixin_29096377的博客 433

【数据集】1980-2020年(5年)土地利用分类数据-中国科学院

简介1980-2020年每五年土地利用数据-中国科学院

WW、forever的博客 3933

Android Binder框架实现之Framework层Binder服务注册过程源码分析

  Android Binder框架实现之framework层服务注册过程源码分析

IT先森 4135

开发Qt上位机获取阿里云IOT设备数据(开发上位机对接阿里云IOT平台)

使用Qt框架开发一款上位机软件,调用阿里云物联网平台的API接口,获取设备最新上传的实时数据,并在Qt设计的软件界面上展示处理。同时,还支持绘制曲线图表展示数据,并具备定时刷新功能。

2143

Android Binder框架实现之Java层Binder整体框架设计

 Android Binder框架实现之Framework层Binder整体框架设计 前言   本文是Android Binder框架实现之Framework层Binder整体框架设计的起始篇,本文会重点讲述Android Binder框架Framework层整体设计思路,本系列的文章列表如下: Android Binder框架实现之Binder的设计和框架 Android Binder框架实现之Binder中的数据结构 Android Binder框架实现之Binder相关的接口和类 Android

IT先森 2897

STM32入门教程:智能储物柜控制

在这个例子中,我们将使用一个4x4的储物柜,共有16个储物格。我们了解了硬件准备、储物柜电路设计、STM32的基本配置、储物柜控制代码的编写以及测试和调试等方面的知识。根据我们的电路设计,我们需要将一些引脚配置为输出,并将其他引脚配置为输入。在本教程中,我们将使用STM32微控制器来实现一个基本的智能储物柜控制系统。在主函数中,我们将不断循环读取传感器数据,并根据数据的变化来控制储物柜的开关和显示相关信息。这个函数将读取人体感应传感器、温湿度传感器和光照传感器的数据,并将数据存储到相应的变量中。

m0_75244442的博客 661

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

都2021年了,还有人在研究Framework源码?

Android是一个庞大的系统,Android Framework只是对系统的- -个封装,里面还牵扯到JNI、C++、Java虚拟机、Linux系统内核、 指令集等。面对如此庞大的系统,我们得有-定的章法去阅读源码,否则就会只见树木不见森林,陷入卷帙浩繁的细节与琐碎之中。 要善于抓住主线和支线,主线指的就是Android系统的各个模块,支线就是这个模块从上值下各个层级中的重要元素,逐- -分析,直至探究到模块的最根源层。 要善于去粗存精,Android Framework也是人写的,有精华也有糟粕,并不是

zhireshini233的博客 236

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

安卓系统SystemServer启动源码分析

主线支线。

2601_95605400的博客 229

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

关于Android Framework源码阅读——阿里大佬分享的核心经验

Android是一个庞大的系统,Android Framework只是对系统的- -个封装,里面还牵扯到JNI、C++、Java虚拟机、Linux系统内核、 指令集等。面对如此庞大的系统,我们得有-定的章法去阅读源码,否则就会只见树木不见森林,陷入卷帙浩繁的细节与琐碎之中。 一、 善于抓住主线和支线,主线指的就是Android系统的各个模块,支线就是这个模块从上值下各个层级中的重要元素,逐- -分析,直至探究到模块的最根源层。 二、 不要去记录那些API调用链,绘制一个序列图理清思路即可,Android F

Android23333的博客 496

Android framework成为热门就业方向,Android framework开发该如何入门学习?

近年越来越多的Android工程师开始关注Framework领域,伺机从应用开发深入到系统开发。但是,稍一了解就会发现,Android源码非常庞大,为使整个源码更易更新和维护,它纵向分层,横向模块化,设计非常精妙。其主要包括通信模块;多媒体模块等,多到眼花缭乱。而且一接触源码,发现得熟悉JNI、读得懂C++、理解Java虚拟机、Linux系统甚至汇编、指令集等等,可谓是困难重重。

Androiddddd的博客 456

从应用开发深入到系统开发,Android framework应该如何学习?

近年越来越多的Android工程师开始关注Framework领域,伺机从应用开发深入到系统开发。但是,稍一了解就会发现,Android源码非常庞大,为使整个源码更易更新和维护,它纵向分层,横向模块化,设计非常精妙。其维护的模块主要包括:ActivityManagerService、WindowManagerService、PackageManagerService、PowerManagerService、SurfaceFlinger、通信模块、多媒体模块等…多到令人眼花缭乱。而且一接触源码,发现得熟悉JNI

m0_64365896的博客 391

Android 架构 JAVA API,android6.0源码分析之Camera API1.0框架简介

1、架构简介由于最近项目涉及到Camera,所以对Camera源码进行了研究,本文将分享Camera框架的基本知识。anroid6.0与5.0相比,Camera框架未曾改变,依然提供了两种API,即API1和API2,依然采用C/S的架构,而client和server两个线程间的通信依然使用IPC binder进程间通信的机制。camera架构图如下: 由图可知:在framework层中,Java...

weixin_39842029的博客 186

面试官再问Android Framework,求你看完这份至尊级学习笔记怼他,全网最全

一、认识Framework层 Framework其实可以简单的理解为一些API的库房,android开发人员将一些基本功能实现,通过接口提供给上层调用,可以重复的调用我们可以称Framework层才真正是Java语言实现的层,在这层里定义的API都是用Java语言编写。但是又因为它包含了JNI的方法,JNI用C/C++编写接口,根据函数表查询调用核心库层里的底层方法,最终访问到Linux内核。那么Framework层的作用就有2个。 1.用Java语言编写一些规范化的模块封装成框架,供APP层开发者调用开发

Android725的博客 492

Android 知识体系

Android归档前言 前言 感谢: Gityuan:Android系统架构开篇 刘望舒的博客:知识体系

许浑的博客 8199

Android Framework层源码阅读,Android架构师专家原文解读

在日常开发过程中,和我们接触最多的就是应用层和 frameWork 框架层了,很多人在开发工作中涉及从Java 层到JNI 层,再到Native层,经常追着追着就丢了这是大多数开发者常见问题,这时阅读Android Framework层的源码成为Android 开发者深入学习的必经之路。但在学习的过程中看到最多的是各路大神的源码分析,而很少有展示如何一步一步找到相关代码的。对于我们来讲,读源码最大的问题,其实是没有应用场景,或者说短期来看成本高,收益底,容易半途而废。

老皮的博客 559
上一篇: 千里马Android Framework实战开发-am命令怎么编译生成及native程序与java程序的binder通信实战
下一篇: 千里马Android Framework实战开发视频-binder驱动的简单核心方法及原理介绍
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值