Android13-系统服务大管家-ServiceManager进程-启动篇

news/2025/2/8 22:37:35/

文章目录

  • 关注 ServiceMager 原因
  • ServerManager需要掌握的知识
  • 资料参考
  • ServiceManager 进程启动
    • 启动脚本
    • Native层源码分析
      • main.cpp
      • 流程
      • 打开驱动 initWithDriver
        • init
        • make
        • ProcessState 构造方法
        • open_driver(driver)
      • 注册成Binder服务 addService
      • 注册成Binder服务 becomeContextManager
      • 轮询
      • 解析命令,执行命令
  • 总结


关注 ServiceMager 原因

  • 理解实现的原理

  • Framework层核心内容Service,绝绝大部分离不开ServiceManager的,framework层的各种Service
    都和ServiceManager打交道的。应用层调用系统Service也是和ServiceManager 关联的,

  • 方便后面理解各种Service源码

  • Binder 机制了解 怎么可能不去熟悉ServiceManager

ServerManager需要掌握的知识

资料参考

ServiceManager(Native)启动分析
系统服务大管家-ServiceManager
启动ServiceManager

ServiceManager__29">ServiceManager 进程启动

我们需要从两方面分析,Native层和framework层,本章我们作为 ServiceManager 源码的开篇,仅关注启动相关源码分析
为什么把ServiceManager 启动单独拿出来:方便分析,一步一个脚印理解。

启动脚本

涉及到的相关源码文件

为了方便理解,暂不用实际平台项目作为参考,直接用谷歌一套来check 源码的开篇,仅关注启动相关源码分析
部分路径和平台源码路径不一致很正常,在实际开发中以实际各个OEM厂商源码 位置为准。

在线源码XrefAndroid:
init.rc
servicemanager

/bootable/recovery/etc/init.rc 
/frameworks/native/cmds/servicemanager/servicemanager.rc

源码跟踪

ServiceManager_48">ServiceManager脚本启动位置

ServiceManager是在rc脚本中启动的:

/bootable/recovery/etc/init.rc 中# Start essential servicesstart servicemanager
ServiceManager_57">ServiceManager关联脚本

servicemanager服务定义在frameworks\native\cmds\servicemanager\servicemanager.rc。
可以看到,servicemanger是一个Linux程序,它在设备中的存储路径是/system/bin/servicemanager,源码路径则是/frameworks/native/cmds/servicemanager。

在这里插入图片描述

 service servicemanager /system/bin/servicemanagerclass core animation   #表示这是一个核心服务,系统启动时优先运行user system            # 以 system 用户身份运 group system readproccritical               # 标记为关键服务,如果退出会触发系统重启onrestart restart apexd                             # 如果servicemanager重启 则 apexd也会重启onrestart restart audioserver                       # 如果servicemanager重启 则  audioserveronrestart restart gatekeeperd                       # 如果servicemanager重启 则  audioserveronrestart class_restart --only-enabled main          onrestart class_restart --only-enabled halonrestart class_restart --only-enabled early_haltask_profiles ServiceCapacityLowshutdown critical 

简单介绍下这个文件脚本:
满足条件后执行程序 /system/bin/servicemanager,去Android 下面查看,果然有。
在这里插入图片描述

Native层源码分析

上面已经分析了servicemanager.rc 脚本了,我们看看该模块下的编译文件Android.bp
在这里插入图片描述

cc_binary {
name: "servicemanager",
defaults: ["servicemanager_defaults"],
init_rc: ["servicemanager.rc"],
srcs: ["main.cpp"],
}

这里就定位到了资源文件 main.cpp

