Android Binder机制源码笔记(1)

11 篇文章 0 订阅
11 篇文章 0 订阅
  1. Binder在java层的实现其实是对native层的封装(Binder.java中一堆的native方法),因此主要分析的应该是native层.

  2. android_util_Binder.cpp:

    • 对于java层的native方法在这里进行了register,已和c/c++层对应起来:

      • 构造一个JNINativeMethod数组,里面存储了Binder的java方法和cpp方法的映射:

        /* name, signature, funcPtr */
        { “getCallingPid”, “()I”, (void*)android_os_Binder_getCallingPid }……..

      • 上面这些方法都是在Binder.java中定义的native方法.

      • 映射到的native层的方法都在该.cpp内,但是也只是对IPCThreadState::self()相应方法的转发,一个简单的封装.
      • Method映射的调用步骤:
        1. AndroidRuntime::start(…)->startReg(env)
        2. startReg(env) -> register_jni_procs(gRegJNI, NELEM(gRegJNI), env)
        3. 而 gRegJNI数组中包含了REG_JNI(register_android_os_Binder)
        4. android_util_Binder中的register_android_os_Binder(…)
        5. 会调用3个init_register_XXX方法:
          • int_register_android_os_Binder
          • int_register_android_os_BinderInternal
          • int_register_android_os_BinderProxy
        6. 这三个方法最后都会调AndroidRuntime::registerNativeMethods(…)来将对应的Java层method与native层的函数对应起来.
        7. 三个method映射数组分别是:
          • gBinderMethods[] (Binder.java中的native函数):
            • getCallingPid
            • getCallingUid
            • clearCallingIdentity
            • restoreCallingIdentity
            • setThreadStrictModePolicy
            • getThreadStrictModePolicy
            • flushPendingCommands
            • init
            • destroy
          • gBinderInternalMethods[]
            • getContextObject
            • joinThreadPool
            • disableBackgroundScheduling
            • handleGc
          • gBinderProxyMethods[](BinderProxy.java中的native函数, 这个类也是在Binder.java中定义的,和class Binder一样是implements了IBinder接口)
            • pingBinder
            • isBinderAlive
            • getInterfaceDescriptor
            • transact
            • linkToDeath
            • unlinkToDeath
            • destroy
  3. 很多方法都是直接转交给IPCThreadState->self来调用的:

    • IPCThreadState的self() 是static的函数,其实返回的是一个TLS对象,里面是该线程自己own的一个IPCThreadState对象,可见IPCThreadState对象基本是每个线程都有自己的一个专属的, 注意如果已经shutdown(gShutdown), 那么会返回null. 如果当前线程的TLS还没有对应的IPCThreadState,那么就会new一个,注意,在IPCThreadState的构造函数中,会将自己放入到所在线程的TLS中(pthread_setspecific(gTLS, this)).

    • IPCThreadState的shutdown函数也是一个static的函数,会将gShutdown设为true,但是只会将自己线程的TLS先null,其他线程的则需要等待被使用过后的释放.

  4. 在Java层使用时,一般只有Binder类显山露水,但是其实BinderProxy也是被使用的,只不过通过一个IBinder的引用来使用的,因此看不到。

    • Parcel的nativeReadStrongBinder最后被绑定到native层的android_os_Parcel_readStrongBinder上(android_os_Parcel.cpp).

    • 进一步调用了android_util_binder的javaObjectForIBinder(JNIEnv* env, const sp& val)

    • 在这个函数里可以发现最重要的一部: object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);, gBinderProxyOffsets.mClass是在哪里赋值呢? 就是在int_register_android_os_BinderProxy这个绑定java层BinderProxy的函数里,相应赋值语句是gBinderProxyOffsets.mClass = (jclass) env->NewGlobalRef(clazz);,这里的clazz就是clazz = env->FindClass(kBinderProxyPathName, 就是“android/os/BinderProxy”);

    • 这里就是很清晰了,本地通过在Parcel里填充一个Binder对象并发给远端来实现通信,远端通过Parcel的readStrongBinder得到的其实是一个远端本地new出来的BindProxy对象, 而这个BindProxy对象又和本地的Binder对象可以通信(transact/onTranscat).

    • 从上面可以看出,在远端通过Parcel的readStrongBinder得到一个IBinder对象用来向本地transact数据时,这个IBinder对象其实就是一个远端本地的BinderProxy对象.

    • 那么通过transact发送数据其实调用的就是BinderProxy的transact:

      • 这个函数也是native实现的: android_os_BinderProxy_transact

      • 这个函数中最终调用的是target->transact(…)

      • 而target其实是(IBinder*) env->GetIntField(obj, gBinderProxyOffsets.mObject) 拿到的.

      • gBinderProxyOffsets.mObject其实也是在int_register_android_os_BinderProxy中初始化的,对应的是Java层BinderProxy的mObject对象成员(一个int型,因为其实保存的是native层的一个对象).

      • 也就是说target其实是BinderProxy中的mObject,而且这个对象是int型的,其实就是native层一个IBinder对象的指针地址, 最终的transact其实还是在native层发生的: target->transact(code, *data, reply, flags).

      • 那么这个target是什么时候被设置的呢?就是上面说的在readStrongBinder调用的javaObjectForIBinder中,javaObjectForIBinder有一个输入参数是const sp& val, 这个值会被塞进new出来的BinderProxy的mObject中.

      • 进一步这个val值在Pacel.cpp中是通过readStrongBinder()->unflatten_binder(ProcessState::self(), *this, &val(被赋结果值))

      • unflatten_binder和flatten_binder类似与反序列化和序列化. writeStrongBinder对应的就是flatten_binder(ProcessState::self(), val, this).

      • 在android_os_BinderProxy_transact中调用的target其实是一个BpBinder,而不是BBinder

      • BpBinder中的transact函数调用的就是IPCThreadState::self()->transact(mHandle int32_t,知道和谁通信的关键, code, data, reply, flags), mHandler是在构造时就初始化了. 而BpBinder的new也只在ProcessState的getStrongProxyForHandle(handle)/getWeakProxyForHandle(int32_t handle)被调用. 如果Bpbinder不是alive的,那么会返回DEAD_OBJECT.

      • 继续跟踪IPCThreadState的transact(…) -> writeTransactionData(…), 同时如果不是ONE_WAY的话,还需要等待response(waitForResponse(…)).

      • writeTransactionData: 将handle/code等信息填充到一个binder_transaction_data对象,注意这里的cmd是BC_TRANSACTION表示是一个Transaction而不是reply(BC_REPLY), 将cmd和binder_transaction_data对象写入到mOut中(private Parcel是一个对象而非指针不需要再new来构建).

      • IPCThreadState的构造函数接受一个关键值作为自己的mProcess: ProcessState::self(), 而后者返回的是一个ProcessState全局单例对象, 可以认为每个进程只有一个,并且是lazy-init的.

      • 那么就要跟踪到ProcessState的构造函数了,看着好像啥都没干,其实有一个很重要的点是在初始化列表里面调用的:mDriverFD(open_driver()).

      • ProcessState::open_driver()是一个static函数,其操作是打开了“/dev/binder”这个驱动层的虚拟设备文件, 并且设定了BINDER的version和binder的max thread数量.然会返回打开的设备文件的fd保存在自己的mDriverFD中.

      • ProcessState的初始化一般都会在Service init的时候就被调用,并且会调用其startThreadPool()来生成线程池 -> spawnPooledThread(…)可以看到new了一个PoolThread,而该PoolThread的操作则是: IPCThreadState::self()->joinThreadPool(mIsMain)调用当前线程的joinThreadPool(…), 会传入一个isMain参数来标示是否是主线程, 在哪个线程上调用了ProcessState的spawnPooledThread,就会启动一个线程,将这个线程上的IPCThreadState对象进行joinThreadPool. PooledThread继承自Thread(Threads.cpp中定义),这个类通过在run()中调用androidCreateRawThreadEtc创建了一个Thread(pthread_create), 这个线程运行的函数则是 内部定义的 _threadLoop,_threadLoop里面有一个doWhile循环不断的调用Thread对象的threadLoop函数(PooledThread就是在override了,调用了IPCThreadState的joinThreadPool())

      • IPCThreadState的joinThreadPool本质就是一个do while循环,只有在ECONNREFUSED/EBADF/TIMED_OUT/不是主线程时才会break. 循环里面调用的是IPCThreadState::getAndExecuteCommand().

      • getAndExecuteCommand()里面的重要操作是talkWithDriver()和executeCommand(cmd).

      • talkWithDriver(…)里没有显式的IO函数调用,因为用的是驱动层自定义的ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr), 里面的bwr是一个binder_write_read对象,即包含了要write的数据,也包含了要read数据的存放地,一次操作,一个do while不断的调用这个过程,遇到EINTR也会继续,直到遇上了其他错误,在这一次循环结束以后,会将mOut中发送出去的数据清除,将read到的数据填充到mIn中

      • executeCommand(int32_t cmd)就简单了,根据上面得到mIn的数据进行操作并写将回应写回到mOut中.

      • 不过写出去的数据是如何送到对端之类的实现,还需要看binder驱动层的实现.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值