当前位置: 首页 > news >正文

Android 系统服务的添加

Android 中如何添加一个系统服务

一、这道题主要考察什么

“如何添加一个系统服务”主要考察以下几个方面:

  1. 是否理解系统服务的使用方式
    应用通常通过Context.getSystemService()获取系统服务。

  2. 是否理解系统服务的发现机制
    服务端需要将自己的 Binder 对象注册到ServiceManager,客户端才能根据服务名称找到它。

  3. 是否理解 Binder 跨进程通信
    应用进程获取到系统服务的 Binder 代理对象后,通过 Binder IPC 调用服务端。

  4. 是否理解系统服务的启动位置
    系统服务可以运行在system_server进程中,也可以运行在单独的 Native 进程中。

可以将核心概括为三个关键词:

方便使用、注册开放、Binder IPC


二、系统服务的整体调用链

应用获取和调用系统服务的大致流程是:

应用程序 ↓ Context.getSystemService(name) SystemServiceRegistry ↓ 根据 name 查找 ServiceFetcher 创建对应的 Manager 对象 ↓ ServiceManager.getService(name) ↓ 获得服务端 Binder 代理对象 ↓ AIDL 接口代理 Stub.Proxy ↓ Binder IPC 系统服务端

例如应用获取电源服务:

PowerManagerpowerManager=(PowerManager)context.getSystemService(Context.POWER_SERVICE);

底层大致经历:

Context.getSystemService(POWER_SERVICE) ↓ SystemServiceRegistry ↓ PowerManager 对应的 ServiceFetcher ↓ ServiceManager.getService("power") ↓ 获得 IPowerManager 的 Binder 代理 ↓ 封装成 PowerManager 返回给应用

三、为什么还要封装一个 Manager 类

客户端从ServiceManager中取得的,本质上是系统服务的 Binder 接口代理,例如:

IPowerManager

但 Android 通常不会直接把 AIDL 接口暴露给普通应用,而是再封装一层:

PowerManager

调用关系为:

应用 ↓ PowerManager ↓ IPowerManager.Stub.Proxy ↓ Binder IPC PowerManagerService

PowerManager相当于客户端代理或者业务封装层,主要作用是:

  • 隐藏 Binder 和 AIDL 实现细节;
  • 统一处理RemoteException
  • 对外提供更容易使用的业务 API;
  • 对参数、权限和兼容性进行额外处理。

所以,添加一个完整的系统服务时,不能只考虑服务端,还应该考虑应用如何方便地使用该服务。


四、ServiceManager 的作用

ServiceManager可以理解为 Binder 系统中的服务注册中心。

系统服务启动后,需要把自己的 Binder 实体注册到ServiceManager

ServiceManager.addService("my_service",binder);

客户端使用时,根据服务名称查询:

IBinderbinder=ServiceManager.getService("my_service");

整体关系为:

注册 Binder 系统服务 ----------------------> ServiceManager ↑ │ 根据名称查询 │ 客户端 -----------------------------+

客户端并不需要提前知道服务对象所在的进程,只需要知道服务名称。

查询到 Binder 对象后,客户端便可以通过 Binder IPC 调用服务端。


五、如何添加一个系统服务

添加系统服务需要同时处理服务端和客户端。

1. 定义跨进程接口

通常使用 AIDL 定义服务接口:

interface IMyService { int calculate(int value); }

编译后会生成:

IMyService IMyService.Stub IMyService.Stub.Proxy

其中:

  • Stub用于服务端接收 Binder 请求;
  • Proxy用于客户端发起 Binder 请求。

2. 实现系统服务

服务端实现 AIDL 生成的Stub

publicclassMySystemServiceextendsIMyService.Stub{@Overridepublicintcalculate(intvalue){returnvalue*2;}}

此时MySystemService本身就是一个 Binder 实体对象。

实际系统服务通常还会包含:

  • 资源初始化;
  • 系统状态监听;
  • 权限检查;
  • Binder 接口实现;
  • 生命周期管理。

3. 选择系统服务运行的位置

系统服务主要有两种运行方式。

方式一:运行在 system_server 中

大多数 Java 系统服务运行在system_server进程,例如:

ActivityManagerService PackageManagerService PowerManagerService WindowManagerService

这类服务通常在SystemServer启动过程中创建。

大致过程:

MySystemServiceservice=newMySystemService();ServiceManager.addService("my_service",service);

如果运行在system_server中,不需要自己初始化 Binder 驱动和 Binder 线程池,因为system_server已经完成这些工作。


方式二:运行在独立进程中

部分 Native 系统服务运行在独立进程中,例如:

SurfaceFlinger media 服务 ServiceManager