main.cpp

     int main(int argc, char** argv) {#ifdef __ANDROID_RECOVERY__android::base::InitLogging(argv, android::base::KernelLogger);#endifif (argc > 2) {LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";}const char* driver = argc == 2 ? argv[1] : "/dev/binder";  //检查输入参数,如果参数为空,则driver为"/dev/binder"sp<ProcessState> ps = ProcessState::initWithDriver(driver);   //创建ProcessState对象(进程唯一),并进行open、ioctl、mmap操作态ps->setThreadPoolMaxThreadCount(0);                 // 设置Binder线程池的最大线程数为0(表示使用默认设置)ps->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";}//保存ServiceManager作为BBinder对象到IPCThreadState实例中IPCThreadState::self()->setTheContextObject(manager);//向驱动注册自己成为全局唯一的ContextManager,全局只有一个ServiceManagerps->becomeContextManager();sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);  //获取一个LooperBinderCallback::setupTo(looper);              //将binder fd添加到Looper中监听,当驱动有事件时,回调handleEvent()处理ClientCallbackCallback::setupTo(looper, manager);      //这个是用于告知客户端当前服务端有多少个客户端绑定的回调监听//循环等待事件到来while(true) {     //阻塞等待event的到来,然后进行ioctl和驱动交互获取数据    looper->pollAll(-1);}// should not be reachedreturn EXIT_FAILURE;}

流程

上面的main方,可以分析Service启动流程的,我们先给出流程图,下一步一步一步分析说明
在这里插入图片描述

上面列举了main方法,给出了流程图,下面具体分析核心方法,具体在启动时候做了哪些动作

打开驱动 initWithDriver

initWithDriver

/frameworks/native/libs/binder/ProcessState.cppsp<ProcessState> ProcessState::initWithDriver(const char* driver){return init(driver, true /*requireDefault*/);}
init
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault){................std::call_once(gProcessOnce, [&](){if (access(driver, R_OK) == -1) {ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);driver = "/dev/binder";}// we must install these before instantiating the gProcess object,// otherwise this would race with creating it, and there could be the// possibility of an invalid gProcess object forked by another thread// before these are installedint ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,ProcessState::childPostFork);LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));std::lock_guard<std::mutex> l(gProcessMutex);gProcess = sp<ProcessState>::make(driver);});......verifyNotForked(gProcess->mForked);return gProcess;}

这里注意核心 内容 方法 make, 就是通过智能指针创建了ProcessState对象,走一遍构造方法。
Sp 关联的强指针-若指针参考

make

先看下make 方法位置和定义,在StrongPointer.h 里面
StrongPointer.h

// TODO: Ideally we should find a way to increment the reference count before running the// constructor, so that generating an sp<> to this in the constructor is no longer dangerous.template <typename T>template <typename... Args>sp<T> sp<T>::make(Args&&... args) {T* t = new T(std::forward<Args>(args)...);sp<T> result;result.m_ptr = t;t->incStrong(t);  // bypass check_not_on_stack for heap allocationreturn result;}

所以 m sp::make(driver) 回去执行 ProcessState 构造方法

ProcessState 构造方法
   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);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);if (mVMStart == MAP_FAILED) {close(opened.value());// *sigh*opened = base::Error()<< "Using " << driver << " failed: unable to mmap transaction memory.";mDriverName.clear();}}#ifdef __ANDROID__LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating: %s",driver, opened.error().message().c_str());#endifif (opened.ok()) {mDriverFD = opened.value();}}
open_driver(driver)

这里不就是打开驱动的逻辑嘛

 static base::Result<int> open_driver(const char* driver) {int fd = open(driver, O_RDWR | O_CLOEXEC);if (fd < 0) {return base::ErrnoError() << "Opening '" << driver << "' failed";}int vers = 0;status_t result = ioctl(fd, BINDER_VERSION, &vers);if (result == -1) {close(fd);return base::ErrnoError() << "Binder ioctl to obtain version failed";}if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {close(fd);return base::Error() << "Binder driver protocol(" << vers<< ") does not match user space protocol("<< BINDER_CURRENT_PROTOCOL_VERSION<< ")! ioctl() return value: " << result;}size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);if (result == -1) {ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));}uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);if (result == -1) {ALOGE_IF(ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::ONEWAY_SPAM_DETECTION),"Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));}return fd;}

在打开驱动时候进行了 ioctl 控制操作

注册成Binder服务 addService

ServiceManager.cpp

ServiceManager这个服务保存中mNameToService中,回调服务onRegistration()​方法。其实ServiceManager也是一个服务,用来管理其他服务,在其他服务启动注册前就已经就绪了。

 Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {auto ctx = mAccess->getCallingContext();if (multiuser_get_app_id(ctx.uid) >= AID_APP) {return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services");}if (!mAccess->canAdd(ctx, name)) {return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial");}if (binder == nullptr) {return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Null binder");}if (!isValidServiceName(name)) {LOG(ERROR) << "Invalid service name: " << name;return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name");}#ifndef VENDORSERVICEMANAGERif (!meetsDeclarationRequirements(binder, name)) {// already loggedreturn Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "VINTF declaration error");}#endif  // !VENDORSERVICEMANAGER// implicitly unlinked when the binder is removedif (binder->remoteBinder() != nullptr &&binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {LOG(ERROR) << "Could not linkToDeath when adding " << name;return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure");}// Overwrite the old service if it existsmNameToService[name] = Service {.binder = binder,.allowIsolated = allowIsolated,.dumpPriority = dumpPriority,.debugPid = ctx.debugPid,};auto it = mNameToRegistrationCallback.find(name);if (it != mNameToRegistrationCallback.end()) {for (const sp<IServiceCallback>& cb : it->second) {mNameToService[name].guaranteeClient = true;// permission checked in registerForNotificationscb->onRegistration(name, binder);}}return Status::ok();}

