• Treble 架构之 HwServiceManager


    HAL ServiceManager main

    
    int main() {
        // 配置 binder驱动线程池数量
        // 实现在 libhwbinder/ProcessState.cpp 中
        // 配置线程池数量为 1, 简单的说,就是 不允许binder驱动在创建线程了  
        // size_t kernelMaxThreads = maxThreads - 1;
        configureRpcThreadpool(1, true /* callerWillJoin */);
    
    
        sp<ServiceManager> manager = new ServiceManager();
        setRequestingSid(manager, true);
    
        if (!manager->add(serviceName, manager)) {
            ALOGE("Failed to register hwservicemanager with itself.");
        }
    
        TokenManager *tokenManager = new TokenManager();
    
        if (!manager->add(serviceName, tokenManager)) {
            ALOGE("Failed to register ITokenManager with hwservicemanager.");
        }
    
        // 创建 Looper
        sp<Looper> looper(Looper::prepare(0 /* opts */));
    
        int binder_fd = -1;
        // 获取binder fd 并往binder驱动 写入 BC_ENTER_LOOPER
        IPCThreadState::self()->setupPolling(&binder_fd);
        if (binder_fd < 0) {
            ALOGE("Failed to aquire binder FD. Aborting...");
            return -1;
        }
        // Flush after setupPolling(), to make sure the binder driver
        // knows about this thread handling commands.
        IPCThreadState::self()->flushCommands();
    
        // 当有数据到达时,就会回调 BinderCallback处理数据
        sp<BinderCallback> cb(new BinderCallback);
        if (looper->addFd(binder_fd, Looper::POLL_CALLBACK, Looper::EVENT_INPUT, cb,
                nullptr) != 1) {
            ALOGE("Failed to add hwbinder FD to Looper. Aborting...");
            return -1;
        }
    
        // Tell IPCThreadState we're the service manager
        sp<BnHwServiceManager> service = new BnHwServiceManager(manager);
        IPCThreadState::self()->setTheContextObject(service);
        // Then tell binder kernel
        flat_binder_object obj {
            .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
        };
    
        status_t result = ioctl(binder_fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
    
        // fallback to original method
        if (result != 0) {
            android_errorWriteLog(0x534e4554, "121035042");
    
            result = ioctl(binder_fd, BINDER_SET_CONTEXT_MGR, 0);
        }
    
        // Only enable FIFO inheritance for hwbinder
        // FIXME: remove define when in the kernel
    #define BINDER_SET_INHERIT_FIFO_PRIO    _IO('b', 10)
    
        int rc = ioctl(binder_fd, BINDER_SET_INHERIT_FIFO_PRIO);
        if (rc) {
            ALOGE("BINDER_SET_INHERIT_FIFO_PRIO failed with error %d
    ", rc);
        }
    
        // Hw ServicveMananger 启动就绪
        rc = property_set("hwservicemanager.ready", "true");
        if (rc) {
            ALOGE("Failed to set "hwservicemanager.ready" (error %d). "
                  "HAL services will not start!
    ", rc);
        }
    
        // 进入循环。
        while (true) {
            looper->pollAll(-1 /* timeoutMillis */);
        }
    
        return 0;
    }
    
    
    1. 打开binder驱动

      configureRpcThreadpool(1, true /* callerWillJoin */);
      

      就这简单的一句,做了如下工作:

      • 限制了当前进程的线程数量。binder驱动不能再通过BR_SPAWN_LOOPER创建子线程了,简单的说就是整个ServiceManager进程只有一个主线程。没有其他线程了。

      • 打开bidner驱动。

        static int open_driver()
        {
            int fd = open("/dev/hwbinder", O_RDWR | O_CLOEXEC);
        	size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;			// 0
        	result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
            return fd;
        }
        
    2. 创建ServiceManager对象

      创建过程也很简单,关于ServiceManger是如何管理注册过来的服务的,见ServiceManager的解析,这里不表。

    3. 创建TokenManager对象

      作用我还不清楚。

    4. 创建Looper对象

      这个是Java Looper的底层实现吧,MessageQueue的核心。通过epoll实现,通过addFd方法将文件描述符注册到Looper后,当有读写等事件到来时,就会调用回调函数(对应这里的BinderCallback)。

    5. 创建BnHwServiceManager,并设置为Context Object。

      虽然创建了BnHwServiceManager对象,但是并没有将其传递到驱动中去生成binder_node。由于设置成为了conetext,驱动根据binder_proc->context就能直接找到该进程。然后将发送给BpHwBinder::mHandler == 0的请求都交由我们的Service Manager进程处理。

    6. 设置就绪属性,并进入循环

      设置属性的作用是defaultServiceManager需要等待ServiceManager就绪。

      
      static const char* kHwServicemanagerReadyProperty = "hwservicemanager.ready";
      // ProcessState::self()->getContextObject(NULL) 前调用
      void waitForHwServiceManager() {
          using std::literals::chrono_literals::operator""s;
      
          while (!WaitForProperty(kHwServicemanagerReadyProperty, "true", 1s)) {
              LOG(WARNING) << "Waited for hwservicemanager.ready for a second, waiting another...";
          }
      }
      

    前面提到,当数据到来时,Looper会回调BinderCallback处理数据,看一下其实现:

    class BinderCallback : public LooperCallback {
    public:
        BinderCallback() {}
        ~BinderCallback() override {}
    
        int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
            IPCThreadState::self()->handlePolledCommands();
            return 1;  // Continue receiving callbacks.
        }
    };
    
    // libhwhandle
    status_t IPCThreadState::handlePolledCommands()
    {
        status_t result;
    
        do {
            result = getAndExecuteCommand();
        } while (mIn.dataPosition() < mIn.dataSize());
    
        processPendingDerefs();
        flushCommands();
        return result;
    }
    

    嗯,了解libbinder的都知道接下来的处理流程了:

    处理 BR_TRANSACTION命令字:

    case BR_TRANSACTION:
    {
    	binder_transaction_data& tr = tr_secctx.transaction_data;
    	result = mIn.read(&tr, sizeof(tr));
    	Parcel buffer;
    	buffer.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);
    
    	if (tr.target.ptr) {
    		// We only have a weak reference on the target object, so we must first try to
    		// safely acquire a strong reference before doing anything else with it.
    		if (reinterpret_cast<RefBase::weakref_type*>(
    				tr.target.ptr)->attemptIncStrong(this)) {
                    error = reinterpret_cast<BHwBinder*>(tr.cookie)->transact(tr.code, buffer,
    					&reply, tr.flags, reply_callback);
    				reinterpret_cast<BHwBinder*>(tr.cookie)->decStrong(this);
    		} else {
    		error = UNKNOWN_TRANSACTION;
    		}
    
    	} else {
            error = mContextObject->transact(tr.code, buffer, &reply, tr.flags, reply_callback);
    	}
    	...
    }
    

    重点来了,前面我们执行了IPCThreadState::self()->setTheContextObject(BnHwServiceManager);,所以这里的mContextObject就是BnHwServiceManager

    当驱动知道数据的目的地是Context时,tr.target.ptr 就会被设置为nullptr。所以,最终数据最终都会交由BnHwServiceManager::onTransaction处理。

    BnHwServiceManager有hild-gen自动生成,其内部会生成IServiceManager.hal中定义的函数的通用实现。所谓通用实现就是无关具体的业务逻辑,只处理binder通信过程中,函数参数的打包和解包等操作。具体的实现还是由我们来实现。

    回过头看BnHwServiceManager的创建:

    // Tell IPCThreadState we're the service manager
    sp<BnHwServiceManager> service = new BnHwServiceManager(manager);
    

    其需要传入我们实现的ServiceManager对象manager,所以可以大胆猜测,在其BnHwServiceManager::onTransaction中,最终还是会调用到manager的具体实现的。

    到这里,ServiceManager的启动就分析完了,还有很多细节忽略了。有时间再补充。。。。

    和 Framework ServiceManager的区别

    Framework Service Manager 简称 FSM吧, 那HAl Service Manager就简称为 HSM吧。

    FSM 用C语言实现的,没有用到libbinder库,自身简单的对binder数据进行解析。

    HSM使用C++实现,用到libhwbinder库,和binder的数据交换过程完全屏蔽了,代码看上去清晰了很多,不过前提是了解libhwbinder或者 libbinder,不然,更加一脸懵逼。。。。

  • 相关阅读:
    浅谈系统调用与库函数
    由代码到可执行程序----浅谈程序的编译链接
    初识信号---进程间的交流
    内部排序总结之----选择类排序(选择、堆)
    僵死进程
    父子进程那些事儿
    fok函数
    面试-css样式
    面试-javascript知识
    面试--数据库
  • 原文地址:https://www.cnblogs.com/liutimo/p/14209540.html
Copyright © 2020-2023  润新知