第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级

43 阅读8分钟

第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级

所属板块:第二板块 — Android 四大组件标准化学理

前置知识:第七篇中的 Activity 任务栈、AMS 调度、进程孵化、Binder IPC

本篇定位:Service 是 Android 系统中唯一没有可视化界面、长期运行于后台的组件。本篇将彻底拆解 Service 的双生性(启动与绑定)、生命周期悖论优先级调度算法前台服务(Foreground Service)的生存法则Bound Service 的连接池模型AIDL 的 IPC 序列化机制JobScheduler 与 WorkManager 的系统级调度。我们将深入 ActivityManagerService (AMS)ActiveServices 的源码级逻辑,揭示 Service 为何容易被杀死、以及如何正确保活(非黑科技,而是系统规范)。


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 简单,但混合模式下的状态转换较为复杂。

stateDiagram-v2
    [*] --> Created: onCreate()
    Created --> Started: onStartCommand()
    Created --> Bound: onBind()
    Started --> StartedAgain: onStartCommand()
    Bound --> BoundAgain: onRebind()
    Started --> Destroyed: stopSelf() / stopService()
    Bound --> Destroyed: onUnbind()
    Destroyed --> [*]

    note right of Started
        启动模式
        独立运行
    end note

    note right of Bound
        绑定模式
        依赖客户端
    end note

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。适用于下载任务。

源码级解释

// 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 值进程类别被杀死概率
前台 Service0FOREGROUND_APP_ADJ极低
可见 Service1VISIBLE_APP_ADJ
服务 Service2 - 5SERVICE_ADJ
缓存 Service9 - 15CACHED_APP_ADJ

4.2 前台服务(Foreground Service)

前台服务是 Service 的最高优先级形态。它必须在状态栏显示一个持续的通知,告知用户正在运行。

学术定义

  • 通知渠道:Android 8.0 (O) 以上,必须创建通知渠道。
  • 持续通知:通知的 flags 必须包含 FLAG_ONGOING_EVENTFLAG_NO_CLEAR
  • 优先级:前台 Service 的 oom_adj 为 0,与 Activity 同等级别。

代码示例(系统规范)

// 在 Service 中调用
startForeground(NOTIFICATION_ID, notification);

系统限制

  • Android 8.0 (O) 引入了后台执行限制。后台 Service 无法启动前台 Service,除非应用处于前台。
  • Android 9.0 (P) 引入了前台服务权限FOREGROUND_SERVICE)。

5. Bound Service 与 IPC 机制

5.1 Binder 通信模型

Bound Service 的核心是 Binder IPC。Service 返回一个 IBinder 对象,客户端通过这个对象与 Service 通信。

graph TB
    subgraph ClientProc ["客户端进程"]
        Client["Activity/Fragment"]
        Proxy["Binder Proxy (Stub.Proxy)"]
    end

    subgraph ServiceProc ["服务端进程"]
        Service["Service"]
        Stub["Binder Stub (Stub)"]
        Impl["ServiceImpl"]
    end

    Client -->|"1. bindService"| Proxy
    Proxy <-->|&#34;2. Binder IPC (transact/onTransact)&#34;| Stub
    Stub -->|&#34;3. 调用&#34;| Impl

5.2 AIDL 的序列化机制

AIDL(Android Interface Definition Language)是 Android 的 IPC 接口定义语言。它定义了客户端和服务端通信的契约。

学术定义

  • Parcelable:AIDL 传输的对象必须实现 Parcelable 接口,以便在不同进程间序列化和反序列化。
  • Stub:服务端实现的基类,包含 onTransact() 方法,负责接收并处理客户端的请求。
  • Proxy:客户端持有的代理对象,负责将请求打包成 Parcel,发送给服务端。

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() 的源码级流程

sequenceDiagram
    participant Client as 应用进程
    participant AMS as ActivityManagerService
    participant AS as ActiveServices
    participant Service as Service 进程

    Client->>AMS: startService(intent)
    AMS->>AS: startServiceLocked()
    AS->>AS: 查找 ServiceRecord
    alt Service 未运行
        AS->>AMS: bringUpServiceLocked()
        AMS->>Service: 创建进程 (fork)
        Service->>Service: onCreate()
    end
    AS->>Service: sendServiceArgsLocked()
    Service->>Service: onStartCommand()

关键数据结构

  • ServiceRecord:AMS 中保存 Service 信息的记录,包含 nameprocessNameintentFilter 等。
  • ServiceMap:AMS 中按用户 ID 存储的 Service 映射表。

6.2 bindService() 的源码级流程

sequenceDiagram
    participant Client as 应用进程
    participant AMS as ActivityManagerService
    participant AS as ActiveServices
    participant Service as Service 进程

    Client->>AMS: bindService(intent, conn, flags)
    AMS->>AS: bindServiceLocked()
    AS->>AS: 查找 ServiceRecord
    alt Service 未运行
        AS->>AMS: bringUpServiceLocked()
        AMS->>Service: 创建进程 (fork)
        Service->>Service: onCreate()
    end
    AS->>Service: requestServiceBindingsLocked()
    Service->>Service: onBind()
    Service-->>Client: 返回 IBinder
    Client->>Client: onServiceConnected(conn, binder)

7. Service 的销毁与回收

7.1 销毁流程

Service 的销毁由 AMS 统一管理。

sequenceDiagram
    participant Client as 应用进程
    participant AMS as ActivityManagerService
    participant AS as ActiveServices
    participant Service as Service 进程

    Client->>AMS: stopService() / unbindService()
    AMS->>AS: stopServiceLocked() / unbindServiceLocked()
    AS->>AS: 检查引用计数
    alt 引用计数为 0
        AS->>Service: scheduleStopService()
        Service->>Service: onDestroy()
        AS->>AMS: serviceDoneExecuting()
        AMS->>AMS: 更新进程优先级
    end

7.2 低内存回收(Low Memory Killer)

当系统内存不足时,LMK 会根据 Service 的优先级进行回收。

回收策略

  1. 优先回收:处于后台的 Service(oom_adj >= 9)。
  2. 其次回收:正在运行但不在前台的 Service(oom_adj = 2-5)。
  3. 最后回收:前台 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 系统推荐的省电后台执行方案。

示例

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 组件,基于 JobSchedulerAlarmManagerBroadcastReceiver 构建,提供更高级的后台任务管理。

学术定义

  • 向后兼容:支持 Android 4.0+。
  • 链式任务:可以定义任务的执行顺序。
  • 保证执行:即使在应用退出或设备重启后,任务也会被执行(取决于约束条件)。

9. Service 的安全机制

9.1 权限保护

Service 可以通过权限保护,防止未授权的应用启动或绑定。

<service
    android:name=".MyService"
    android:permission="com.example.permission.MY_SERVICE" />

学术定义

  • 自定义权限:应用可以定义自己的权限,并在 Manifest 中声明。
  • 系统权限:某些系统 Service 需要特定的系统权限才能访问。

9.2 导出控制

<service
    android:name=".PublicService"
    android:exported="true" />
<service
    android:name=".PrivateService"
    android:exported="false" />

学术定义

  • exported="true":允许其他应用访问。
  • exported="false":仅限应用内部访问,防止组件暴露漏洞。

10. 关键数据结构与源码定义

10.1 ServiceRecord(AMS 中的 Service 记录)

// 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(绑定连接记录)

// 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 事件分发与有序广播