注册成Binder服务 becomeContextManager

其实就是通过ioctl 给系统发送了一条指令 BINDER_SET_CONTEXT_MGR_EXT,驱动被认定这个进程是ServiceManager.
android binder驱动层-BINDER_SET_CONTEXT_MGR_EXT

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);// fallback to original methodif (result != 0) {android_errorWriteLog(0x534e4554, "121035042");int unused = 0;result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);}if (result == -1) {ALOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));}return result == 0;}

轮询

开启了死循环,通过Looper不停的pull,回调给相应的LooperCallback

 sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);while(true) {looper->pollAll(-1);
}setupTo 方法:轮询读取命令
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {sp<BinderCallback> cb = sp<BinderCallback>::make();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,Looper::POLL_CALLBACK,Looper::EVENT_INPUT,cb,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.}};

解析命令,执行命令

上面轮训中看到 处理指令 handleEvent,最终回调方法是handlePolledCommands

status_t IPCThreadState::handlePolledCommands(){status_t result;do {result = getAndExecuteCommand();} while (mIn.dataPosition() < mIn.dataSize());processPendingDerefs();flushCommands();return result;}

总结

  • 了解ServiceManager 进程的启动,脚本和Native基本知识
  • 通过ServiceManager 的启动,为后续ServieManager的注册、获取、Binder和Service的交互打一个小基础

http://www.ppmy.cn/news/1570434.html

相关文章

使用 Axios 进行高效的数据交互

一、前言 1. 项目背景与目标 Axios 的重要性: Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js,简化了与服务器的通信。Axios 提供了丰富的功能,如拦截器、并发请求管理、取消请求等。2. 环境搭建 开发工具准备: 推荐使用 VSCode 或 WebStorm。安装必要的…

PostgreSQL / PostGIS:创建地理要素

PostGIS详细教程可以参考官方文档&#xff1a;https://postgis.net/workshops/zh_Hans/postgis-intro/&#xff0c;并且官方文档提供了练习数据、教程、PPT版本教程。我这里参考QGIS文档中关于PostGIS的教程进行学习。 PostGIS 可以被认为是一组数据库内函数的集合&#xff0c…

php得到本周的起始日期实现签到功能

要做一个签到功能&#xff0c;在签到界面会显示本周&#xff0c;从周一到周日的七天。 上代码 <?php$stime_format date(Y-m-d 00:00:00, strtotime(monday this week));$stime strtotime($stime_format);for ($i 0; $i < 6; $i) {$ta array(timestamp > $stim…

【数据采集】基于Selenium采集豆瓣电影Top250的详细数据

基于Selenium采集豆瓣电影Top250的详细数据 Selenium官网:https://www.selenium.dev/blog/ 豆瓣电影Top250官网:https://movie.douban.com/top250 写在前面 实验目标:基于Selenium框架采集豆瓣电影Top250的详细数据。 电脑系统:Windows 使用软件:PyCharm、Navicat 技术需求…

TLS 和 SSL区别

TLS 与 SSL 的区别 TLS&#xff08;传输层安全协议&#xff09;和 SSL&#xff08;安全套接字层&#xff09;都是用于加密网络通信的协议&#xff0c;特别是在 Web 流量&#xff08;如 HTTPS&#xff09;中保护数据传输的安全。虽然它们有相似的功能和目的&#xff0c;但在协议…

Nginx部署Umi React前端项目标准配置

文章目录 概要前端Umi项目配置文件请求后端Api打包 后端项目Nginx配置配置文件 错误信息 概要 使用UmiJs开发的前端项目打包部署在Nginx&#xff0c;主要是Umi中项目的配置和Nginx的配置 前端Umi项目 基于"umijs/max": "^4.3.24", "react": &…

2.7学习总结

并查集&#xff1a; 1.查询&#xff08;采用了递归的方法&#xff09; 2.合并、 完整代码模板&#xff08;联系题目直接套模板&#xff09; 1.优化前 #include<stdio.h> #include<stdlib.h> #define MAXSIZE 100int uset[MAXSIZE];//定义一个足够长的数组 //用…

RISC-V芯片与扩展医疗影像处理边缘设备编程探析

一、引言 在数智化医疗快速发展的当下,医疗影像处理作为疾病诊断、治疗方案制定的关键环节,对设备性能与效率提出了极高要求。传统的医疗影像处理多依赖于集中式的大型计算中心,数据需传输至远程服务器进行处理,这不仅面临网络延迟、带宽限制的问题,还存在数据隐私安全风险…