美文网首页
Java 层添加服务

Java 层添加服务

作者: Wi1ls努力努力再努力 | 来源:发表于2019-10-30 21:04 被阅读0次

    以 AMS 为例
    //ActivityManagerService.java

    public void setSystemProcess( ){
      ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
    }
    

    //ServiceManager.java

    public static addService(String name, IBinder service, boolean allowIsolated){
      getIServiceManager( ).addService(name, service, allowIsloted)
    }
    
    private static IServiceManager getIServiceManager(){
      sServiceManager = ServiceManagerNative.getInterface(BinderInternal.getContextObject);
    }
    

    //android_utils_Binder.cpp

    //该方法返回一个 Java 层的BinderProxy 对象,同时持有下面的 BpBinder(handle = 0)的句柄
    static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){
      sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
      return javaObjectForIBinder(env, b);
    }
    

    //ProcessState.cpp

    //改方法返回一个 BpBinder(handle = 0)
    sp<IBinder> ProcessState::getContextObject(const sp<IBinder>&){
      return getStrongProxyForHandle(0);
    }
    

    //ServiceManagerNative.java

    static public IServiceManager asInterface(IBinder obj){
      return new ServiceManagerProxy(obj)
    }
    

    经过一系列的反应,最后再 AMS 进程中,service_manager 在 AMS 中的代理表现为

    ServiceManagerNativeServiceManagerProxy.java 对象,该对象内部有一个 mRemote 成员变量表现为BinderProxy.java对象。BinderBidnerProxy.java 对象内部有成员变量 mObject,表现为 native 层BpBinder.cpp对象。BpBinder.cpp 对象内部有一个 handle 为0,表示 service_manager 在 binder 驱动中的注册编号

    --重头戏---

    addService( )@ServiveManager.java
    ⤵️
    addService( )@ServiceManagerNative$ServiceManagerProxy.java
    ⤵️
    transact(ADD_SERVICE_TRANSACTION)@Binder$BinderProxy.java
    ⤵️
    android_os_BinderProxy_transact()@android_util_Binder.cpp
    ⤵️
    transact( )@BpBinder.cpp
    ⤵️
    transact( )@IPCThreadState.cpp
    ⤵️
    ioctl()@IPCThreadState.cpp使用的 cmd 就是 BINDER_WRITE_READ
    

    接下来看每一层的数据打包过程。

    //参数,name = "activity", service 是 ActivityManagerService, allowIsolated=true
    public void addService(String name,IBinder service, boolean allowIsolated){
      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( );
    }
    

    关于 Parcel 打包,参见link
    此时 Parcel data 打包了一些基础数据类型,将 ActivityManagerService.java 封装成了 flat_binder_object 打包进 Parcel。
    //BinderProxy

    //code 就是 ADD_SERVICE_TRANSACT, data 是封装了请求信息,reply 没有内容,flags=0
    public boolean transact(int code, Parcel data, Parcel reply, int flags){
      return transactNative(code, data, reply, flags)
    }
    

    //android_utils_Binder.cpp

    static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, jint code, jobject dataObject, jobject replyObj, jint flags){
      //从 Parcel.java 中的 mNativePtr 获得 native 层的 Parcel.cpp
      Parcel* data = parcelForJavaObject(env, dataObj);
      Parcel* reply = parcelForJavaObject(env, replyObj);
      //从 BinderProxy.java 获得 BpBinder
      //此处 BpBinder 中的 handle = 0,代表 service_manager
      IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
    
      status_t err = target->transact(code, *data, reply, flags)
    }
    

    //BpBinder.cpp

    status BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
      status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply. flags);
    }
    

    //IPCThreadState.cpp

    status_t IPCThreadState::transact(int32_t handle, uint32_T code, const Parcel& data, Parcel* reply, uint32_t flags){
      //表示通讯 cmd 是 BC_TRANSACTION,表示向 Binder 驱动发送消息
      //handle = 0 表示向 handle = 0 的服务,即 service_manager 发送消息
      //code = ADD_SERVICE,该码用来给目标服务表示要调用的方法
      //data 包含了请求的参数
      //于是 handle,code,data 包含了目标对象,目标方法,方法参数
      writeTransactionData(BC_TRANSACTION, flags, handle, code, data);
      //真正发起 RPC 通讯
      waitForResponse(reply)
    }
    
    status_t IPCThreadStatus::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer){
      //IPCThreadStatus 层的包装协议是 binder_transaction_data,在目标进程也按照该协议进行拆箱
      //cmd = BC_TRANSACTION 是该层的命令协议
      //封装的 binder_transaction_data 连同 cmd 打包进了 mOut
      binder_transaction_data tr;
    
      tr.target.ptr = 0;
      tr.target.handle = handle;
      tr.code = code;
      tr.flags = binderFlags;
      tr.cookie=0
      tr.sender_pid = 0;
      tr.sender_euid = 0;
      tr.data_size = data.ipcDataSize( );
      tr.data.ptr.buffer = data.ipcData();
      tr.offsets_size = data.ipcObjecCount()*sizeof(binder_size_t);
      tr.data.ptr.offet = data.ipcObjects( );
    
      mOut.writeInt32(cmd)
      mout.write(&tr, sizeof(tr))
    }
    
    status_t IPCThreadStatus::waitForResponse(Parcel * reply, status_t *acquireResult){
      //进行 PRC
      talkWithDriver();
      //处理 RPC 返回结果
      ...
    }
    
    status_t IPCThreadStatus::talkWithDriver(boolean doReceive){
      //与 Binder 驱动交换数据
      binder_write_read bwr;
      bwr.write_siez = outAvail;
      bwr.write_buffer = (uintptr_t)mOut.data()
      ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
    }
    
    • 一级通讯 cmd 为 BINDER_WRITE_READ,像 Binder 驱动表示此次 RPC 需求读写内容
    • 二级 cmd 为 BC_TRANSACTION
    • 三级 cmd 为 ADD_VERSION

    接下来看通讯的解包装
    //binder.c,此时是在 kernel中运行

    static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long args){
      //获得发起请求的进程 binder_proc 结构
      struct binder_proc *proc = filp->private_data;
      struct binder_thread *thread;
      //用户空间的 binder_write_read 的指针
      void __user *ubuf = (void __user *)arg;
      //kernal将当前进程,即发起请求的进程进行休眠。直到被唤醒
      //如果 binder_stop_on_user_error < 2则直接跳过不会挂起
      wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error <2);
      //获得发起 RPC 请求的现场
      thread = binder_get_thread(proc);
      switch(cmd){
      //符合一级通讯 cmd
      case BINDER_WRITE_READ{
        struct binder_write_read bwr;
        //将用户进程的 binder_write_read 拷贝到内核空间
        copy_from_user(&bwr, ubuf, sizeof(bwr))
        //本次请求符合
        if(bwr.write_size >0){
            binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
        }
      }
      }
    }
    
    int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed){
      uint32_t cmd;
      void __user *buffer = (void __user *)(uintptr_t) binder_buffer;
      void __user *ptr = buffer+*consumed;//此时指针子 bwr 中 write_buffer 的 data
      void __user *end = buffer+size
      swicth(cmd){
        //二级通讯 cmd
       case BC_TRANSACTION:
        binder_transaction_data tr;
        //再次拆箱,拆出 binder_transaction_data
        copy_from_user(&tr, ptr, sizeof(tr));
        //真正发起 RPC,这里可以看到,binder 驱动将 BC_TRANSACTION换成了 BC_REPLY
        binder_transaction(proc, thread, &tr, cmd = BC_REPLY);
      }
    }
    

    binder_transaction( )函数格外复杂。简而言之是根据请求中目标进程的 handle(此处为 0),多啰嗦一句,所有的 Binder 实体经过 Binder 驱动,都会被记录到一个 binder_node 节点并且插入到 Binder 驱动的 2 颗红黑树(key 不同)。在这里因为 handle 为 0,于是找到对应的 Binder 实体对应的进程,随后创建一个事务binder_transaction,将其挂载到目标进程 traget_list 即 todo 队列。随后唤醒目标进程。

    在此处,调用wait_event_interruptible()尝试休眠 AMS 进程是,因为 binder_stop_on_user_error < 2成立,因此不会休眠进程。在进行binder_thread_write()进行 rpc 调用后,在binder_thread_read()会通过wait_event_freezable_exclusive()休眠当前线程,知道 service_manager.cpp 返回请求结果。
    而 service_manager.cpp 进入 loop 后,就是一直阻塞在binder_thread_read()中的wait_event_freezable_exclusive()去尝试获取请求。当 binder_has_proc_work()符合条件,即进程所造的 todo 队列有内容,才会唤醒。
    当 AMS 将此次 RPC 请求投递到 service_manager.cpp 所在的 todo 队列,service_manager.cpp 就会被唤醒,读取处理请求。同事 AMS 会在wait_event_freezable_exclusive()挂起线程,直到有某个事务(其他进程或者 service_manager.cpp 返回了结果)被投递到 AMS 进程所在的 todo 队列


    Binder 的通讯大致过程都相似,如果是同步请求 A 进程像 Binder 发送 RPC,内核休眠 A 进程,唤醒目标 B 进程,处理请求,回复 Binder 驱动,唤醒 A 进程。

    相关文章

      网友评论

          本文标题:Java 层添加服务

          本文链接:https://www.haomeiwen.com/subject/yepavctx.html