SDV 中的服务质量调度

SDV 服务质量 (QoS) 调度框架为生命周期管理器 (LM) 管理的服务软件包提供确定性的 CPU 资源分配。通过将低级别 Linux 调度属性(政策、优先级、Nice)抽象为逻辑预设,该平台实现了服务开发与车辆级系统调优之间的清晰分离。这有助于为安全关键型和时间敏感型工作负载提供必要的计算带宽,同时系统会限制后台任务以防止不稳定。

角色和职责

SDV 调度模型遵循委托责任模式,有助于确保服务保持可移植性,同时允许 OEM 调优系统。

角色 职责 主要交付成果
SDV 平台 (Google) 定义 sdv_service_bundles_scheduling.proto 架构,实现 LM 执行逻辑,并提供 sdv_service_bundles_scheduling 客户端库。 Protobuf 定义和平台库
OEM(系统集成商) 为每个预设定义具体值,例如 ELEVATED 在特定硬件上的含义,并控制系统级配置。 /product/etc/lifecycle_config.textproto
服务开发者 选择适当的逻辑预设名称,并在服务软件包清单中注册 scheduling_config.textproto 路径。 scheduling_config.textprotosdv_service_bundles_manifest.textproto

技术工作流

  1. 平台集成: OEM 定义车辆专用的 lifecycle_config.textproto。此文件建立系统级调度配置文件(预设),并根据目标硬件将其映射到具体的 Linux 调度属性。
  2. 服务软件包开发: 开发者在其 APEX 软件包中捆绑 scheduling_config.textproto,推荐逻辑预设(例如 ELEVATED),并定义任何内部线程名称。
  3. 服务软件包集成: 在车辆集成阶段,OEM 会审核开发者推荐的预设。OEM 可以保留推荐的配置文件,也可以替换它,例如将 ELEVATED 服务降级为 NORMAL,以在签署 APEX 之前提高整体系统稳定性。
  4. 运行时属性解析: 启动服务后,LM 会从服务的清单中识别授权的预设,并从 OEM 的系统配置中检索相应的 Linux 属性。
  5. 启动同步和执行: LM 会将解析的属性应用于服务进程,然后使用信号和继续协议向其发送信号以继续执行。

核心概念

以下概念是 SDV 调度框架的核心。

调度预设

调度预设是管理 SDV 中 QoS 的主要机制。开发者无需定义原始 Linux 调度参数,而是按名称引用预定义的预设。在运行时,LM 会将这些逻辑名称映射到具体的 Linux 调度属性。

以下预设在 lifecycle_config.textproto 中配置为示例:

预设名称 调度政策 典型 Nice 值 典型应用场景
NORMAL SCHED_OTHER 0 标准服务(暖通空调、媒体、设置)
ELEVATED SCHED_OTHER -10 核心系统组件和基础架构
IDLE SCHED_IDLE 19 后台分析和非关键日志记录
CUSTOM 用户定义的 -20(初始) 需要实时政策或亲和性的服务

应用预设时,LM 会使用 setpriority 系统调用来设置进程范围的 nice 值。这会影响进程在默认 Linux 完全公平调度器 (CFS) 下争用期间收到的相对 CPU 份额。

特权和安全性

为防止未经授权的优先级提升,SDV 平台采用基于 SELinux 网域和 Linux 功能的分层安全模型。

安全网域

  • untrusted_service_bundle:标准预设(NORMALELEVATEDIDLE)的默认网域。内核会限制此网域中的进程,阻止它们更改自己的调度参数。
  • priority_service_bundle:授予在系统级 lifecycle_config.textproto 中设置了 is_privileged: true 的任何使用预设的服务软件包。转换到此网域会授予进程 CAP_SYS_NICE 功能,使其能够管理自己的资源分配。

CAP_SYS_NICE 功能

该平台会向 priority_service_bundle 网域中的进程授予 CAP_SYS_NICE 功能。此权限允许进程执行以下操作:

  • 将其自己的 nice 值提升到初始分配值以上。
  • 将其调度政策更改为实时类,例如 SCHED_FIFOSCHED_RR
  • 使用 sched_setaffinity 设置 CPU 亲和性。
  • SCHED_DEADLINE 配置专用截止时间参数。

将此功能限制为专用网域,可通过限制对明确授权服务的干扰来保护系统级调度平衡。

配置指南

本部分为 OEM 和服务开发者提供配置指南。

OEM 指南:系统级预设

OEM 在 /product/etc/lifecycle_config.textproto 中定义调度配置文件。该平台在 lifecycle_management/config/lifecycle_config.textproto 中提供了一个示例,OEM 应根据车辆硬件对其进行调整。

示例:定义实时预设

OEM 可以为绝不能被标准应用抢占的安全相关服务定义 CRITICAL 预设:

# lifecycle_config.textproto
scheduling_presets {
  name: "CRITICAL"
  is_privileged: true
  thread_scheduling_configuration {
    policy: 1      # SCHED_FIFO
    priority: 80   # High real-time priority
  }
}

开发者指南:服务软件包配置

服务开发者推荐预设,并可以选择在 scheduling_config.textproto 文件中定义逻辑线程名称。如需让平台发现此文件,必须在 sdv_service_bundles_manifest.textproto 中注册此文件的路径。

示例:清单注册

# sdv_service_bundles_manifest.textproto
service_bundle_entries {
  name: "SensorService"
  scheduling_config_path: "configs/scheduling_config.textproto"
}

