配置 Orchestrator

编排器是本地 SDV 代理,可在每个虚拟机 (VM) 上运行,并提供一种机制来控制何时应创建、启动、停止或销毁服务软件包。这是通过编排配置完成的,您可以在其中定义一组规则,用于确定何时以及如何对服务包实例执行操作。这些规则基于车辆、电源和自定义模式。

您可以在配置 APEX 中或通过每个虚拟机的配置来配置 Orchestrator。此分布式配置系统允许通过服务软件包注册表独立更新每个服务软件包的部分内容,如图所示。

编排器分布式配置图

图 1. 编排器配置图。

独立于车辆的配置不会因 OEM 或车辆而异。在每个 OEM 的所有车辆上,配置都保持不变。不同 OEM 的不同车辆的车辆专用配置可能有所不同,但特定 OEM 制造的所有车辆的配置可能相同。

配置 APEX

在运行时,编排器会前往服务软件包注册表,为每个服务软件包提取 SDV 编排,并加载和解析每个配置。如需了解详情,请参阅编排元数据

每个虚拟机的配置

当 Orchestrator 启动时,它会加载并解析虚拟机配置(如果存在)。此配置文件的绝对路径通过系统属性 persist.sdv.orchestrator_config_pathro.boot.sdv.orchestrator_config_path 指定。

系统会在启动时根据以下层次结构确定虚拟机配置文件路径:

  1. 系统会检查 persist.sdv.orchestrator_config_path 属性。如果该属性具有值,则使用该路径。此值在重新启动后会保留,也可以在运行时设置。

  2. 如果 persist.sdv.orchestrator_config_path 为空,系统会检查 ro.boot.sdv.orchestrator_config_path 属性。如果 ro.boot.sdv 属性具有值,则该路径会复制到 persist 属性,并用于当前启动和所有未来的启动(除非被替换)。

persist.sdv.orchestrator_config_path

persist.sdv.orchestrator_config_path 是 SDV Orchestrator 代理用来获取其配置文件路径的主要属性。这是一个持久性属性,这意味着其值会在设备重启后保存。您可以在运行时更改该值,这对于测试或特定场景(例如端到端测试)非常有用。

您可以在运行时使用 setprop 命令设置该值,也可以在构建时使用 makefile(扩展名为 .mk)或资源脚本文件(扩展名为 .rc)设置该值。

在运行时设置属性

在运行时设置属性对于测试或进行临时更改非常有用,因为该值会在重新启动后保存:

adb root
adb shell setprop persist.sdv.orchestrator_config_path {$path_to_file}.textproto

在构建时设置属性

如需将此属性设置为设备 build 配置的一部分,请在产品或主板的 makefile 中添加一行代码。此属性非常适合为新的设备映像设置默认值。

# Add this line to a product's or device's .mk file
PRODUCT_PROPERTY_OVERRIDES += persist.sdv.orchestrator_config_path={$path_to_file}.textproto

您还可以在资源脚本文件中设置此属性:

# Add this line to an .rc file
on {$property}
    setprop persist.sdv.orchestrator_config_path {$path_to_file}.textproto

ro.boot.sdv.orchestrator_config_path

ro.boot.sdv.orchestrator_config_path 是一个启动时只读属性,用于为 persist.sdv.orchestrator_config_path 属性提供初始值。如果系统启动时 persist.sdv.orchestrator_config_path 为空,则将 ro.boot.sdv.orchestrator_config_path 的值复制到 persist.sdv.orchestrator_config_path。一旦设置了 persist.sdv.orchestrator_config_path,后续启动时该属性就不会覆盖它。

您可以使用启动配置或内核 cmdline 设置 ro.boot.sdv.orchestrator_config_path

文件格式

.textproto 格式(例如,以结构化文本格式)定义编排配置,以便在运行时加载新配置。

配置语法

本部分介绍了配置语法。

服务包

每个服务包都必须使用服务包配置进行定义,该配置用于在 Orchestrator 中标识相应软件包,并用于处理软件包实例的生命周期。服务包配置定义了以下内容:

  • InstanceToGroupMapping 可让您在群组中包含服务包的实例,以在同一服务包的实例之间建立依赖关系。

  • InstancesStates 用于定义服务软件包实例的不同状态。

  • InstancesStateConfiguration 定义了服务包实例在条件评估结果为 true 时必须设置的状态(从 InstancesStates 开始)。

  • ServiceBundleConfig 包含有关特定服务包及其实例的信息。它包含相应软件包的 InstanceToGroupMappingInstancesStateConfiguration

  • CustomModes 定义了软件包允许发布的一系列自定义模式。CustomModes 用于防止未经授权的软件包修改自定义模式的值。此字段是可选字段,因为服务包可能无法发布到任何自定义模式。如需了解详情,请参阅自定义模式

必需的软件包配置

软件包配置至少应提供以下属性:

service_bundle_config {
    package_name: "package_name"
    service_bundle_name: "service_bundle_name"

    instance: "instance_1"
    instance: "instance_n"
}

此声明定义了具有相应 FQIN 的 n 服务软件包实例:

vm_name.package_name.service_bundle_name.instance_1

vm_name.package_name.service_bundle_name.instance_n

