第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级
所属板块:第二板块 --- Android 四大组件标准化学理
前置知识:第七篇中的 Activity 任务栈、AMS 调度、进程孵化、Binder IPC
本篇定位 :Service 是 Android 系统中唯一没有可视化界面、长期运行于后台 的组件。本篇将彻底拆解 Service 的双生性 (启动与绑定)、生命周期悖论 、优先级调度算法 、前台服务(Foreground Service)的生存法则 、Bound Service 的连接池模型 、AIDL 的 IPC 序列化机制 、JobScheduler 与 WorkManager 的系统级调度 。我们将深入 ActivityManagerService (AMS) 与 ActiveServices 的源码级逻辑,揭示 Service 为何容易被杀死、以及如何正确保活(非黑科技,而是系统规范)。全程无业务代码、无最佳实践建议,仅保留 Android Framework 的底层定义与系统级调度规范。
1. 核心结论先行(Thesis Statement)
Service 是 Android 操作系统中用于在后台执行长时间运行操作 的组件。它不是线程 ,也不是进程 ,而是一个由系统服务(AMS)管理的、具有独立生命周期的、运行在应用进程中的实体。
- Service 的本质 :一个后台执行实体(Background Execution Entity)。它不提供 UI,但可以在后台播放音乐、下载文件、执行网络请求或处理数据。
- 双生性(Duality) :Service 有两种截然不同的激活方式:启动(Started)和绑定(Bound)。这两种方式决定了 Service 的生命周期和行为。
- 优先级的核心 :Service 的生存能力取决于它在系统中的进程优先级(oom_adj)。前台服务(Foreground Service)拥有最高优先级,几乎不会被杀死;而后台服务(Background Service)极易被 Low Memory Killer 回收。
- IPC 的桥梁:Service 是 Android 实现**进程间通信(IPC)**的主要载体。通过 Binder 和 AIDL,Service 可以向其他进程提供服务接口。
2. Service 的两种激活模式(The Two Faces of Service)
2.1 启动模式(Started Service)
当一个组件(如 Activity)调用 startService() 时,Service 被启动。它独立于启动它的组件运行,即使启动它的组件被销毁,Service 仍会继续运行。
学术定义:
- 生命周期 :
onCreate()→onStartCommand()→onDestroy()。 - 独立性 :启动后,Service 与启动者无直接关联。启动者无法直接与 Service 通信(除非使用广播或 Messenger)。
- 终止条件 :Service 必须调用
stopSelf()或被其他组件调用stopService()才能停止。
示例场景:
- 后台下载文件。
- 上传日志。
- 同步服务器数据。
2.2 绑定模式(Bound Service)
当一个组件(如 Activity)调用 bindService() 时,Service 被绑定。它提供了一个客户端-服务器接口,允许组件与 Service 进行交互、发送请求、获取结果,甚至跨进程(IPC)通信。
学术定义:
- 生命周期 :
onCreate()→onBind()→onUnbind()→onDestroy()。 - 依赖性 :绑定是临时性的。当所有绑定的组件都解绑(unbind)后,Service 会自动销毁。
- 交互性 :客户端通过
IBinder接口与 Service 通信。
示例场景:
- 音乐播放器(Activity 控制播放/暂停)。
- 提供数据查询接口(ContentProvider 的替代方案)。
- 跨进程功能调用。
2.3 混合模式(Hybrid Service)
一个 Service 可以同时被启动 和绑定。这是最复杂的情况。
学术定义:
- 生命周期 :
onCreate()→onStartCommand()→onBind()→onUnbind()→onRebind()→onDestroy()。 - 终止条件 :必须同时满足:停止启动(
stopSelf()/stopService()) 且 所有绑定者解绑(unbindService())。
3. Service 生命周期拓扑学(Lifecycle Topology)
3.1 生命周期状态机(DFA)
Service 的生命周期比 Activity 简单,但混合模式下的状态转换较为复杂。
#mermaid-svg-4Sp3wflh2xDUE4dX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4Sp3wflh2xDUE4dX .error-icon{fill:#552222;}#mermaid-svg-4Sp3wflh2xDUE4dX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Sp3wflh2xDUE4dX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Sp3wflh2xDUE4dX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Sp3wflh2xDUE4dX .marker.cross{stroke:#333333;}#mermaid-svg-4Sp3wflh2xDUE4dX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Sp3wflh2xDUE4dX p{margin:0;}#mermaid-svg-4Sp3wflh2xDUE4dX defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-4Sp3wflh2xDUE4dX g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-4Sp3wflh2xDUE4dX g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-4Sp3wflh2xDUE4dX g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-4Sp3wflh2xDUE4dX g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-4Sp3wflh2xDUE4dX g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-4Sp3wflh2xDUE4dX .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-4Sp3wflh2xDUE4dX .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-4Sp3wflh2xDUE4dX .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-4Sp3wflh2xDUE4dX .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4Sp3wflh2xDUE4dX .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-4Sp3wflh2xDUE4dX .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-4Sp3wflh2xDUE4dX .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-4Sp3wflh2xDUE4dX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-4Sp3wflh2xDUE4dX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-4Sp3wflh2xDUE4dX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-4Sp3wflh2xDUE4dX .edgeLabel .label text{fill:#333;}#mermaid-svg-4Sp3wflh2xDUE4dX .label div .edgeLabel{color:#333;}#mermaid-svg-4Sp3wflh2xDUE4dX .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-4Sp3wflh2xDUE4dX .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-4Sp3wflh2xDUE4dX .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-4Sp3wflh2xDUE4dX .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-4Sp3wflh2xDUE4dX .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-4Sp3wflh2xDUE4dX .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Sp3wflh2xDUE4dX .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Sp3wflh2xDUE4dX #statediagram-barbEnd{fill:#333333;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4Sp3wflh2xDUE4dX .cluster-label,#mermaid-svg-4Sp3wflh2xDUE4dX .nodeLabel{color:#131300;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-4Sp3wflh2xDUE4dX .note-edge{stroke-dasharray:5;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-note text{fill:black;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram-note .nodeLabel{color:black;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagram .edgeLabel{color:red;}#mermaid-svg-4Sp3wflh2xDUE4dX #dependencyStart,#mermaid-svg-4Sp3wflh2xDUE4dX #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-4Sp3wflh2xDUE4dX .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-4Sp3wflh2xDUE4dX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} onCreate()
onStartCommand()
onBind()
onStartCommand()
onRebind()
stopSelf() / stopService()
onUnbind()
Created
Started
Bound
StartedAgain
BoundAgain
Destroyed
启动模式
独立运行
绑定模式
依赖客户端
3.2 onStartCommand() 的返回值(Redelivery Policy)
startService() 后,系统会调用 onStartCommand()。该方法返回一个整数,告诉系统在 Service 被杀死后应该如何处理。
| 返回值 | 学术定义 | 系统行为 |
|---|---|---|
| START_STICKY | 粘性 Service | 如果 Service 被杀死,系统会尝试重新创建它,并调用 onStartCommand(),但不会传递最后的 Intent。适用于媒体播放器。 |
| START_NOT_STICKY | 非粘性 Service | 如果 Service 被杀死,系统不会重新创建它,除非有新的 Intent 传入。适用于定时任务。 |
| START_REDELIVER_INTENT | 重传 Intent | 如果 Service 被杀死,系统会重新创建它,并重传最后一个 Intent。适用于下载任务。 |
源码级解释:
java
// ActiveServices.java
private void handleServiceArgs(...) {
int res = service.onStartCommand(args.args, flags, startId);
if (res == Service.START_STICKY) {
// 标记 Service 为粘性
r.sticky = true;
}
}
4. Service 的优先级与进程调度
4.1 进程优先级(oom_adj)体系
Service 的生存能力取决于它所在的进程优先级。AMS 根据 Service 的状态计算 oom_adj 值。
| Service 状态 | oom_adj 值 | 进程类别 | 被杀死概率 |
|---|---|---|---|
| 前台 Service | 0 | FOREGROUND_APP_ADJ | 极低 |
| 可见 Service | 1 | VISIBLE_APP_ADJ | 低 |
| 服务 Service | 2 - 5 | SERVICE_ADJ | 中 |
| 缓存 Service | 9 - 15 | CACHED_APP_ADJ | 高 |
4.2 前台服务(Foreground Service)
前台服务是 Service 的最高优先级形态。它必须在状态栏显示一个持续的通知,告知用户正在运行。
学术定义:
- 通知渠道:Android 8.0 (O) 以上,必须创建通知渠道。
- 持续通知 :通知的
flags必须包含FLAG_ONGOING_EVENT或FLAG_NO_CLEAR。 - 优先级 :前台 Service 的
oom_adj为 0,与 Activity 同等级别。
代码示例(系统规范):
java
// 在 Service 中调用
startForeground(NOTIFICATION_ID, notification);
系统限制:
- Android 8.0 (O) 引入了后台执行限制。后台 Service 无法启动前台 Service,除非应用处于前台。
- Android 9.0 § 引入了前台服务权限 (
FOREGROUND_SERVICE)。
5. Bound Service 与 IPC 机制
5.1 Binder 通信模型
Bound Service 的核心是 Binder IPC 。Service 返回一个 IBinder 对象,客户端通过这个对象与 Service 通信。
#mermaid-svg-cktFr4MNR1QpS87f{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cktFr4MNR1QpS87f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cktFr4MNR1QpS87f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cktFr4MNR1QpS87f .error-icon{fill:#552222;}#mermaid-svg-cktFr4MNR1QpS87f .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cktFr4MNR1QpS87f .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cktFr4MNR1QpS87f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cktFr4MNR1QpS87f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cktFr4MNR1QpS87f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cktFr4MNR1QpS87f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cktFr4MNR1QpS87f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cktFr4MNR1QpS87f .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cktFr4MNR1QpS87f .marker.cross{stroke:#333333;}#mermaid-svg-cktFr4MNR1QpS87f svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cktFr4MNR1QpS87f p{margin:0;}#mermaid-svg-cktFr4MNR1QpS87f .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cktFr4MNR1QpS87f .cluster-label text{fill:#333;}#mermaid-svg-cktFr4MNR1QpS87f .cluster-label span{color:#333;}#mermaid-svg-cktFr4MNR1QpS87f .cluster-label span p{background-color:transparent;}#mermaid-svg-cktFr4MNR1QpS87f .label text,#mermaid-svg-cktFr4MNR1QpS87f span{fill:#333;color:#333;}#mermaid-svg-cktFr4MNR1QpS87f .node rect,#mermaid-svg-cktFr4MNR1QpS87f .node circle,#mermaid-svg-cktFr4MNR1QpS87f .node ellipse,#mermaid-svg-cktFr4MNR1QpS87f .node polygon,#mermaid-svg-cktFr4MNR1QpS87f .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cktFr4MNR1QpS87f .rough-node .label text,#mermaid-svg-cktFr4MNR1QpS87f .node .label text,#mermaid-svg-cktFr4MNR1QpS87f .image-shape .label,#mermaid-svg-cktFr4MNR1QpS87f .icon-shape .label{text-anchor:middle;}#mermaid-svg-cktFr4MNR1QpS87f .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cktFr4MNR1QpS87f .rough-node .label,#mermaid-svg-cktFr4MNR1QpS87f .node .label,#mermaid-svg-cktFr4MNR1QpS87f .image-shape .label,#mermaid-svg-cktFr4MNR1QpS87f .icon-shape .label{text-align:center;}#mermaid-svg-cktFr4MNR1QpS87f .node.clickable{cursor:pointer;}#mermaid-svg-cktFr4MNR1QpS87f .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cktFr4MNR1QpS87f .arrowheadPath{fill:#333333;}#mermaid-svg-cktFr4MNR1QpS87f .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cktFr4MNR1QpS87f .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cktFr4MNR1QpS87f .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cktFr4MNR1QpS87f .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cktFr4MNR1QpS87f .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cktFr4MNR1QpS87f .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cktFr4MNR1QpS87f .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cktFr4MNR1QpS87f .cluster text{fill:#333;}#mermaid-svg-cktFr4MNR1QpS87f .cluster span{color:#333;}#mermaid-svg-cktFr4MNR1QpS87f div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cktFr4MNR1QpS87f .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cktFr4MNR1QpS87f rect.text{fill:none;stroke-width:0;}#mermaid-svg-cktFr4MNR1QpS87f .icon-shape,#mermaid-svg-cktFr4MNR1QpS87f .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cktFr4MNR1QpS87f .icon-shape p,#mermaid-svg-cktFr4MNR1QpS87f .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cktFr4MNR1QpS87f .icon-shape .label rect,#mermaid-svg-cktFr4MNR1QpS87f .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cktFr4MNR1QpS87f .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cktFr4MNR1QpS87f .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cktFr4MNR1QpS87f :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 服务端进程
客户端进程
- bindService
- Binder IPC (transact/onTransact)
- 调用
Activity/Fragment
Binder Proxy (Stub.Proxy)
Service
Binder Stub (Stub)
ServiceImpl
5.2 AIDL 的序列化机制
AIDL(Android Interface Definition Language)是 Android 的 IPC 接口定义语言。它定义了客户端和服务端通信的契约。
学术定义:
- Parcelable :AIDL 传输的对象必须实现
Parcelable接口,以便在不同进程间序列化和反序列化。 - Stub :服务端实现的基类,包含
onTransact()方法,负责接收并处理客户端的请求。 - Proxy :客户端持有的代理对象,负责将请求打包成
Parcel,发送给服务端。
AIDL 文件示例:
aidl
// IRemoteService.aidl
interface IRemoteService {
int getPid();
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);
}
生成的 Java 代码解析:
IRemoteService.Stub:抽象类,继承Binder,实现IRemoteService。服务端必须继承此类并实现接口方法。IRemoteService.Stub.Proxy:客户端使用的代理类,实现IRemoteService。它将方法调用转换为 Binder 事务。
6. Service 的启动与调度流程
6.1 startService() 的源码级流程
Service 进程 ActiveServices ActivityManagerService 应用进程 Service 进程 ActiveServices ActivityManagerService 应用进程 #mermaid-svg-gpVNukRnX62vTNEO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gpVNukRnX62vTNEO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gpVNukRnX62vTNEO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gpVNukRnX62vTNEO .error-icon{fill:#552222;}#mermaid-svg-gpVNukRnX62vTNEO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gpVNukRnX62vTNEO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gpVNukRnX62vTNEO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gpVNukRnX62vTNEO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gpVNukRnX62vTNEO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gpVNukRnX62vTNEO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gpVNukRnX62vTNEO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gpVNukRnX62vTNEO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gpVNukRnX62vTNEO .marker.cross{stroke:#333333;}#mermaid-svg-gpVNukRnX62vTNEO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gpVNukRnX62vTNEO p{margin:0;}#mermaid-svg-gpVNukRnX62vTNEO .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gpVNukRnX62vTNEO text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-gpVNukRnX62vTNEO .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gpVNukRnX62vTNEO .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-gpVNukRnX62vTNEO .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-gpVNukRnX62vTNEO .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-gpVNukRnX62vTNEO #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-gpVNukRnX62vTNEO .sequenceNumber{fill:white;}#mermaid-svg-gpVNukRnX62vTNEO #sequencenumber{fill:#333;}#mermaid-svg-gpVNukRnX62vTNEO #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-gpVNukRnX62vTNEO .messageText{fill:#333;stroke:none;}#mermaid-svg-gpVNukRnX62vTNEO .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gpVNukRnX62vTNEO .labelText,#mermaid-svg-gpVNukRnX62vTNEO .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-gpVNukRnX62vTNEO .loopText,#mermaid-svg-gpVNukRnX62vTNEO .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-gpVNukRnX62vTNEO .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-gpVNukRnX62vTNEO .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-gpVNukRnX62vTNEO .noteText,#mermaid-svg-gpVNukRnX62vTNEO .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-gpVNukRnX62vTNEO .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gpVNukRnX62vTNEO .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gpVNukRnX62vTNEO .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-gpVNukRnX62vTNEO .actorPopupMenu{position:absolute;}#mermaid-svg-gpVNukRnX62vTNEO .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-gpVNukRnX62vTNEO .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-gpVNukRnX62vTNEO .actor-man circle,#mermaid-svg-gpVNukRnX62vTNEO line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-gpVNukRnX62vTNEO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} altService 未运行 startService(intent)startServiceLocked()查找 ServiceRecordbringUpServiceLocked()创建进程 (fork)onCreate()sendServiceArgsLocked()onStartCommand()
关键数据结构:
- ServiceRecord :AMS 中保存 Service 信息的记录,包含
name、processName、intentFilter等。 - ServiceMap:AMS 中按用户 ID 存储的 Service 映射表。
6.2 bindService() 的源码级流程
Service 进程 ActiveServices ActivityManagerService 应用进程 Service 进程 ActiveServices ActivityManagerService 应用进程 #mermaid-svg-brvRYIGaayXSE2dj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-brvRYIGaayXSE2dj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-brvRYIGaayXSE2dj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-brvRYIGaayXSE2dj .error-icon{fill:#552222;}#mermaid-svg-brvRYIGaayXSE2dj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-brvRYIGaayXSE2dj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-brvRYIGaayXSE2dj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-brvRYIGaayXSE2dj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-brvRYIGaayXSE2dj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-brvRYIGaayXSE2dj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-brvRYIGaayXSE2dj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-brvRYIGaayXSE2dj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-brvRYIGaayXSE2dj .marker.cross{stroke:#333333;}#mermaid-svg-brvRYIGaayXSE2dj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-brvRYIGaayXSE2dj p{margin:0;}#mermaid-svg-brvRYIGaayXSE2dj .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-brvRYIGaayXSE2dj text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-brvRYIGaayXSE2dj .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-brvRYIGaayXSE2dj .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-brvRYIGaayXSE2dj .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-brvRYIGaayXSE2dj .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-brvRYIGaayXSE2dj #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-brvRYIGaayXSE2dj .sequenceNumber{fill:white;}#mermaid-svg-brvRYIGaayXSE2dj #sequencenumber{fill:#333;}#mermaid-svg-brvRYIGaayXSE2dj #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-brvRYIGaayXSE2dj .messageText{fill:#333;stroke:none;}#mermaid-svg-brvRYIGaayXSE2dj .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-brvRYIGaayXSE2dj .labelText,#mermaid-svg-brvRYIGaayXSE2dj .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-brvRYIGaayXSE2dj .loopText,#mermaid-svg-brvRYIGaayXSE2dj .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-brvRYIGaayXSE2dj .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-brvRYIGaayXSE2dj .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-brvRYIGaayXSE2dj .noteText,#mermaid-svg-brvRYIGaayXSE2dj .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-brvRYIGaayXSE2dj .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-brvRYIGaayXSE2dj .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-brvRYIGaayXSE2dj .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-brvRYIGaayXSE2dj .actorPopupMenu{position:absolute;}#mermaid-svg-brvRYIGaayXSE2dj .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-brvRYIGaayXSE2dj .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-brvRYIGaayXSE2dj .actor-man circle,#mermaid-svg-brvRYIGaayXSE2dj line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-brvRYIGaayXSE2dj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} altService 未运行 bindService(intent, conn, flags)bindServiceLocked()查找 ServiceRecordbringUpServiceLocked()创建进程 (fork)onCreate()requestServiceBindingsLocked()onBind()返回 IBinderonServiceConnected(conn, binder)
7. Service 的销毁与回收
7.1 销毁流程
Service 的销毁由 AMS 统一管理。
Service 进程 ActiveServices ActivityManagerService 应用进程 Service 进程 ActiveServices ActivityManagerService 应用进程 #mermaid-svg-4UmOi4kEVPD0v8jv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4UmOi4kEVPD0v8jv .error-icon{fill:#552222;}#mermaid-svg-4UmOi4kEVPD0v8jv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4UmOi4kEVPD0v8jv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4UmOi4kEVPD0v8jv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4UmOi4kEVPD0v8jv .marker.cross{stroke:#333333;}#mermaid-svg-4UmOi4kEVPD0v8jv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4UmOi4kEVPD0v8jv p{margin:0;}#mermaid-svg-4UmOi4kEVPD0v8jv .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4UmOi4kEVPD0v8jv text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4UmOi4kEVPD0v8jv .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4UmOi4kEVPD0v8jv .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4UmOi4kEVPD0v8jv #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4UmOi4kEVPD0v8jv .sequenceNumber{fill:white;}#mermaid-svg-4UmOi4kEVPD0v8jv #sequencenumber{fill:#333;}#mermaid-svg-4UmOi4kEVPD0v8jv #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4UmOi4kEVPD0v8jv .messageText{fill:#333;stroke:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4UmOi4kEVPD0v8jv .labelText,#mermaid-svg-4UmOi4kEVPD0v8jv .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .loopText,#mermaid-svg-4UmOi4kEVPD0v8jv .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4UmOi4kEVPD0v8jv .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4UmOi4kEVPD0v8jv .noteText,#mermaid-svg-4UmOi4kEVPD0v8jv .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4UmOi4kEVPD0v8jv .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4UmOi4kEVPD0v8jv .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4UmOi4kEVPD0v8jv .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4UmOi4kEVPD0v8jv .actorPopupMenu{position:absolute;}#mermaid-svg-4UmOi4kEVPD0v8jv .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-4UmOi4kEVPD0v8jv .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4UmOi4kEVPD0v8jv .actor-man circle,#mermaid-svg-4UmOi4kEVPD0v8jv line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4UmOi4kEVPD0v8jv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} alt引用计数为 0 stopService() / unbindService()stopServiceLocked() / unbindServiceLocked()检查引用计数scheduleStopService()onDestroy()serviceDoneExecuting()更新进程优先级
7.2 低内存回收(Low Memory Killer)
当系统内存不足时,LMK 会根据 Service 的优先级进行回收。
回收策略:
- 优先回收 :处于后台的 Service(
oom_adj>= 9)。 - 其次回收 :正在运行但不在前台的 Service(
oom_adj= 2-5)。 - 最后回收 :前台 Service(
oom_adj= 0)。
学术定义:
- Service 重启 :如果 Service 返回
START_STICKY,系统会在内存充足时重新创建它。 - Service 不重启 :如果 Service 返回
START_NOT_STICKY,系统不会重新创建它。
8. 系统级 Service 调度器(JobScheduler & WorkManager)
8.1 JobScheduler
Android 5.0 (L) 引入了 JobScheduler,用于在满足特定条件(如充电、网络连接、空闲)时执行后台任务。
学术定义:
- 条件约束:Job 可以设置网络类型、充电状态、设备空闲、电池电量等约束。
- 批量执行:系统会将多个 Job 批量执行,以节省电量。
- 省电机制:JobScheduler 是 Android 系统推荐的省电后台执行方案。
示例:
java
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, componentName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setRequiresCharging(true)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
8.2 WorkManager
Android Jetpack 组件,基于 JobScheduler、AlarmManager 和 BroadcastReceiver 构建,提供更高级的后台任务管理。
学术定义:
- 向后兼容:支持 Android 4.0+。
- 链式任务:可以定义任务的执行顺序。
- 保证执行:即使在应用退出或设备重启后,任务也会被执行(取决于约束条件)。
9. Service 的安全机制
9.1 权限保护
Service 可以通过权限保护,防止未授权的应用启动或绑定。
xml
<service
android:name=".MyService"
android:permission="com.example.permission.MY_SERVICE" />
学术定义:
- 自定义权限:应用可以定义自己的权限,并在 Manifest 中声明。
- 系统权限:某些系统 Service 需要特定的系统权限才能访问。
9.2 导出控制
xml
<service
android:name=".PublicService"
android:exported="true" />
<service
android:name=".PrivateService"
android:exported="false" />
学术定义:
exported="true":允许其他应用访问。exported="false":仅限应用内部访问,防止组件暴露漏洞。
10. 关键数据结构与源码定义
10.1 ServiceRecord(AMS 中的 Service 记录)
java
// com.android.server.am.ServiceRecord
class ServiceRecord extends Binder {
final ServiceInfo serviceInfo; // Manifest 信息
final String packageName;
final String processName; // 运行进程
final Intent.FilterComparison filter; // Intent 过滤器
final ArrayMap<IBinder, ConnectionRecord> connections; // 绑定连接记录
boolean foreground; // 是否为前台服务
int lastStartId; // 最后一次启动 ID
}
10.2 ConnectionRecord(绑定连接记录)
java
// com.android.server.am.ConnectionRecord
class ConnectionRecord {
final IBinder binding; // Binder 对象
final IServiceConnection conn; // 客户端连接接口
final int flags; // 绑定标志
final int clientUid; // 客户端 UID
final String clientProcessName; // 客户端进程名
}
11. 本篇总结(Knowledge Closure)
| 关键点 | 纯学术定义 |
|---|---|
| Service 的本质 | 由 AMS 管理的后台执行实体,无 UI,用于执行长时间运行的操作。 |
| 双生性 | 启动模式(独立运行)和绑定模式(交互运行)是 Service 的两种激活方式。 |
| 优先级 | 前台服务(Foreground Service)拥有最高优先级,后台服务极易被回收。 |
| IPC 机制 | 通过 Binder 和 AIDL 实现跨进程通信,Service 作为服务端提供接口。 |
| 系统调度 | JobScheduler 和 WorkManager 是系统推荐的后台任务调度方案,用于省电和优化性能。 |
| 安全机制 | 通过权限保护和导出控制,防止未授权的访问。 |
下一篇预告 :第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播