示例:使用标准预设

对于大多数服务,在 scheduling_config.textproto 中引用预设名称就足够了:

# configs/scheduling_config.textproto
scheduling_preset_name: "ELEVATED"

示例:为服务生成的工作器线程进行调度

服务开发者可能会在其代码中创建其他工作器线程来处理专用任务,例如低延迟传感器数据循环。开发者可以在配置文件中为这些内部线程定义命名的调度属性。

仅在特权服务中使用手动应用,这些服务使用此元数据为其内部工作器线程设置属性:

# configs/scheduling_config.textproto
scheduling_preset_name: "CUSTOM"

# Map of logical thread names to their attributes (propagated as metadata)
thread_scheduling_configuration {
  key: "sensor-processing-thread"
  value {
    policy: 1        # SCHED_FIFO
    priority: 50
    cpu_affinity_ids: [2, 3]  # Pin to specific cores
  }
}

系统行为和执行

SDV 平台采用严格的执行模型,以便在运行任何特定于服务的代码之前激活调度配置。

启动同步

为防止服务以不正确的优先级运行(即使在其初始化阶段也是如此),LM 和服务软件包运行程序 (SBR) 使用信号和继续同步协议:

  1. 进程创建: LM 会派生 SBR 进程。此时,SBR 子进程正在运行,但会立即进入阻塞状态,等待其 stdin 上的信号。
  2. 属性应用: 在子进程被阻塞期间,LM 会使用 setpriority 系统调用来应用请求的 nice 值,并配置调度政策(例如 SCHED_IDLE)。
  3. 安全转换: LM 执行 SELinux 网域转换,将子进程移至 untrusted_service_bundlepriority_service_bundle 网域。
  4. 信号: 只有在成功应用所有参数后,LM 才会向子进程的 stdin 发送单字节信号。
  5. 执行: SBR 接收信号并开始加载服务库和调用生命周期方法。

对主线程和生命周期的影响

通过在加载服务库之前进行同步,该平台会在所有生命周期回调中为主执行线程保持请求的优先级:

  • onCreate:所有依赖项注入和初始资源分配都以正确的优先级进行。
  • onStart:预设控制向活跃状态的转换和任何初始工作循环。
  • onStoponDestroy:该平台以相同的优先级执行清理操作,以防止在关机期间关键系统活动被饿死。

Binder 线程池和优先级继承

平台管理的 Binder 线程池中的线程不会以创建该池的线程的优先级执行工作。相反,对于同步事务,服务器线程会继承调用方的优先级。Binder 内核驱动程序控制着此优先级继承机制。

线程级微调

需要精细控制(例如实时处理循环)的服务软件包必须手动将其配置应用于其工作器线程。请按照以下步骤应用线程级配置:

  1. 请求特权预设(其中 is_privileged: true 已设置)。
  2. 使用 sdv_service_bundles_scheduling 库中的 get_scheduling_configuration 函数读取 thread_scheduling_configuration
  3. 使用 sched_setattr 将属性应用于工作器线程。

SELinux 和功能执行

该平台使用 SELinux 和 CAP_SYS_NICE Linux 功能来执行调度预设:

  • 对于使用 NORMALIDLE 等预设的服务,调度由 LM 在启动期间配置。这些服务没有 CAP_SYS_NICE 功能,无法更改其优先级或政策。
  • 使用特权预设(is_privileged: true)的服务会被授予 CAP_SYS_NICE 功能。这允许它们根据实时任务的需要,手动控制其内部线程的调度。

验证和示例

验证调度行为需要结合日志分析和系统级性能衡量。SDV 平台提供了一个专用示例来演示这些技术。

QoS 调度示例

此示例位于 samples/qos_scheduling 中,包含多个旨在并行运行并报告其进度的性能测试服务。

  • PerformanceTesterNormal:使用 NORMAL 预设运行。
  • PerformanceTesterElevated:使用 ELEVATED 预设运行。
  • PerformanceTesterRealtime:使用 CUSTOM 预设将其 SCHED_FIFO 应用于其内部工作器线程。
  • PolicyOffender:一种诊断服务,尝试在使用 NORMAL 预设时设置实时优先级。这用于验证平台是否成功阻止未经授权的升级。

运行验证套件

  1. 启用特定于 QoS 的编排配置:

    adb shell setprop persist.sdv.orchestrator_config_path /etc/orch/vm_qos_scheduling_orch_config.textproto

  2. 重启设备以在其各自的调度网域中启动服务:

    adb reboot

  3. 过滤日志以查看比较性能结果:

    adb logcat | grep sdv_sample_qos_common

    PerformanceTesterNormal 相比,PerformanceTesterElevated 服务报告的已完成工作单元明显更高。PolicyOffender 服务的日志中包含 EPERM 或 SELinux 拒绝错误。

向后兼容性

  • 为了实现向后兼容性,任何在其清单中指定了 scheduling_config_path 在配置文件中指定 scheduling_preset_name 的旧版服务软件包都会自动被视为特权服务。这保留了依赖手动线程调优的旧版服务所需的必要功能(例如 CAP_SYS_NICE)。
  • 根配置消息 DeadlineSchedulingConfiguration 计划在未来的版本中重命名。当前名称是历史名称,不再准确反映该消息处理所有调度类型(而不仅仅是截止时间调度)。