虚拟机名称未在配置中明确声明。由于配置是按虚拟机定义的,因此虚拟机名称始终是部署配置文件的虚拟机的名称,并且编排代理已知道该名称。

配置实例

声明服务软件包实例无效。若要由 Orchestrator 执行,必须配置实例。例如,必须告知编排器实例应在哪些条件(或虚拟机/车辆状态)下运行。如需配置实例,应通过以下方式定义配置状态:

  • condition 是应评估的虚拟机或车辆状态表达式。

  • instances_states 是每个实例的一组状态,如果条件求值为 true,则应应用这些状态。

如需了解详情,请参阅条件

service_bundle_config {
    package_name: "oem.package"
    service_bundle_name: "OemApplication"

    instance: "adaptive_light"
    instance: "reserve_light"

    state {
        condition {
            power_state: "ON"
        }

        instances_states {
            started: "adaptive_light"
            created: "reserve_light"
        }
    }
}

实例到群组的映射

您还可以通过将服务实例纳入服务组来配置服务实例。在服务包配置级别,您可以将实例添加到群组。然后,您可以在虚拟机配置级别配置组。如需了解详情,请参阅下一部分和服务套装

service_bundle_config {
    package_name: "oem.package"
    service_bundle_name: "OemApplication"

    instance: "fog_front_light"
    instance: "fog_rear_light"
    instance: "turn_signal_light"
    instance: "light_flasher_display"

    # Declare that fog_light contains fog_front_light and fog_rear_light.
    group_mapping {
        group: "fog_light"
        instance: "fog_front_light"
        instance: "fog_rear_light"
    }

    # Declare that flasher_light contains turn_signal_light and light_flasher_display.
    group_mapping {
        group: "flasher_light"
        instance: "turn_signal_light"
        instance: "light_flasher_display"
    }
}

Proto 架构

以下是 proto 方案示例:

// Service bundle configuration.
//
// Defines service bundle data, its instances and configuration for instances
// states depending on the state of the system
message ServiceBundleConfig {
  // Required. Name of the service bundle.
  string service_bundle_name = 1;

  // Required. Package name of the service bundle.
  string package_name = 2;

  // Required. Service instances.
  repeated string instance = 3;

  // Configuration for instances states depending on the state of the system.
  repeated InstancesStateConfiguration state = 4;

  // Mapping of groups to their member service instances.
  repeated InstanceToGroupMapping group_mapping = 5;

  // Custom modes that this service bundle is allowed to set.
  repeated string custom_mode = 6;

  // Defines the retry policies for specific instances.
  // If multiple mappings target the same instance, the one with the highest `max_retries`
  // value takes precedence. This applies across all configuration files.
  repeated InstanceToRetryMapping retry_mapping = 7;
}

// Mapping of instances to their retry configuration.
message InstanceToRetryMapping {
  // Required.
  //
  // Name of the instances for which the given retry configuration is applied.
  repeated string instance = 1;

  // Required.
  //
  // The configuration that defines the restart and retry strategy for the instances.
  RetryConfiguration retry_config = 2;

  // Configuration for retry and restart.
  // This configuration is applied after a failure on a transition or after the bundle instance
  // has crashed. Upon a successful operation, the retry counter are reset to max_retries. This
  // configuration can be applied to any service bundle, not only the monitored ones. If the
  // configuration is not provided or none of the optional fields are filled, the default behavior
  // stated is applied (the value from `ro.boot.sdv.orchestrator.recovery.max_retries`
  // or zero if not set).
  message RetryConfiguration {
    // The number of times a retry/restart operation can be performed.
    // Defines the number of times the Orchestrator retries a transition
    // after a transient failure or after a bundle crash notification.
    // This applies to creating, starting and destroying operations.
    // The retry count resets to max_retries after a successful operation.
    // If not set, the default configured value in the
    // `ro.boot.sdv.orchestrator.recovery.max_retries` is used, or-if not set-
    // it fallbacks to zero.
    optional uint32 max_retries = 1;
  }
}

// Mapping of groups to their member service instances.
message InstanceToGroupMapping {
  // Required. Names of groups to which members are added.
  //
  // Group behavior is defined in VM configuration.
  repeated string group = 1;

  // Required. Names of instances to be included in the groups.
  //
  // Can reference only instance defined in the same config file.
  repeated string instance = 2;
}

// Describes the state the service instances should be in after the state is executed.
//
// If there is no valid configuration for the instance in the specific system state, such instance is transitioned to the "destroyed" state.
//
// For the GroupsStates definition to be useful, at least one item should be present in any of the fields.
message InstancesStates {
  // Names of the instances that must be in a "created" state.
  repeated string created = 1;

  // Names of the instances that must be in a "started" state, overrides "created" state.
  repeated string started = 2;

  // Names of the instances that must not run, overrides all other states.
  repeated string destroyed = 3;
}

// Configuration for instances states depending on the state of the system.
message InstancesStateConfiguration {
  // Condition for the system state under which the related instances states should be executed by Orchestrator.
  //
  // If omitted, the related instances states are always executed.
  Condition condition = 1;

  // Required. States of service bundle instances to be executed by Orchestrator if the condition is true.
  InstancesStates instances_states = 2;
}

