架构之Binder 核心原理(二)

架构之Binder 核心原理(一)

  1. 打开binder设备:
    service_manager.c 源码中:

        if (argc > 1) {
        driver = argv[1];
        } else {
            driver = "/dev/binder"; //打开binder设备文件,返回文件描述符
        }
    
        bs = binder_open(driver, 128*1024); // binder 的 buffer缓冲区创建,用于进程间数据的传输 
    
  2. 打开一个binder设备文件,并且开启一个128k的内存映射。
    binder.c 有内存映射mmap()函数调用

        bs->fd = open(driver, O_RDWR | O_CLOEXEC); // 打开binder设备
        // ...
        bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); // 开启内存映射
    

    mmap 函数是在系统启动的时候就开启了binder映射,查看源码System.map
    在这里插入图片描述

  3. ServiceManager启动
    init.rc中启动ServiceManager服务
    在这里插入图片描述

  4. 打包Parcel中,数据写入binder设备,copy_from_user

    • IServiceManager.cpp源码中,搜索addService
          virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                      bool allowIsolated, int dumpsysPriority) {
              Parcel data, reply; //parcel对象,将Service相关的信息打包
              data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
              data.writeString16(name);
              data.writeStrongBinder(service);
              data.writeInt32(allowIsolated ? 1 : 0);
              data.writeInt32(dumpsysPriority);
              status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
              return err == NO_ERROR ? reply.readExceptionCode() : err;
          }
      
      parcel对象,将Service相关的信息打包到parcel对象,并且通过remote()->transact方法传输到下一步,
    1. 如何将数据写入binder设备,查看IIPCThreadState.cpp源码,IPCThreadState.h
      err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
      
  5. 服务注册,添加到链表svclist中

    int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle,
                       uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid) {
        struct svcinfo *si;
    
        //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
        //        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
    
        if (!handle || (len == 0) || (len > 127))
            return -1;
    
        if (!svc_can_register(s, len, spid, uid)) {//检查服务权限,
            ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
                 str8(s, len), handle, uid);
            return -1;
        }
    
        si = find_svc(s, len);//检查服务是否已经在svclist链表上注册过
        if (si) {
            if (si->handle) {
                ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                     str8(s, len), handle, uid);
                svcinfo_death(bs, si);
            }
            si->handle = handle;
        } else {
            si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); //没有注册过,分配服务管理结构svcinfo,并将其添加到链表的list当中。
            if (!si) {
                ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
                     str8(s, len), handle, uid);
                return -1;
            }
            si->handle = handle;
            si->len = len;
            memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
            si->name[len] = '\0';
            si->death.func = (void*) svcinfo_death;
            si->death.ptr = si;
            si->allow_isolated = allow_isolated;
            si->dumpsys_priority = dumpsys_priority;
            si->next = svclist; //将代表该服务的结构添加到链表中
            svclist = si;
        }
    
        binder_acquire(bs, handle); // 增加binder的应用 计数
        binder_link_to_death(bs, handle, &si->death);//如果服务退出之后,就需要通知ServiceManager
        return 0;
    }
    

    以上整个过程,就是Server如何向ServerManager添加服务的注册过程。

  6. 定义主线程的线程池,不停地读写
    查看IIPCThreadState.cpp源码

    		void IPCThreadState::joinThreadPool(bool isMain)
    		{
    		    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
    		
    		    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    		
    		    status_t result;
    		    do {
    		        processPendingDerefs();
    		        // now get the next command to be processed, waiting if necessary
    		        result = getAndExecuteCommand();
    		
    		        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
    		            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
    		                  mProcess->mDriverFD, result);
    		            abort();
    		        }
    		
    		        // Let this thread exit the thread pool if it is no longer
    		        // needed and it is not the main process thread.
    		        if(result == TIMED_OUT && !isMain) {
    		            break;
    		        }
    		    } while (result != -ECONNREFUSED && result != -EBADF);
    		
    		    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
    		        (void*)pthread_self(), getpid(), result);
    		
    		    mOut.writeInt32(BC_EXIT_LOOPER);
    		    talkWithDriver(false);
    		}
    
  7. 循环从mIn mOut中取出读写请求,发送的binder的设备中

    		    pthread_setspecific(gTLS, this); //将对象设置为当前线程的私有
    		    clearCaller();
    		    mIn.setDataCapacity(256); //输入分配256字节的空间
    		    mOut.setDataCapacity(256);//输出分配256字节的空间
    

    输入/出 预分配256字节的空间,主要工作循环从mIn mOut中进行IO的读写工作,然后发送的binder的设备中来。

    继续往下,是如何检查是否有数据要读?

    		    binder_write_read bwr;
    		
    		    // Is the read buffer empty?
    		    const bool needRead = mIn.dataPosition() >= mIn.dataSize(); //检查是否有读数据的请求
    		
    		    // We don't want to write anything if we are still reading
    		    // from data left in the input buffer and the caller
    		    // has requested to read the next data.
    		    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0; // //检查是否有写数据的请求
    		    		// 省略代码....
    		        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) //将读写的请求 发送到binder中来
    		            err = NO_ERROR;
    		        else
    		            err = -errno;
    

平时项目中,碰到的第三方登录,分享。实际就是跨进行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值