独立进程的服务通常需要:

  1. init.rc中配置进程启动方式;
  2. 提供进程入口函数;
  3. 初始化 Binder 通信环境;
  4. 创建系统服务 Binder 对象;
  5. 注册到ServiceManager
  6. 启动 Binder 线程池并进入循环。

大致流程:

init 读取 rc 配置 ↓ 启动系统服务进程 ↓ 打开 Binder 驱动 ↓ 进行 mmap 内存映射 ↓ 启动 Binder 线程池 ↓ 创建服务对象 ↓ ServiceManager.addService() ↓ 进入 Binder 线程循环

4. 注册到 ServiceManager

无论系统服务运行在system_server,还是运行在独立进程中,都需要向ServiceManager注册。

ServiceManager.addService("my_service",myService);

注册时传入:

  • 服务名称;
  • 服务的 Binder 实体对象。

注册之后,其他进程才能通过名称查询:

IBinderbinder=ServiceManager.getService("my_service");

因此,注册的本质是:

把服务名称和 Binder 对象之间的映射关系保存到 ServiceManager 中。


5. 编写客户端 Manager 类

为了避免应用直接操作 AIDL 接口,通常再封装一个 Manager 类:

publicclassMyManager{privatefinalIMyServiceservice;publicMyManager(IMyServiceservice){this.service=service;}publicintcalculate(intvalue){try{returnservice.calculate(value);}catch(RemoteExceptione){throwe.rethrowFromSystemServer();}}}

调用链为:

MyManager ↓ IMyService.Proxy ↓ Binder IPC MySystemService

6. 注册到 SystemServiceRegistry

为了让应用能够像使用其他系统服务一样调用:

context.getSystemService("my_service");

还需要在客户端框架层注册对应的ServiceFetcher

概念代码如下:

registerService("my_service",MyManager.class,newCachedServiceFetcher<MyManager>(){@OverridepublicMyManagercreateService(ContextImplcontext){IBinderbinder=ServiceManager.getService("my_service");IMyServiceservice=IMyService.Stub.asInterface(binder);returnnewMyManager(service);}});

之后应用便可以通过:

MyManagermanager=(MyManager)context.getSystemService("my_service");

获取服务。

这里完成了三层转换:

服务名称 ↓ IBinder ↓ IMyService ↓ MyManager

六、完整添加流程

完整流程可以总结为:

1. 使用 AIDL 定义 Binder 接口 ↓ 2. 服务端继承 Stub,实现业务逻辑 ↓ 3. 决定服务运行在 system_server 还是独立进程 ↓ 4. 在合适的系统启动阶段创建服务 ↓ 5. 使用 ServiceManager.addService() 注册 Binder ↓ 6. 客户端实现对应的 Manager 封装类 ↓ 7. 在 SystemServiceRegistry 中注册 ServiceFetcher ↓ 8. 应用通过 Context.getSystemService() 获取服务 ↓ 9. 通过 Binder IPC 调用服务端

七、除了代码,还需要处理什么

真正将一个系统服务加入 Android 系统,通常还需要处理:

  • Android.bp 等编译配置;
  • AIDL 接口编译配置;
  • SELinux 权限和策略;
  • service_contexts服务名称映射;
  • Binder 调用权限检查;
  • 系统 API 的公开或隐藏配置;
  • 独立进程对应的init.rc
  • 系统启动顺序和依赖关系;
  • 服务异常和 Binder 死亡处理。

因此,添加系统服务不仅是写一个 Binder 类,还涉及:

Framework、Binder、SystemServer、ServiceManager、编译系统以及 SELinux。


八、逻辑梳理

Android 中添加一个系统服务,需要同时考虑服务端注册、Binder 通信和客户端使用方式。

首先,可以通过 AIDL 定义跨进程接口,然后在服务端继承 AIDL 生成的Stub,实现具体业务逻辑。

接着要确定服务运行的位置。如果服务运行在system_server中,可以在SystemServer启动系统服务的阶段创建它;如果运行在独立进程中,还需要通过init.rc启动进程,并初始化 Binder 驱动、内存映射和 Binder 线程池。

服务创建完成后,需要调用ServiceManager.addService(),将服务名称和 Binder 实体注册到ServiceManager。这样客户端才能通过ServiceManager.getService()根据名称获得 Binder 代理对象,并通过 Binder IPC 调用服务。

为了让应用使用起来更方便,通常还会编写一个 Manager 类,对 AIDL 接口进行封装,并在SystemServiceRegistry中注册对应的ServiceFetcher。这样应用就可以像使用其他系统服务一样,通过Context.getSystemService()获取该服务。

此外,真正加入 Android 系统还需要处理编译配置、SELinux 权限、service_contexts、接口权限检查和系统启动顺序等问题。


九、十句话以内的面试回答