虚拟机级配置

虚拟机配置可用于定义群组映射和群组配置。它用于在虚拟机级别对服务包之间的依赖关系进行建模,从而灵活地同时修改多个服务包的状态。将组的所有实例都置于指定状态。

编排程序不保证状态更改的执行顺序。编排器会将每个实例提升到指定状态。

通过在任何配置部分中使用 group 名称来隐式声明组。例如,实例到群组的映射、群组到群组的映射和群组配置状态。

群组到群组映射

群组可以包含其他群组。通过声明 group_1 包含 subgroup_2,我们可以有效地将 subgroup_2 中的所有服务实例添加到 group_1 中。

例如:

# Declare that body contains fog_light and flasher_light.
group_mapping {
    group: "body"
    subgroup: "fog_light"
    subgroup: "flasher_light"
}

配置群组

声明组不会产生任何影响。若要由 Orchestrator 执行,必须配置群组。例如,必须告知编排程序组应在虚拟机或车辆的哪些条件或状态下运行。

您可以采用与配置服务实例类似的方式(即使用配置状态)来配置群组。唯一的区别是语法中使用了 groups_states 而不是 instances_states

state {
    condition {
        power_state: "ON"
    }

    groups_states {
        started: "Body"
        started: "Adas"
    }
}

Proto 架构

以下是 proto 架构示例:

// VM configuration.
//
// Defines group-to-group mappings and configuration for groups
// states depending on the state of the system.
//
// Configurations of service bundles can also be defined in VM configuration (as well as in a separate configuration file).
message VmConfig {
  // Group to member groups mapping.
  repeated GroupToGroupMapping group_mapping = 1;

  // Configuration of group states.
  repeated GroupsStateConfiguration state = 2;

  // Required. We also allow to configure individual service bundles in the VM config, to simplify development and migration from the monolithic configuration.
  repeated ServiceBundleConfig service_bundle_config = 3;
}

// Mapping of groups to their member groups.
message GroupToGroupMapping {
  // Required. Names of groups to which members are added.
  repeated string group = 1;

  // Required. Names of member groups to be included in the groups.
  repeated string subgroup = 2;
}

// Describes the state the service instance groups should be in after the state is executed.
//
// If group configuration is valid in a specific system state, the configured state is applied to
// all group members. After that, the normal service instance configuration rules still apply:
// - "destroyed" > "started" > "created" precedence
// - not configured means the instance should be moved to the default state
//
// For the GroupsStates definition to be useful, at least one item should be present in any of the fields.
message GroupsStates {
  // Names of the groups that must be in a "created" state.
  repeated string created = 1;

  // Names of the groups that must be in a "started" state, overrides "created" state.
  repeated string started = 2;

  // Names of the groups that must not run, overrides all other states.
  repeated string destroyed = 3;
}

// Configuration for group states depending on the state of the system.
message GroupsStateConfiguration {
  // Condition for the system state under which the related group states should be executed by  Orchestrator.
  //
  // If omitted, the related groups states are always executed.
  Condition condition = 1;

  // Required. States of service bundle groups to be executed by Orchestrator if the condition  is true.
  GroupsStates groups_states = 2;
}

配置状态

配置状态(状态)定义了服务实例或组的启动、停止或销毁时间,由 conditionsinstances_states(软件包配置)以及 groups_states(虚拟机配置)组成。

条件

条件允许模型具有布尔条件,当该条件评估为 true 时,系统会应用定义的实例状态。条件具有以下特征:

  • 基于支持的信号(例如电源、车辆和自定义模式)的任意复杂布尔表达式(使用 andnot 表达式构成)。

  • (可选)没有条件的配置状态始终处于有效状态,这意味着它会评估为 true

实例状态和组状态

instances_statesgroups_states 具有以下特征。

  • 指定编排代理需要哪些状态才能应用于给定的实例或组,前提是状态为 active

  • 将状态应用于群组时,该状态会应用于群组中的每个服务包实例。实例进入该状态的时间没有顺序。

支持的州包括:

  • 在调用 Service::on_start 之后调用 started

  • created

    • 在调用 Service::new 之后,但在调用 Service::on_start 之前。

    • 在调用 Service::on_stop 之后,但在调用 Service::drop 之前。

  • 在调用 Service::drop 之后调用 destroyed

规则集

配置状态可以是有效无效,具体取决于条件。可以随时启用多个状态。当编排代理收到信号更新时,系统会先评估所有配置状态,然后再修改服务软件包的生命周期。系统会根据以下规则评估服务实例状态:

  • 当没有一个有效状态适用于服务实例时,该实例会被销毁。

  • 当应用一种或多种有效状态时,适用以下优先级:

    1. destroyed 具有绝对优先权。
    2. started 优先于 created

Proto 架构

以下是 proto 架构示例:

// A root boolean condition.
message Condition {
  // Required.
  oneof root {
    // VPM power state condition.
    string power_state = 1;
    // VPM vehicle state condition.
    string vehicle_state = 2;
    // Custom mode state condition.
    CustomState custom_state = 3;
    // Negation of a nested condition.
    Condition not = 4;
    // Logical 'and' between conditions grouped in expression.
    Expression and = 5;
    // Logical 'or' between conditions grouped in expression.
    Expression or = 6;
  }
}

