Binder系列--ServiceManager的启动

ServiceManager的启动
hongxi.zhu
Android 13

主要流程:
在这里插入图片描述

1. 启动ServiceManager进程

ServiceManager是由init(pid = 1)进程启动的
system/core/rootdir/init.rc

on init......# Start essential services.start servicemanager  //framework层使用start hwservicemanager  //hal层start vndservicemanager  //vendor内部

进程被创建后,进入main方法

2. 执行main方法

frameworks/native/cmds/servicemanager/main.cpp

int main(int argc, char** argv) {...const char* driver = argc == 2 ? argv[1] : "/dev/binder";sp<ProcessState> ps = ProcessState::initWithDriver(driver); //创建ProcessState对象(进程唯一),并进行open、ioctl、mmap操作ps->setThreadPoolMaxThreadCount(0);  //初始线程数实际为0ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());  //构造自己时构造Access对象,这个是用于权限检测//先注册自己作为服务if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {LOG(ERROR) << "Could not self register servicemanager";}IPCThreadState::self()->setTheContextObject(manager); //保存ServiceManager作为BBinder对象到IPCThreadState实例中ps->becomeContextManager();  //向驱动注册自己成为全局唯一的ContextManager,全局只有一个ServiceManagersp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/); //获取一个LooperBinderCallback::setupTo(looper);  //将binder fd添加到Looper中监听,当驱动有事件时,回调handleEvent()处理ClientCallbackCallback::setupTo(looper, manager);  //这个是用于告知客户端当前服务端有多少个客户端绑定的回调监听while(true) {  //循环等待事件到来looper->pollAll(-1);  //阻塞等待event的到来,然后进行ioctl和驱动交互获取数据}// should not be reachedreturn EXIT_FAILURE;
}
  1. 创建ProcessState对象,通过这个对象打开驱动节点,检验Binder版本和进行内存映射等操作,
  2. 设置线程池的初始大小为0,实际线程数并不是固定的,这个要根据实际任务决定是否新加线程到线程池(binder驱动中处理这个逻辑
  3. 然后创建ServiceManager对象,并通过addService添加自己到服务列表中。
  4. 保存ServiceManager作为BBinder对象到IPCThreadState实例中,并向Binder驱动注册自己成为全局唯一的ContextManager
  5. 然后创建Looper,通过Looper监听binder驱动的消息,当驱动有消息时回调handleEvent()处理(然后真正读数据是ioctl)
  6. 进入大循环阻塞等待事件到来

3. ProcessState::initWithDriver(driver)

frameworks/native/libs/binder/ProcessState.cpp

sp<ProcessState> ProcessState::initWithDriver(const char* driver)
{return init(driver, true /*requireDefault*/);
}sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{...[[clang::no_destroy]] static std::once_flag gProcessOnce;std::call_once(gProcessOnce, [&](){  //call_once单例模式确保每个进程只有一个ProcessStateif (access(driver, R_OK) == -1) {  //测试下binder的节点是否可读ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);driver = "/dev/binder";}...std::lock_guard<std::mutex> l(gProcessMutex);gProcess = sp<ProcessState>::make(driver);  //调用构造函数,构造ProcessState实例});...return gProcess;
}#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)  //ServiceManager申请用于binder通信的虚拟内存大小也是 1MB-8KB
#define DEFAULT_MAX_BINDER_THREADS 15   //最大工作线程数 15 + 1(本身)
#define DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION 1  //开启异步垃圾通信检测
...
ProcessState::ProcessState(const char* driver): mDriverName(String8(driver)),mDriverFD(-1),mVMStart(MAP_FAILED),mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),mThreadCountDecrement(PTHREAD_COND_INITIALIZER),mExecutingThreadsCount(0),mWaitingForThreads(0),mMaxThreads(DEFAULT_MAX_BINDER_THREADS),mStarvationStartTimeMs(0),mForked(false),mThreadPoolStarted(false),mThreadPoolSeq(1),mCallRestriction(CallRestriction::NONE) {base::Result<int> opened = open_driver(driver);  //进行open、ioctlif (opened.ok()) {// mmap the binder, providing a chunk of virtual address space to receive transactions.mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,opened.value(), 0);if (mVMStart == MAP_FAILED) {close(opened.value());// *sigh*opened = base::Error()<< "Using " << driver << " failed: unable to mmap transaction memory."; //内存不足mDriverName.clear();}}...
}

构造方法里做的最主要的两件事就是通过open_driver()mmap()

3.1 open_driver

static base::Result<int> open_driver(const char* driver) {int fd = open(driver, O_RDWR | O_CLOEXEC);  //通过open打开binder节点,获取binder设备驱动的fd...int vers = 0;status_t result = ioctl(fd, BINDER_VERSION, &vers);  //通过ioctl和binder驱动通信,查询binder驱动的binder版本,binder驱动的版本要和用户空间的binder协议的版本保持匹配,不然无法工作...size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;  //DEFAULT_MAX_BINDER_THREADS = 15result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);  //通过ioctl告知binder驱动,用户进程支持的最大binder工作线程数,默认是15+1 = 16个(加上本身)...uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);  //开启oneway方式垃圾请求攻击检测(类似于垃圾邮件攻击检测)...return fd;  //返回驱动的fd
}

open_driver主要做四件事:

  1. 通过系统调用open打开设备节点,获取设备驱动fd
  2. 通过系统调用ioctl获取驱动的binder版本
  3. 通过系统调用ioctl告知驱动用户进程支持的最大线程数,(默认是15+1,SystemServer进程默认是31+1)
  4. 通过系统调用ioctl设置垃圾oneway异步通信检测

3.2 mmap

		...if (opened.ok()) {// mmap the binder, providing a chunk of virtual address space to receive transactions.mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,opened.value(), 0);  //BINDER_VM_SIZE = 1MB-8KBif (mVMStart == MAP_FAILED) {close(opened.value());// *sigh*opened = base::Error()<< "Using " << driver << " failed: unable to mmap transaction memory."; //内存不足(没有满足需求的连续内存)mDriverName.clear();}}...

ProcessState构造函数接着会通过系统调用mmap将当前进程的一块虚拟内存(内核分配的虚拟地址,这个地址是进程地址空间的)映射到内核空间,这个系统调用最终实现是binder驱动中的binder_mmap(), binder驱动会在内核也申请一块空间(内核空间),并指向一块物理地址,注意这个仅仅用在这个进程作为服务端时,接收来自binder的消息,这个过程没有发生IO的拷贝。

4. setTheContextObject

void IPCThreadState::setTheContextObject(const sp<BBinder>& obj)
{the_context_object = obj;
}

保存ServiceManager作为BBinder对象到IPCThreadState实例中(这样处理其他进程获取SM时就不需要每次都创建BBinder的对象)

5. becomeContextManager

bool ProcessState::becomeContextManager()
{AutoMutex _l(mLock);flat_binder_object obj {.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,};int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);  //注册自己成为ContextManager...return result == 0;
}

向驱动注册自己成为全局唯一的SM

6. BinderCallback::setupTo(looper)

class BinderCallback : public LooperCallback {  //继承于LooperCallback,当Looper通过epoll监听到对应fd有event时回调cb.handleEvent
public:static sp<BinderCallback> setupTo(const sp<Looper>& looper) {sp<BinderCallback> cb = sp<BinderCallback>::make();   //创建BinderCallback对象int binder_fd = -1;IPCThreadState::self()->setupPolling(&binder_fd);LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);int ret = looper->addFd(binder_fd,  //添加binder驱动的fd到Looper的监听fdLooper::POLL_CALLBACK,Looper::EVENT_INPUT,cb,  //传递自己作为callback对象,有event就回调自己的handleEvent方法nullptr /*data*/);LOG_ALWAYS_FATAL_IF(ret != 1, "Failed to add binder FD to Looper");return cb;}int handleEvent(int /* fd */, int /* events */, void* /* data */) override {IPCThreadState::self()->handlePolledCommands();  //驱动有事件上报时,就去处理return 1;  // Continue receiving callbacks.}
};

将binder驱动的fd注册到Looper中监听,当驱动上报事件时回调handleEvent, 处理相关事务

6.1 setupPolling

status_t IPCThreadState::setupPolling(int* fd)
{if (mProcess->mDriverFD < 0) {return -EBADF;}mOut.writeInt32(BC_ENTER_LOOPER);flushCommands();*fd = mProcess->mDriverFD;return 0;
}void IPCThreadState::flushCommands()
{if (mProcess->mDriverFD < 0)return;talkWithDriver(false);  //通过ioctl 通知驱动将当前线程加入Looper状态...
}

通过ioctl通知驱动将当前线程加入Looper状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/3356.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS distribution发布证书过期或者被手动revoke了app会被下架吗?

在距离distribution 证书过期一个月&#xff08;或被手动revoke了&#xff09;的时候会受到apple的邮件 虽然distribution过期&#xff08;或者被手动revoke&#xff09;了&#xff0c;如果你的开发者账号是company&#xff08;公司&#xff09;类型或个人类型的&#xff0c;只…

【youcans动手学模型】MobileNet 模型-CIFAR10图像分类

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【youcans动手学模型】MobileNet 模型-CIFAR10图像分类 1. MobileNet 卷积神经网络模型1.1 模型简介1.2 论文介绍 2. 在 PyTorch 中定义 MobileNet V1 模型类2.1 深度可分离卷积&#xff08;DSC&…

PHP 的 Logo 为什么是大象?

因为大象是世界上最好的动物。 当然&#xff0c;这只是开玩笑&#xff0c;那么为什么PHP的LOGO是大象呢&#xff1f;还有哪些关于PHP的LOGO的有趣的事情呢&#xff1f; 吉祥物-大象 ElePHPant 是一款可爱的 PHP 吉祥物&#xff0c;其设计中有一头大象。 最初的LOGO 1998 年…

高斯过程(Gaussian Process)回归预测,例子,代码及可视化展示

高斯过程指的是一组随机变量的集合&#xff0c;这个集合里面的任意有限个随机变量都服从联合正态分布。&#xff08;联合正态分布是指多个随机变量的联合分布满足正态分布。联合分布是指多个随机变量同时满足的概率分布&#xff0c;一个常见的例子是考虑两个随机变量&#xff1…

如何在 Spring Boot 中使用 WebMvc

如何在 Spring Boot 中使用 WebMvc 引言 Spring Boot 是一个快速、简单的开发框架&#xff0c;可以帮助我们快速地搭建一个基于 Spring 的 Web 应用程序。在 Spring Boot 中&#xff0c;我们可以使用 WebMvc 来构建 Web 应用程序。WebMvc 是 Spring 框架中的一个模块&#xf…

让集合数据操控指尖舞动:迭代器和生成器的精妙之处

文章目录 &#x1f499;迭代器&#xff08;Iterator&#xff09;迭代器的特点&#xff1a;迭代器的优点&#xff1a;代码案例&#xff1a; &#x1f49a;生成器&#xff08;Generator&#xff09;生成器的特点&#xff1a;生成器的优点&#xff1a;代码案例&#xff1a; &#…

python自动化办公——定制化将电子签名批量签写到PDF文件

python自动化办公——定制化将电子签名批量签写到PDF文件 文章目录 python自动化办公——定制化将电子签名批量签写到PDF文件1、安装依赖2、需求分析3、代码 1、安装依赖 首先需要下载所需要的库 pip install pdf2image pip install img2pdf pip install opencv-python此外还…

Linux系统中的信号

信号是由用户、系统或者进程发送给目标进程的信息&#xff0c;以通知目标进程某个状态的改变或系统异常。Linux信号可由如下条件产生&#xff1a; 对于前台进程&#xff0c;用户可以通过输入特殊的终端字符来给它发送信号。比如输入CtrlC通常会给进程发送一个中断信号&#xf…

charles unknown 问题和手机代理设置(iOS手机)

一、Charles下载 下载地址&#xff1a;https://www.charlesproxy.com/download/ 二、Charles配置代理 1.查看本机IP&#xff1a;help-->Local IP Address 2.查看或者设置访问端口&#xff1a;Proxy->Proxy Settings 3.设置不代理计算机的请求&#xff08;推荐&#xff0…

【NLP】Attention机制和RNN

一、说明 循环神经网络是深度学习的主要内容之一,它允许神经网络处理文本、音频和视频等数据序列。它们可用于将序列简化为高级理解、注释序列,甚至从头开始生成新序列! 二、引进长记忆网络 基本的 RNN 设计很难处理较长的序列,但一种特殊的变体——“长短期记忆”网络 [1]…

蓝桥杯专题-试题版-【操作格子】【查找整数】【分解质因数】【高精度加法】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

爬虫入门指南(5): 分布式爬虫与并发控制 【提高爬取效率与请求合理性控制的实现方法】

文章目录 前言多线程与多进程多线程多进程多线程和多进程的选择 使用Scrapy框架实现分布式爬虫1. 创建Scrapy项目2. 配置Scrapy-Redis3. 创建爬虫4. 启动爬虫节点5. 添加任务到队列 并发控制与限制请求频率并发控制限制请求频率 未完待续... 前言 在进行爬虫任务时&#xff0c;…