添加 Android 系统服务,首先要使用 AIDL 定义跨进程接口,并在服务端继承Stub实现业务逻辑。
然后确定服务运行在system_server进程,还是运行在独立进程中。
如果运行在system_server中,通常在SystemServer启动系统服务的阶段创建。
如果运行在独立进程中,还需要配置init.rc,并初始化 Binder 线程池。
服务创建后,通过ServiceManager.addService()注册服务名称和 Binder 实体。
客户端通过ServiceManager.getService()根据名称取得 Binder 代理。
之后通过 AIDL 生成的 Proxy 发起 Binder IPC 调用。
为了方便应用使用,还应封装一个对应的 Manager 类。
再在SystemServiceRegistry中注册,使应用可以通过Context.getSystemService()获取。
最后还需要配置编译规则、SELinux、service_contexts和调用权限。


十、最核心的一句话

添加系统服务的本质,是创建一个 Binder 服务,将它注册到 ServiceManager,并在客户端提供通过 Context.getSystemService() 获取和调用该服务的封装。


第一是添加时机。如果服务运行在 system_server 中,就在 SystemServer 启动系统服务的阶段创建;如果运行在独立进程中,就需要配置 init.rc,并提供进程入口函数。

第二是服务端工作。服务端需要支持 Binder 通信、完成自身初始化,并通过 ServiceManager.addService() 注册自己的 Binder 对象。如果运行在 system_server 中,Binder 环境已经由系统初始化;如果运行在独立进程中,则需要自己启动 Binder 线程池。

第三是应用端工作。为了让应用能够像使用其他系统服务一样,通过 Context.getSystemService() 获取服务,需要在 SystemServiceRegistry 中注册对应的 ServiceFetcher,并封装客户端 Manager 类。

http://www.jsqmd.com/news/1321735/

相关文章:

  • 2026江门管道疏通哪家好旭日管道疏通免费上门靠谱 - 余生黄金回收
  • 副主任药师评审答辩课程怎么选不浪费钱? - 资讯在线
  • 别再手动剪视频了!AI全自动UP主工作流上线即用:1个API调用=日更3条高质量视频(内测资格仅剩82个)
  • Unity开发效率提升利器:QHierarchy插件核心功能与实战配置指南
  • 如何自己设计一个DSL
  • 深圳全区域Picotin18菜篮子回收!冷门爆款高流通变现,别再低价乱卖 - 大牌深度测评
  • 数据接口测试工具 Postman 介绍
  • 重庆漏水检测设备实测:知途管道科技技术团队深度评测6大主流技术 - 知途管道科技
  • 终极指南:使用TegraRcmGUI免费图形化工具快速为Switch注入Payload
  • 为什么你的AI文章总被限流?深度解析微信算法最新识别逻辑(附3套逃逸提示工程方案)
  • 2026年食品厂防霉涂料行业深度分析与优质品牌选型指南 - 优企甄选
  • 主任护师考试哪个机构通过率高? - 资讯在线
  • 相关系数全解析:从皮尔逊到斯皮尔曼,量化变量关联的实战指南
  • 用户画像失效?广告ROI跌破1.8?AI实时动态分层系统上线48小时,精准度提升至92.6%(附AB测试原始日志)
  • Wand-Enhancer终极指南:免费解锁Wand专业版功能的简单方法
  • 3步解锁跨语言屏幕实时翻译:Translumo打破语言壁垒的技术革命
  • 从积木题看算法思维:游程编码与连续段统计在信奥竞赛中的应用
  • 终极指南:5步免费解锁Wand Pro完整功能与远程控制
  • MAA智能公招系统:基于图像识别与算法决策的明日方舟自动招募解决方案
  • 2026年道路标线涂料生产厂家推荐:综合实力解析 品牌选购参考 - 全域品牌推荐
  • 获取任意链接文章正文 API 功能简介
  • 2026宁波江北管道疏通哪家好旭日靠谱上门疏通避坑指南 - 余生黄金回收
  • 2026 河南叛逆青少年封闭学校汇总|八大正规基地推荐,解决孩子厌学、沉迷手机、亲子对立 - Luckyone王
  • 在 Ionic2 TypeScript 项目中导入第三方 JS 库
  • (2026年8月更新)淮南甲醛检测公司怎么选:只做检测、不做治理的专业 CMA 资质实验室——醛清测研甲醛检测中心室内空气及环境检测 - 创达咨询
  • Webpack 2 视频教程 004 - Webpack 初体验
  • ChatTTS与UE5集成:游戏动态语音生成架构与实战
  • 开源按键映射工具终极指南:游戏手柄与键鼠全能转换方案
  • RAG 入门实战:从 0 到 1 搭一个本地知识库问答系统
  • 2026河北塑胶地板生产厂家推荐:运动塑胶地板、PVC塑胶地板、养老院康复训练地板、健身房PVC地板、羽毛球运动地板,3强塑胶地板厂家选择指南 - 海棠依旧大