// Representation of Custom state condition.
//
// Custom mode(s) are defined by the OEM and are not standardized by the platform, in contrast with
// VPM modes (i.e. power and vehicle mode).
message CustomState {
  // Custom mode being checked.
  string mode = 1;
  // State of the custom mode.
  string state = 2;
}

// A set of conditions united under an 'and' or 'or' expression.
//
// Evaluation type ('and' or 'or') depends on the field in [Condition]/[Expression], where the
// expression is being used.
//
// At least one value in at least one of the fields is required.
message Expression {
  // VPM power state condition.
  repeated string power_state = 1;
  // VPM vehicle state condition.
  repeated string vehicle_state = 2;
  // Custom mode state condition.
  repeated CustomState custom_state = 3;
  // Negation of a nested condition.
  repeated Condition not = 4;
  // Logical 'and' between conditions grouped in expression.
  repeated Expression and = 5;
  // Logical 'or' between conditions grouped in expression.
  repeated Expression or = 6;
}

崩溃恢复和重启策略

编排器提供了一种强大的机制来处理服务软件包崩溃和生命周期转换失败。由于 Orchestrator 全面了解服务状态并管理模式转换,因此它是执行重启和重试策略的最合适组件。生命周期管理器 (LM) 通过 binder 终止通知向 Orchestrator 报告服务软件包崩溃。为了避免向 LM 发出不必要的 binder 调用,Orchestrator 会缓存每个软件包的最后状态(无论成功与否),并且如果最后已知状态与新请求的状态相同,则不会重新应用过渡。

重试配置

您可以使用 retry_mapping 在 Orchestrator 配置中按实例定义重启和重试策略。如果未在配置中设置 max_retries,则默认值取自 ro.boot.sdv.orchestrator.recovery.max_retries 系统属性。如果未设置此属性,则值会回退到 0。

  • max_retries:定义在发生暂时性故障或收到软件包崩溃通知后,编排程序重试转换的次数。在成功执行操作后或处理新模式时,重试计数器会重置为 max_retries 的值。如果多个映射以同一实例为目标,则 max_retries 值最高的映射优先。

配置示例

service_bundle_config {
  package_name: "oem.package"
  service_bundle_name: "OemApplication"
  instance: "fog_front_light"
  instance: "fog_rear_light"

  # Defines the restart configuration mapping for specific instances.
  retry_mapping {
    instance: "fog_front_light"
    instance: "fog_rear_light"
    retry_config {
      max_retries: 3
    }
  }
}

恢复行为

Orchestrator 的重启和重试逻辑可妥善管理多种故障情形:

  • 正常运行崩溃:如果服务软件包在运行时崩溃,编排器会应用重启策略,并尝试根据剩余的重试次数将软件包恢复到上次请求的状态。
  • 模式转换期间发生崩溃:如果软件包在强制执行新模式时崩溃,则重新启动请求会排队,并在稍后处理。处理完请求后,编排器会检查实例的最后状态,并且仅当实例不处于最后请求的状态(来自上次模式转换)时才应用重启。
  • 恢复期间的新模式:如果 Orchestrator 在软件包重启期间(或在要重启的实例队列中)收到转换到新模式的请求,则会取消正在进行的恢复。新的模式转换接管,重试计数器重置,以便为新的目标状态重新尝试。

Orchestrator 会区分 Lifecycle Manager 返回的不同错误类型,以确定重试策略:

  • 暂时性错误(SERVICE_NOT_FOUNDOPERATION_FAILEDINTERNAL_ERROR:编排器会重试操作,而不会采取任何特殊的清理措施。
  • 持久性错误(VALUE_CORRUPTEDINVALID_ARGUMENT:编排器会假定服务软件包可能处于损坏状态,并尝试在重试操作之前终止服务实例,以确保干净的重新启动。
  • 永久性错误 (PERMISSION_DENIED):系统不会重试相应操作,并且会将相应软件包视为处于无法恢复的状态。

如果生命周期管理器崩溃,所有服务软件包进程都会丢失。由于实际状态未知,Orchestrator 会使每个实例失效,并应用剩余重试次数的重启策略,以使每个实例达到上次请求的状态。

为了防止反复崩溃或失败的软件包出现无限恢复循环,只有在生命周期操作成功或请求新的模式转换时,重试计数器才会重置为 max_retries。如果某个软件包因连续失败(例如,过渡失败后发生崩溃)而用尽重试次数,则在重试计数器重置之前,该软件包不会重新启动。

向健康状况监控器报告状态

Orchestrator 会公开一个内部 binder 接口,健康监视器 (HM) 会注册到该接口,从而能够持续接收有关所有服务软件包状态的更新。通过此接口,编排器会主动报告以下两项内容:

  • 生命周期状态:基于当前配置和有效模式(例如已启动、已创建或已销毁)的实例预期状态。
  • 恢复状态:达到预期生命周期状态的状态,指示实例是否可运行、当前是否在失败后重试,或者在耗尽所有重试次数后是否未能恢复。

系统会针对所有实例报告此信息,包括未注册接受心跳监控的实例。HM 使用此信息来实现其 API,以报告虚拟机的状态。如需了解详情,请参阅Health monitoring

示例

本部分展示了通过条件配置状态的示例。

基础服务示例
  • 没有条件,因此始终处于有效状态。
  • 启动单个服务实例。
state {
  # Note: This state has no condition, hence its actions are valid throughout the lifetime of the program
  instances_states { started: "ServiceBundleName" }
}
HVAC 应用示例
  • 条件:当 custom_state != occupancy.OCCUPANCY_EMPTY || custom_state == preheat.PREHEAT_ON 时处于有效状态。

  • 将多个 HVAC 相关服务实例声明为 started

state {
  condition {
    or {
      # I.e. when the vehicle is occupied (for example, by _DRIVER / _NON_DRIVER / _PET)
      not {
        custom_state {
          mode: "occupancy"
          state: "OCCUPANCY_EMPTY"
        }
      }
      custom_state {
        mode: "preheat"
        state: "PREHEAT_ON"
      }
    }
  }

  # HVAC-related services
  instances_states {
    started: "HvacTemperatureCommand"
    started: "TempSensorDriverZone"
    started: "TempSensorPassengerZone"
    started: "RefrigerantLoop"
  }
}
省电模式示例
  • 条件:当 custom_state == system_power.SYSTEM_POWER_LOW && custom_state == range_ext.RANGE_EXT_ON 时处于有效状态。

    此状态可视为省电状态。

  • 将一个与暖通空调相关的服务实例声明为 destroyed

  • 在此示例中,当 SYSTEM_POWER_LOWRANGE_EXT_ON 模式处于有效状态时,HVAC 应用在没有 RefrigerantLoop 服务实例的情况下运行:

    state {
      condition {
        and {
          custom_state {
            mode: "system_power"
            state: "SYSTEM_POWER_LOW"
          }
          custom_state {
            mode: "range_ext"
            state: "RANGE_EXT_ON"
          }
        }
      }
    
      # Disable services with high power consumption
      instances_states { destroyed: "RefrigerantLoop" }
    }
    
机上生活示例
  • 条件:如果 power_state == ON && vehicle_state == LIFE_ON_BOARD,则处于有效状态。

    此状态可视为有人在车内且车辆已启动

  • 将温度传感器声明为正在运行。

  • 当有人在车内时,系统会出于安全原因监控温度等项目。

state {
  condition {
    and {
      power_state: "ON"
      vehicle_state: "LIFE_ON_BOARD"
    }
  }

  # Temperature monitoring services
  instances_states {
    started: "TempSensorDriverZone"
    started: "TempSensorPassengerZone"
  }
}

示例

本部分展示了包含以下内容的完整示例:

  • 一种服务包级 proto 配置,用于引入包含两个实例的服务包,每个实例都是一个群组的一部分

  • 一种虚拟机级 proto 配置,用于引入基于模式与群组互动的逻辑

服务包级配置

# proto-file: //system/software_defined_vehicle/orchestration/distributed_config/src/protos/service_bundle_config.proto
# proto-message: ServiceBundleConfig

package_name: "oem.package"
service_bundle_name: "OemApplication"
instance: "fog_front_light"
instance: "fog_rear_light"
instance: "turn_signal_light"
custom_mode: "FOG"
custom_mode: "TURN"

group_mapping {
    group: "fog_light"
    instance: "fog_front_light"
    instance: "fog_rear_light"
}

group_mapping {
    group: "flasher_light"
    instance: "turn_signal_light"
}

state {
    condition {
        power_state: "ON"
    }

    instances_states {
        created: "turn_signal_light"
        destroyed: "fog_front_light"
        destroyed: "fog_rear_light"
    }
}

虚拟机级配置

# proto-file: //system/software_defined_vehicle/orchestration/distributed_config/src/protos/vm_config.proto
# proto-message: VmConfig

group_mapping {
    group: "lights"
    subgroup: "fog_light"
    subgroup: "flasher_light"
}

state {
    condition {
        custom_state {
            mode: "FOG"
            state: "ON"
        }
    }
    groups_states {
        started: "fog_light"
    }
}

state {
    condition {
        custom_state {
            mode: "TURN"
            state: "RIGHT"
        }
    }
    groups_states {
        started: "flasher_light"
    }
}

state {
    condition {
        vehicle_state: "SUSPEND_TO_RAM_ENTER"
    }
    groups_states {
        created: "lights"
    }
}

配置软件包管理并行性

ro.boot.sdv.max_bundles_management_threads 系统属性是用于控制服务软件包生命周期操作期间的性能和资源消耗的关键调优参数。它定义了服务包交易的最大并行级别,并直接影响以下两项核心服务:

  1. 编排引擎:此服务会读取该属性,以确定编排器可以向生命周期管理器发出多少并发调用(例如 startServicestopService)。这对于启动和模式转换期间的性能至关重要,因为在这些期间,许多软件包可能会同时更改状态。

  2. 生命周期管理器:此服务使用该属性的值来计算其 Binder 线程池的大小,该线程池负责处理所有传入的请求。这样可确保 LM 有足够的线程来处理来自 Orchestrator 的并发请求。

如果未设置此属性,则这两个服务的默认值均为 12

配置方法

您可以通过将该属性添加到 BOARD_BOOTCONFIG 变量中,在设备的 BoardConfig.mk 文件中设置该属性。这样可确保每次设备启动时都会应用该值。

BOARD_BOOTCONFIG += \
    androidboot.sdv.max_bundles_management_threads=8

如需更改设备的值,请修改相应 BoardConfig.mk 文件中的这一行,然后重新构建。

启动时优化

ro.sdv.orchestrator.state.ready 是一个 write-once 布尔值属性,属于启动时性能优化策略的一部分。这表示编排代理已完成初始化,可以开始管理服务包的生命周期。其主要目的是通过控制其他 SDV 代理的启动顺序,优先启动 Orchestrator 及其托管式服务捆绑包。

  • 设置者:编排代理。
  • 时间:在启动序列期间调用一次。
  • 用途:此属性由 init 系统用于控制大多数 SDV 代理(更新管理器、VSIDL 提供程序、健康状况监控器、服务发现、数据隧道、RPC、VPM 和遥测)的启动顺序。通过尽早启动 Orchestrator 并让其他代理等待此属性,系统可确保 Orchestrator 能够开始执行启动服务包的关键任务,而不会与其他进程争用系统资源。

性能

在系统启动期间,同时启动所有代理可能会导致资源争用,从而减慢整个启动过程。为了缓解此问题,系统会使用系统属性强制执行顺序启动顺序:

  1. 服务软件包注册表:首先启动以加载所有服务软件包元数据。
  2. 生命周期管理器和编排器:这些核心代理会在注册表准备就绪后立即启动。这种提前启动至关重要,因为它可以让 Orchestrator 开始评估其配置,并立即准备启动服务包。
  3. 其他 SDV 代理:仅在编排器准备就绪后启动。

这种受控序列可确保 Orchestrator 优先使用系统资源,以便尽早启动服务软件包,从而实现更快、更确定、更高效的系统启动。

Orchestrator 消耗的模式

编排代理会保持对 VPM 传输的车辆模式和电源模式的有效订阅。在 Orchestrator 与车辆和电源管理 (VPM) 系统之间建立初始连接后,Orchestrator 会将以下布尔值系统属性设置为 true

  • sdv.orchestrator.bootup.power_mode.ready

  • sdv.orchestrator.bootup.vehicle_mode.ready

编排代理会使用配置文件作为参考,根据接收到的模式的当前值动态计算应处于运行状态的服务包集。然后,编排器会与生命周期管理器通信,发出不同的命令,以使服务包的实际状态与计算出的目标状态保持一致。

车辆和电源状态

车辆模式和电源管理 (VPM) 代理可让 SDV 组件了解车辆的当前状态,例如运行模式(例如,处于泊车或驾驶状态)和电源状态(例如,开启和挂起)。编排器会评估这些值,以根据编排器配置确定应运行哪些服务包。如需了解详情,请参阅车辆和电源管理

自定义模式

由于车辆模式数量众多,我们无法对所有模式进行建模。每个 OEM 的需求各不相同,标准化车辆模式无法满足所有 OEM 用例。因此,我们支持 OEM 专用模式,称为自定义模式。这些模式不会扩展现有的车辆和电源模式。相反,它们提供了一种定义新模式的方式。

功能:

  • 全局范围:自定义模式是全局的,可统一应用于 Orchestrator 管理的所有虚拟机。

  • 组成:每项自定义模式更改都包含两个元素:

    • 名称:OEM 选择的用于表示自定义模式的唯一标识符。

    • :自定义模式的当前状态,未设置值时可以为 UNDEFINED

  • 编排器角色:编排器充当自定义模式值的被动接收器。

  • 服务软件包角色:每个服务软件包可以拥有多个自定义模式,并且可以向任何模式发布新值。多个服务软件包可以拥有同一自定义模式,这意味着自定义模式可以从不同来源接收新值。

  • 验证责任:原始设备制造商 (OEM) 负责确保状态转换有效。编排器接受任何新值。

估计特征:

  • 估计数量:电源和车辆模式可管理大多数服务软件包的生命周期,而自定义模式则发挥补充作用。我们预计自定义模式的数量级为数十个,而不是数百个。

  • 估计时间:模式不会定期发送。相反,模式由事件驱动,由特定操作触发,例如开门、启动停车序列、开始充电周期以及其他 OEM 定义的重要事件。

自定义模式设计可灵活地定义和管理特定模式,同时允许 Orchestrator 保持对底层状态机逻辑的不可知性。

支持的模式

为确保服务包仅发布到其拥有的自定义模式,每个服务包都必须在其 Orchestrator 配置中明确声明所拥有的自定义模式列表,该列表可在本地虚拟机中通过服务包注册表获取。尝试发布到未声明的自定义模式会被舍弃。

为了声明服务包允许发布(因此拥有)的自定义模式,service_bundle_config proto 架构扩展了以下内容:

// Service bundle configuration.
//
// Defines service bundle metadata, its instances, and configuration for instances
// lifecycle states depending on the state of the vehicle.
message ServiceBundleConfig {
      [...]

    // The list of custom modes that this service bundle publishes.
    repeated string custom_mode = 5;
}

根据模式配置软件包

现有的 Orchestrator proto 配置(Condition 组件)支持基于自定义模式来操纵服务包:

message Condition {
  oneof root {
    string power_state = 1;
    string vehicle_state = 2;
    CustomState custom_state = 3;
    Condition not = 4;
    Expression and = 5;
    Expression or = 6;
  }
}

message CustomState {
  // Custom mode being checked.
  string mode = 1;
  // State of the custom mode.
  string state = 2;
}

Proto 示例

以下示例展示了如何配置服务包的实例,以根据 TURNFOG 状态启动:

service_bundle_config {
package_name: "oem.package"
service_bundle_name: "OemApplication"
instance: "flasher_light"
// Service bundle is allowed to set values for the TURN mode
custom_mode: "TURN"
// Service bundle is allowed to set values for the FOG mode
custom_mode: "FOG"

state {
    condition {
        custom_state {
            mode: "TURN"
            state: "LEFT"
        }
    }
    instances_states {
        started: "flasher_light"
    }
}

state {
    condition {
        custom_state {
            mode: "FOG"
            state: "ON"
        }
    }
    // Group assumed to be defined containing all FOG lights instances.
    groups_states {
        started: "fog_lights"
    }
}

}

设置新的自定义模式

设置新的自定义模式值的过程从服务软件包开始,该软件包会将所需的值传递给在同一虚拟机上运行的本地 Orchestrator。然后,编排器会验证服务包是否具有发布到指定自定义模式所需的权限,并参考 .textproto 中定义的配置,以确定是否应将该值传播到其他虚拟机。传播完成后,每个 Orchestrator 都会检查其配置,以查找应更改状态的服务包列表。

RPC

在每个虚拟机上运行的每个 Orchestrator 都会创建一个 RPC 服务器,以监听新的自定义模式值。想要更新自定义模式的每个服务包都必须创建到服务器的 RPC 客户端。系统会强制执行 ACL,以防止未经授权的软件包连接到服务器。

通过 RPC 设置新值的 proto 定义如下例所示:

syntax = "proto3";

import "google/protobuf/timestamp.proto";

package com.sdv.google.Orchestrator;

// Representation of the request used by service bundles to update a custom mode.
// Service bundles are permitted to update only the custom modes specifically designated
// for them within the Orchestrator configuration.
message SetCustomStateRequest {
  // Required.
  // The name of the custom mode.
  // The mode string can not be longer than 56 characters and can only contain
  // letters, numbers, dashes, dots and underscores: [a-zA-Z0-9_-.].
  // No other special character nor spaces should be present in the mode.
  string mode = 1;

  // Required.
  // The new value for the custom mode.
  // The value string can not be longer than 56 characters and can only contain
  // letters, numbers, dashes, dots and underscores: [a-zA-Z0-9_-.].
  // No other special character nor spaces should be present in the value.
  string value = 2;

  // Required.
  // The timestamp in which the new custom mode value was set. This is used to
  // prevent race conditions whenever different service bundles in different
  // VMs want to set a new value for the same custom mode.
  // We use this timestamp to order the requests and we promise eventual
  // consistency: while temporary inconsistencies may occur, the system will
  // eventually converges to the correct state.
  .google.protobuf.Timestamp timestamp = 3;
}

// Representation of the set custom state response.
message SetCustomStateResponse {}

// Orchestrator interface for service bundles that update the value of a
// custom mode.
// When a new value is received, it is propagated to Orchestrators running on
// other VMs.
service CustomStateService {
  // Updates the value for the custom mode.
  // Returns the error:
  // - PermissionDenied: the service is not authorized to update the custom mode.
  // - InvalidArgument: the provided mode and/or value are not valid.
  rpc SetCustomState(SetCustomStateRequest) returns (SetCustomStateResponse) {};
}

取消电源转换

Orchestrator 允许通过 SHUTDOWN_CANCELLED 电源模式(由 VPM 发送到 Orchestrator)取消正在进行的电源转换。

以以下 Orchestrator 配置为例:

state {
    condition {
        power_state: "SUSPEND_TO_RAM_ENTER"
    }
    instances_states {
        started: "instance-1"
        started: "instance-2"
        started: "instance-3"
    }
}

当收到 SHUTDOWN_CANCELLED 模式时,以下两种主要情况会决定 Orchestrator 的行为。在这两种情况下,SHUTDOWN_CANCELLED 电源模式都会附加到队列末尾。然后,在已使用队列中的元素后执行 SHUTDOWN_CANCELLED

场景 1:当前正在进行的模式是电源模式

如果 Orchestrator 正在执行电源模式更新,则请求取消正在进行的模式。虽然生命周期管理器本身不支持取消正在进行的过渡,但 Orchestrator 会验证是否没有启动新的服务包请求。

示例:如果上例中配置的 instance-1 在收到 SHUTDOWN_CANCELLED 模式时正在启动,则 instance-1 会完成其启动。不过,instance-2instance-3 不会继续转换到已启动状态。

场景 2:处理队列中存在电源模式

如果编排器正在处理非电源模式更新,并且待执行的模式队列中有电源请求,则从队列中移除电源转换。这样可以防止执行该代码。

示例:使用上例中的配置,如果 Orchestrator 正在处理非电源相关更新(例如车辆更新),并且队列中有 SUSPEND_TO_RAM_ENTER,则收到 SHUTDOWN_CANCELLED 不会导致任何实例(instance-1instance-2instance-3)启动。

实现示例

希望使用中间件生成的代码来创建 RPC 服务器客户端的客户端的目录可能如下例所示:

# proto-file: //system/software_defined_vehicle/vsidl/language/src/protos/sdv/vsidl/v1/syntax.proto
# proto-message: VsidlEntry

package: "package_name"

service_bundle {
    name: "service_bundle_name"

    client {
        service: "com.android.sdv.orchestrator.CustomStateService"
    }
}

生成代码时,您必须将依赖项添加到 Orchestrator 目录:

--dependency-catalog-path orchestration/engine/stable/vsidl/*

用于发送新值的客户端代码如下所示:

let fqin = ServiceFqin::builder()
        .sdv_vm_name("vm_name")
        .sdv_package_name("package_name")
        .service_bundle_name("service_bundle_name")
        .service_instance_name("instance_name")
        .build()
        .unwrap();
let context_ref = ContextRef::create(fqin);
let comms = Arc::new(SdvComms { context: context_ref });
// service_bundle_name is the bundle generated with middleware code that defines
// the RPC client to "com.android.sdv.orchestrator.CustomStateService".
let client = service_bundle_name::new(comms).await.unwrap();
let rpc_client = client
        .create_rpc_client::<Client>(
            UnitName::builder()
                .vm_name(comms.context.get_self_fqin().get_sdv_vm_name())
                .package_name("com.android.sdv.orchestrator")
                .bundle_name("OrchestratorServiceBundle")
                .service_unit_name(Client::DEFAULT_UNIT_NAME)
                .build()
                .unwrap(),
            ClientOptions::default(),
        )
        .await;
let client = Arc::new(rpc_client.unwrap());
let request = SetCustomStateRequest {
mode: custom_mode_name,
value: custom_mode_value,
timestamp: MessageField::some(Timestamp::now()),
..Default::default()
};
let result = client.SetCustomState(&request).await;
// Process result

调试工具

Orchestrator 代理支持 dumpsys 工具。您可以在正在运行的 SDV 实例上运行以下命令来调用它:

adb shell dumpsys com.google.sdv.ISdvAgent/orch

使用此工具可调试并深入了解 Orchestrator 代理的内部状态。这样做会显示:

  • 当前模式状态:查看当前有效的车辆模式、电源模式和自定义模式。
  • 自定义模式发布者:确定哪些服务可以发布自定义模式(以及可以发布到哪些模式)。
  • 各服务的所需状态:了解每个服务包的状态(基于预定义条件和当前模式)。这有助于诊断服务为何可能未处于预期状态。
  • 模式强制执行状态:清楚了解正在强制执行的模式,如果没有正在强制执行的模式,则了解上次强制执行的模式。
  • 模式强制执行队列:查看等待强制执行的模式。

例如:

AGENT NAME: SDV Agent dump - Orchestrator
AGENT FQIN: instance1:com.android.sdv.orchestrator.OrchestratorServiceBundle/default
AGENT STATE: See orchestrator state below.
----------------
----------------
INTERNAL STATE REPORTERS:

*NAME: Configuration state
*REPORT:
Active modes:
MODE                          VALUE                         TIMESTAMP (scs, ns)
Power                         POWER_OFF_EXIT                -
Vehicle                       VEHICLE_ON                    -
Custom("CHARGING")            ON                            1750757590 (scs) 466507459 (ns)
Custom("TIRE_PRESSURE")       front-left                    1750757570 (scs) 554522995 (ns)

Modes allowed to publish by bundle (FQIN: modes):
com.android.sdv.sample.orchestration/CustomModeControlBundle: CHARGING, TIRE_PRESSURE

Requested state for instances:
STATE          FQIN
Started        com.android.sdv.sample.orchestration/CustomModeControlBundle/always-started-instance
Started        com.android.sdv.sample.orchestration/OrchestratedServiceBundle/my-instance
Started        com.sdv.oem.sample.diagnostics/DiagnosticsSampleWithDataItem/instance
Started        com.sdv.oem.sample.diagnostics/DiagnosticsSampleWithEvent/instance
Started        com.sdv.oem.user_preferences/UserPreferencesServiceBundle/default
----------------
*NAME: Engine state
*REPORT:
Last mode enforced was Custom("CHARGING") with value "ON"

Next modes to process: []
----------------

如需详细了解由 Orchestrator 管理的各个服务软件包,请使用 Lifecycle Manager 中的现有 dumpsys,如下所示:

dumpsys google.sdv.lifecycle.ILifecycleManager/default

这样做可提供有关每项服务的生命周期状态的详细信息。通过将 Orchestrator dumpsys 输出与 Lifecycle Manager 的输出相结合,可以全面了解虚拟机中服务软件包的生命周期。